---
title: "Nginx Config Cheatsheet"
slug: "nginx-config"
category: "cheatsheets"
tags: ["cheatsheets", "nginx", "webserver", "ops", "proxy", "reference"]
status: "stable"
last_updated: 2026-05-14
summary: "Nginx server, location, and upstream block reference with proxy_pass, try_files, return, SSL, and gzip directives."
related:
  [
    "[[ops/cloudflare]]",
    "[[ops/hostinger-vps]]",
    "[[cheatsheets/http-status-codes]]",
    "[[cheatsheets/dockerfile-syntax]]",
    "[[ops/cloudflare-security-headers]]",
    "[[cheatsheets/curl-flags]]",
    "[[cheatsheets/index|Cheatsheets]]",
  ]
---

## Overview

Nginx config is organized as a tree of contexts: `http` contains `server` blocks, which contain `location` blocks. Directives inherit from the enclosing context unless overridden. This card covers the directives that make up 90% of real configs: reverse proxy, static file serving, SSL termination, redirects, and compression. Test config with `nginx -t` before reloading; reload with `nginx -s reload` (zero downtime) rather than a full restart.

## Block structure

The three main blocks and their purpose.

| Block         | Scope                | Typical content                                                       |
| ------------- | -------------------- | --------------------------------------------------------------------- |
| `http {}`     | Global HTTP settings | `include mime.types`, logging format, `gzip`, `upstream` definitions. |
| `server {}`   | One virtual host     | `listen`, `server_name`, SSL config, `root`, `location` blocks.       |
| `location {}` | URL prefix or regex  | `proxy_pass`, `try_files`, `return`, caching, headers.                |
| `upstream {}` | Backend pool         | `server` directives listing backends; `keepalive`.                    |

```nginx
http {
    include       mime.types;
    default_type  application/octet-stream;

    upstream api_backend {
        server 127.0.0.1:3000;
        server 127.0.0.1:3001;
        keepalive 32;
    }

    server {
        listen 443 ssl http2;
        server_name example.com;

        location /api/ {
            proxy_pass http://api_backend/;
        }

        location / {
            root /var/www/html;
            try_files $uri $uri/ /index.html;
        }
    }
}
```

## Location matching

Nginx tests location blocks in a specific order; the first match wins except for exact matches.

| Modifier               | Syntax               | Priority | Notes                                                  |
| ---------------------- | -------------------- | -------- | ------------------------------------------------------ |
| Exact                  | `location = /path`   | Highest  | Must match the URI exactly; no trailing slash allowed. |
| Preferential prefix    | `location ^~ /path`  | Second   | Stops regex search once matched.                       |
| Case-sensitive regex   | `location ~ \.php$`  | Third    | First matching regex wins.                             |
| Case-insensitive regex | `location ~* \.jpg$` | Third    | Same priority as `~`; order in file breaks ties.       |
| Prefix                 | `location /path`     | Lowest   | Longest prefix match is used if no regex matches.      |

```nginx
location = /favicon.ico { access_log off; return 204; }
location ^~ /static/    { root /var/www; expires 1y; }
location ~* \.(jpg|png)$ { expires 30d; add_header Cache-Control "public"; }
location /               { try_files $uri $uri/ =404; }
```

## Common directives

The directives to know for proxying, serving files, and redirects.

| Directive          | Context          | What it does                                                  |
| ------------------ | ---------------- | ------------------------------------------------------------- |
| `proxy_pass`       | location         | Forward requests to an upstream URL or pool.                  |
| `proxy_set_header` | location         | Set or forward a header to the upstream.                      |
| `try_files`        | location         | Test file paths in order; use last item as fallback or error. |
| `return`           | server, location | Immediately return a status or redirect.                      |
| `rewrite`          | server, location | Rewrite the URI and optionally redirect.                      |
| `root`             | server, location | Document root; path is prepended to the URI.                  |
| `alias`            | location         | Replace the location prefix with the given path.              |
| `index`            | server, location | Default file to serve for directory requests.                 |
| `expires`          | location         | Set `Cache-Control` and `Expires` headers.                    |
| `add_header`       | server, location | Add a response header.                                        |

```nginx
# Reverse proxy with forwarded headers
location /api/ {
    proxy_pass         http://api_backend/;
    proxy_set_header   Host              $host;
    proxy_set_header   X-Real-IP         $remote_addr;
    proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_http_version 1.1;
    proxy_set_header   Connection "";   # enable keepalive to upstream
}

# SPA fallback
location / {
    try_files $uri $uri/ /index.html;
}

# Permanent redirect
location /old-path {
    return 301 /new-path;
}
```

## SSL configuration

Minimal TLS 1.2/1.3 config for a modern server.

```nginx
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_stapling        on;
    ssl_stapling_verify on;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
}

# HTTP to HTTPS redirect
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}
```

Generate certificates with Certbot: `certbot --nginx -d example.com`. Certbot edits the nginx config and sets up auto-renewal.

## Compression and performance

Enable gzip for text responses; skip binary formats.

```nginx
http {
    gzip              on;
    gzip_types        text/plain text/css application/json application/javascript
                      text/xml application/xml image/svg+xml;
    gzip_min_length   1024;
    gzip_comp_level   6;      # 1 (fast) to 9 (best compression); 6 is a good balance
    gzip_vary         on;
    gzip_proxied      any;

    # Serve pre-compressed .gz files if they exist
    gzip_static on;

    # Buffer tuning for proxied responses
    proxy_buffers         16 4k;
    proxy_buffer_size     4k;
    keepalive_timeout     65;
    sendfile              on;
    tcp_nopush            on;
}
```

## Common gotchas

- `proxy_pass http://backend/` (with trailing slash) strips the matched location prefix. `proxy_pass http://backend` (no trailing slash) passes the full URI. This mismatch causes 404s; pick the form that matches your intent.
- `add_header` in a child block replaces, rather than adds to, headers set in a parent block. Set all security headers in one place to avoid this.
- `root` prepends the root to the full URI. `alias` replaces the location prefix. Confusing the two produces 404s. Use `alias` for locations whose path on disk differs from the URI prefix.
- `try_files` with `=404` as a fallback returns 404 directly. Using `@fallback` (a named location) allows custom 404 handling.
- `nginx -t` tests syntax but not runtime behavior (e.g., unreachable upstreams). Test proxy connectivity with `curl` from the nginx host.
- The regex location `~* \.(gif|jpg)$` must come before broader prefix locations in the file if Nginx must prefer it; the file order matters for same-priority matches.

## Related

- [[ops/cloudflare]]
- [[ops/hostinger-vps]]
- [[cheatsheets/http-status-codes]]
- [[cheatsheets/dockerfile-syntax]]
- [[ops/cloudflare-security-headers]]
- [[cheatsheets/curl-flags]]
- [[cheatsheets/index|Cheatsheets]]
