Common patterns cheatsheet.

www → apex

server {
    listen 80;
    listen 443 ssl;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

HTTP → HTTPS

server {
    listen 80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

Trailing slash redirect

rewrite ^/path$ /path/ permanent;       # add trailing slash
rewrite ^(.+)/$ $1 permanent;           # remove trailing slash

Force lowercase URLs

if ($request_uri ~ [A-Z]) {
    return 301 $scheme://$host$1$lowercase_uri;
}

Better: OpenResty Lua to lowercase.

Block specific path

location /admin {
    return 404;
}

location ~ \.(env|git) {
    deny all;
    log_not_found off;
}

Internal proxy + public path

location /api/ {
    proxy_pass http://internal:8000/;
}

location = /api/admin {
    return 404;       # hide admin path
}

Status code customizations

error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
error_page 403 = @ratelimited;

location @ratelimited {
    return 429;
}

Mirror traffic

location / {
    mirror /mirror;
    mirror_request_body on;
    
    proxy_pass http://primary;
}

location = /mirror {
    internal;
    proxy_pass http://shadow$request_uri;
    proxy_set_header X-Original-URI $request_uri;
}

Send copy to shadow for testing without affecting client.

A/B testing

split_clients $request_id $variant {
    50% A;
    *   B;
}

map $variant $upstream {
    A app-stable;
    B app-canary;
}

location / { proxy_pass http://$upstream; }

Forwarding to external

location /github/ {
    proxy_pass https://api.github.com/;
    proxy_set_header Host api.github.com;
    proxy_set_header User-Agent "MyProxy/1.0";
    
    resolver 1.1.1.1 valid=300s;
}

Hot reload static

location ~* \.(css|js)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location = /index.html {
    add_header Cache-Control "no-cache";
}

Maintenance page

location / {
    if ($cookie_admin = "") {
        return 503;
    }
    proxy_pass http://app;
}

error_page 503 @maintenance;

location @maintenance {
    root /var/www;
    try_files /maintenance.html =503;
    add_header Retry-After 3600;
}

admin cookie bypasses for ops.

Redirect old paths

location = /old { return 301 /new; }

map $request_uri $redirect {
    /old1 /new1;
    /old2 /new2;
}

if ($redirect) {
    return 301 $redirect;
}

Conditional CSP

map $sent_http_content_type $csp {
    default "default-src 'self'";
    text/html "default-src 'self'; script-src 'self' 'nonce-$request_id'";
}

add_header Content-Security-Policy $csp always;

Pass real IP

set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Now $remote_addr is real client IP.

Block by country (GeoIP2)

geoip2 /etc/nginx/GeoLite2-Country.mmdb {
    $geoip2_country_code country iso_code;
}

map $geoip2_country_code $blocked {
    default 0;
    KP 1;
}

server {
    if ($blocked) { return 451; }
}

Default catchall server

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    
    ssl_certificate /etc/nginx/snakeoil.crt;
    ssl_certificate_key /etc/nginx/snakeoil.key;
    
    return 444;        # close without response
}

Drops requests with wrong Host header.

Multiple domains, same backend

server {
    server_name example.com a.example.com b.example.com;
    location / { proxy_pass http://app; }
}

Sub-applications

location /blog/ {
    proxy_pass http://blog-app/;
}
location /shop/ {
    proxy_pass http://shop-app/;
}
location /api/ {
    proxy_pass http://api-app/;
}

Common mistakes

  • if inside location — nginx wiki: “If is evil.” Use map or return when possible.
  • Forgetting trailing / in proxy_pass.
  • return 301 to relative URL — must be absolute.
  • Caching maintenance page (cache control matters).
  • Multiple redirects for same path causing loop.

Read this next

If you want my pattern collection, it’s at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .