Optimizing for CDN Integration
1. Setting Appropriate Cache Headers
| Header | Values | Description |
|---|---|---|
| Cache-Control | max-age=3600 |
Defines how long content can be cached in seconds |
| Cache-Control | public |
Allows caching by any cache, including shared caches like CDNs |
| Cache-Control | private |
Allows caching only by the user's browser, not shared caches |
| Cache-Control | no-cache |
Content can be stored but must be revalidated before use |
| Cache-Control | no-store |
Prevents caching entirely |
| Expires | Wed, 21 Oct 2026 07:28:00 GMT |
HTTP/1.0 date when the content expires |
| ETag | "33a640-2c-50d8e9b" |
Unique identifier for a specific version of a resource |
| Last-Modified | Wed, 21 Oct 2026 07:28:00 GMT |
Date and time when the resource was last modified |
Example: Setting Cache Headers in Nginx
location /static/ {
alias /var/www/static/;
expires 1d;
add_header Cache-Control "public, immutable";
}
Example: Cache Control for Dynamic Content
location /api/ {
proxy_pass http://backend;
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
2. Configuring Vary Headers
| Header | Values | Description |
|---|---|---|
| Vary | Accept-Encoding, Accept, User-Agent |
Indicates which request headers influence the response selection |
Example: Setting Vary Header for Compression
location / {
gzip on;
gzip_vary on;
proxy_cache_valid 200 1h;
}
Note: Setting
gzip_vary on; automatically adds Vary: Accept-Encoding to responses.
Example: Manual Vary Header
location /api/ {
add_header Vary "Accept, User-Agent";
proxy_pass http://backend;
}
3. Implementing Origin Shield
| Directive | Description | Values | Notes |
|---|---|---|---|
| origin_shield | Enables or disables origin shield for a location | on | off |
Requires Nginx Plus |
| origin_shield_cache | Defines cache key for origin shield | string |
Optional, defaults to request URI |
| origin_shield_timeout | Timeout for origin shield requests | time |
Default: 60s |
Example: Basic Origin Shield Configuration
location / {
origin_shield on;
proxy_pass http://backend;
}
Example: Origin Shield with Custom Cache Key
location / {
origin_shield on;
origin_shield_cache $uri;
proxy_pass http://backend;
}
Note: Origin Shield is a feature exclusive to Nginx Plus and requires a valid license.
Warning: Misconfiguring origin shield can lead to cache pollution or increased backend load.
4. Using X-Accel Headers
| Header | Description | Usage |
|---|---|---|
| X-Accel-Redirect | Directs Nginx to serve a file from a specified path internally | location /protected/ { internal; X-Accel-Redirect /files/$uri;} |
| X-Accel-Buffering | Controls whether to buffer response for faster delivery | X-Accel-Buffering on; or off |
| X-Accel-Expires | Sets the cache expiration time for CDN or browser | X-Accel-Expires 3600; (1 hour) |
Example: Serving files via X-Accel-Redirect
location /cdn/ {
internal;
alias /var/www/files/;
}
location /secure/ {
proxy_pass http://backend;
add_header X-Accel-Redirect /cdn/$uri;
}
Note:
X-Accel-Redirect is only processed if the location block has internal directive.
Warning: Misuse of
X-Accel-Redirect can lead to path traversal vulnerabilities. Always validate and sanitize paths.
5. Setting CORS for CDN
| Directive | Description | Values | Notes |
|---|---|---|---|
| add_header | Adds a custom header to the response | Access-Control-Allow-Origin * |
Used to enable CORS for all origins |
| add_header | Adds a custom header to the response | Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS |
Defines allowed HTTP methods |
| add_header | Adds a custom header to the response | Access-Control-Allow-Headers X-Requested-With, Content-Type, Accept |
Defines allowed headers in requests |
Example: Configuring CORS Headers in Nginx
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS;
add_header Access-Control-Allow-Headers X-Requested-With, Content-Type, Accept;
}
Note: Setting
Access-Control-Allow-Origin * allows any domain to access your resources. For production environments, it's recommended to specify the exact domains that are allowed.
6. Configuring Cache Purge Endpoints
| Directive | Description | Example |
|---|---|---|
| location | Defines the URI for cache purge endpoint | location /purge { ... } |
| limit_except | Restricts access to the purge endpoint | limit_except GET { ... } |
| proxy_cache_purge | Specifies the cache key to be purged | proxy_cache_purge cache_key; |
Example: Basic Cache Purge Configuration
location /purge {
limit_except GET {
allow 127.0.0.1;
deny all;
}
proxy_cache_purge my_cache $uri;
}
Note: The
proxy_cache_purge directive requires the ngx_cache_purge module to be installed.
Warning: Ensure that cache purge endpoints are protected to prevent unauthorized cache invalidation.
7. Using Cache Keys for CDN
| Directive | Description | Example |
|---|---|---|
| proxy_cache_key | Defines the cache key for proxy responses | proxy_cache_key "$scheme$proxy_host$uri?$query_string"; |
| fastcgi_cache_key | Defines the cache key for FastCGI responses | fastcgi_cache_key "$scheme$request_method$proxy_host$uri?$query_string"; |
| uwsgi_cache_key | Defines the cache key for uWSGI responses | uwsgi_cache_key "$scheme$proxy_host$uri?$query_string"; |
Example: Custom Cache Key for CDN
location /api/ {
proxy_cache my_cache;
proxy_cache_key "$scheme$proxy_host$uri?$query_string";
proxy_cache_valid 200 1h;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503;
}
Note: Cache keys must be unique per content variant to prevent serving wrong content.
Warning: Including user-specific query parameters in cache keys can lead to cache pollution.
8. Implementing Signed URLs
Signed URLs are used to provide time-limited access to protected content, typically in CDN or edge computing environments. Nginx can be configured to validate signed URLs using custom modules or by leveraging the auth_request directive.
| Directive | Description | Example |
|---|---|---|
| auth_request | Specifies the URL to which a request is forwarded for authorization. | auth_request /validate-signature; |
| auth_request_set | Sets variables from the response of the auth request. | auth_request_set $auth_resp_signature $upstream_http_x_signature; |
Example: Basic Signed URL Validation
location /protected/ {
auth_request /validate-signature;
proxy_pass http://backend;
}
location = /validate-signature {
internal;
proxy_pass http://auth-service;
proxy_method GET;
proxy_set_header X-Signature $arg_signature;
proxy_set_header X-Expires $arg_expires;
}
Note: The
auth_request module requires the auth_request module to be compiled into Nginx or loaded dynamically.
Warning: Ensure that the validation endpoint is secure and does not expose sensitive data. Signed URLs should include a cryptographic signature to prevent tampering.
Key Considerations
- Use a secure hashing algorithm (e.g., HMAC-SHA256) to generate signatures.
- Set a reasonable expiration time for signed URLs (e.g., 1 hour).
- Validate the signature and expiration time on each request.
- Use HTTPS to prevent interception of signed URLs.
9. Setting Long Expires for Static Assets
| Directive | Values | Description |
|---|---|---|
| expires | 1y, 1d, 1h |
Sets the Expires header for static assets. Can use units like y (year), d (day), h (hour). |
| expires | modified |
Uses the last modified date to set the Expires header. |
| expires | epoch |
Sets the Expires header to epoch time (no cache). |
Example: Setting long expiration for static assets
location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
Note: Using
immutable with 1y is ideal for static assets that won't change, allowing browsers to cache them indefinitely.
Example: Using modified for dynamic assets
location ~* \.(css|js)$ {
expires modified;
add_header Cache-Control "public";
}
10. Optimizing Image Delivery
| Directive | Description | Values | Notes |
|---|---|---|---|
| image_filter | Enables image filtering and resizing | resize, crop, rotate |
Requires ngx_http_image_filter_module to be compiled in |
| image_filter_buffer | Size of the buffer for image processing | size |
Default: 1m; Recommended: 2m or higher for large images |
| image_filter_jpeg_quality | Quality of JPEG output | 0-100 |
Default: 75; Lower values reduce file size but quality |
| image_filter_webp_quality | Quality of WebP output | 0-100 |
Default: 75; Requires WebP support in Nginx |
Example: Resizing Images on the Fly
location ~* /images/(\d+)x(\d+)/(.*\.(jpg|jpeg|png)) {
image_filter resize $1x$2;
image_filter_jpeg_quality 85;
image_filter_buffer 2m;
}
Example: Serving WebP Images
location ~* \.(jpg|jpeg|png)$ {
# Check if client supports WebP
if ($http_accept ~* "image/webp") {
set $webp_ext ".webp";
}
# Serve WebP if available
try_files $uri$webp_ext $uri =404;
}
Note: Image filtering is CPU-intensive. Use caching and CDN for better performance.
Image Optimization Best Practices
- Use
image_filterfor on-the-fly resizing and compression - Enable WebP support for modern browsers
- Set
image_filter_bufferto handle large images efficiently - Use CDN to offload image processing and caching
11. Implementing Conditional GET
| Directive | Description | Values | Notes |
|---|---|---|---|
| if_modified_since | Controls how Nginx handles the If-Modified-Since header | off, exact, last_modified |
Default is exact. Set to off to disable |
| try_files | Checks for files in order and returns 304 if not modified | File paths or variables | Useful in combination with last_modified |
Example: Conditional GET with try_files
location /static/ {
try_files $uri @fallback;
}
location @fallback {
return 304;
}
Note: Ensure that the
last_modified directive is enabled to support conditional GETs properly.
12. Using CDN-specific Headers
| Header | Description | Usage |
|---|---|---|
| Cache-Control | Controls caching behavior for CDN and browsers | Cache-Control: public, max-age=31536000 |
| CDN-Cache-Control | Overrides default cache behavior for CDN | CDN-Cache-Control: public, max-age=31536000 |
| Vary | Indicates which request headers affect response selection | Vary: Accept-Encoding, User-Agent |
| Surrogate-Control | Directs proxy servers to cache content | Surrogate-Control: max-age=31536000 |