Skip to main content

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_filter for on-the-fly resizing and compression
  • Enable WebP support for modern browsers
  • Set image_filter_buffer to 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

Example: Setting CDN-specific Headers

location /static/ {
    add_header Cache-Control "public, max-age=31536000";
    add_header CDN-Cache-Control "public, max-age=31536000";
    add_header Vary "Accept-Encoding, User-Agent";
    add_header Surrogate-Control "max-age=31536000";
}

Was this article helpful?