Many web projects revolve around serving dynamic or semi-dynamic content—such as restaurant menus—that must load quickly and handle traffic spikes (e.g., lunchtime or promotional campaigns). In this post, we’ll discuss NGINX best practices for a “menu site” use case, using a real-world example for illustration. You can also check an example menu website to see production behavior and test optimizations in practice.
1. Use NGINX as a Reverse Proxy with Caching
- Reverse proxy setup: Place NGINX in front of your application server (e.g., Node.js, Python, PHP). This decouples backend concerns and allows NGINX to serve static assets directly.
- Proxy caching: Cache responses for menu data that change infrequently (e.g., daily price updates). Configure
proxy_cache
with appropriate keys (URI, query string if needed) andproxy_cache_valid
directives:
nginx
CopyEdit
proxy_cache_path /var/cache/nginx/menu_cache levels=1:2 keys_zone=menu_zone:10m max_size=1g inactive=60m use_temp_path=off;
server {
...
location /api/menu {
proxy_pass http://backend_upstream;
proxy_cache menu_zone;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_valid 200 10m;
add_header X-Cache-Status $upstream_cache_status;
}
...
}
- Cache purging: If menu data updates (e.g., price changes), send a purge request or use cache-busting techniques (e.g., versioned URLs or query parameters) so that stale data is replaced promptly.
2. Serve Static Assets Efficiently
- Static files (CSS, JS, images) should be served directly by NGINX with long
expires
headers:
nginx
CopyEdit
location /assets/ {
root /var/www/menu_site;
try_files $uri =404;
expires 7d;
add_header Cache-Control "public";
}
- Gzip/Compression: Enable gzip (or brotli if available) for text-based assets:
nginx
CopyEdit
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 256;
- HTTP/2: Ensure HTTP/2 is enabled over TLS to allow multiplexing of requests, improving load times for clients fetching multiple assets.
3. Load Balancing for Scalability
- For menu sites with variable traffic (e.g., lunchtime peaks), front NGINX can load-balance across multiple backend servers:
nginx
CopyEdit
upstream menu_backends {
server 10.0.0.1:8080;
server 10.0.0.2:8080;
# optional: weight, max_fails, fail_timeout
}
server {
...
location / {
proxy_pass http://menu_backends;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- Health checks: Use external health checks or the commercial NGINX Plus health-check feature to detect and remove unhealthy nodes.
4. Security and SSL/TLS
- SSL termination: Let NGINX handle TLS and forward decrypted traffic to backends. Use modern TLS settings:
nginx
CopyEdit
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
- Rate limiting and request throttling: Prevent abusive clients from hammering menu APIs:
nginx
CopyEdit
limit_req_zone $binary_remote_addr zone=menu_rl:10m rate=10r/s;
server {
...
location /api/menu {
limit_req zone=menu_rl burst=20 nodelay;
proxy_pass http://backend_upstream;
}
}
- Security headers: Add headers like
X-Frame-Options
,X-Content-Type-Options
,Referrer-Policy
, etc., to harden the site.
5. Monitoring and Logging
- Access logs: Customize log format to capture key metrics (response time, cache status):
nginx
CopyEdit
log_format menu_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time cache=$upstream_cache_status';
access_log /var/log/nginx/menu_access.log menu_log;
- Error logs: Monitor for 5xx errors to detect backend issues.
- Metrics export: Integrate with tools like Prometheus (via the NGINX stub_status module) to visualize traffic patterns and resource usage.
6. Rate Limits and Bot Protection
- User-agent filtering: Block known bad bots or restrict excessive crawling of menu pages.
- CAPTCHA on high-risk endpoints: If exposing an order API, integrate CAPTCHA or authentication mechanisms upstream of NGINX.
7. Beyond Basic: Edge Caching and CDN
- For geographically distributed audiences, place NGINX at the origin behind a CDN. Configure appropriate
Cache-Control
headers so the CDN caches static and semi-static menu data. - If using NGINX at the edge (e.g., in regional PoPs), adapt caching rules to local traffic patterns and purge origin cache when menu updates occur.
8. Performance Testing
- Use tools like
ab
,wrk
, orhttperf
to simulate concurrent requests for menu JSON endpoints or homepage assets. Check NGINX response times and cache hit rates. - Analyze slow requests and adjust
worker_processes
, buffer sizes, and timeouts accordingly.
Discussion Points:
- Have you implemented similar caching strategies for menu-driven sites or API-driven content? What challenges did you face when invalidating caches after content changes?
- How do you balance long cache durations for performance versus freshness when menu items change regularly?
- Any tips on structuring URLs or API endpoints for easy versioning (e.g.,
/v1/menu
,/v2/menu
) in tandem with NGINX caching rules? - Experiences with SSL/TLS tuning for performance on high-traffic menu or e-commerce sites?
- Best practices for logging and monitoring to catch unusual traffic spikes (e.g., unexpected promotional campaigns driving heavy load)?
Feel free to share your configurations or insights. If you want to see an applied example, you can also review an example menu website to test response times, caching headers, and behavior under load. Looking forward to your feedback and real-world experiences!