elefcode

Nginx Config Generator

Build a server block for a reverse proxy, SPA, static site or PHP app — with HTTPS, redirects, gzip and caching.

Start from:
Site
What does nginx serve?
www handling
HTTPS
Performance & safety
Redirects
example.com.conf
# Lets the Connection header follow the client: "upgrade" for WebSockets, "close" otherwise.
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name www.example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    client_max_body_size 10m;

    # Security headers
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Compression
    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml application/json application/javascript application/xml application/rss+xml image/svg+xml font/woff2;

    # Hide .git, .env and other dotfiles, but keep Let’s Encrypt challenges working
    location ~ /\.(?!well-known) {
        deny all;
    }

    # Next.js build output has hashed names, so it can be cached for good
    location /_next/static/ {
        proxy_pass http://127.0.0.1:3000;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        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_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_read_timeout 300s;
    }
}

Save to /etc/nginx/sites-available/, link it into sites-enabled, then run sudo nginx -t && sudo systemctl reload nginx.

  • Get the certificate first: sudo certbot certonly --nginx -d example.com -d www.example.com. The paths in the config assume Certbot's defaults.
  • A location with its own add_header drops every add_header from the server block, so cached assets get Cache-Control but not the security headers. That is usually fine; copy the headers into that location if you need them.

Advertisement

Guide

About the Nginx Config Generator

nginx reads its site settings from server blocks. Each block says which ports and host names it answers, and its location blocks decide what happens to each request: serve a file, fall back to index.html, pass it to PHP-FPM, or proxy it to an app running on another port.

Pick what your site is, fill in the domain, and the generator writes the whole file, including the separate blocks that redirect plain HTTP and the non-canonical host.

Why a single-page app needs try_files

React Router, Vue Router and similar libraries handle URLs like /settings in the browser, but there is no settings file on disk. Without a fallback, a reload on that page returns 404. try_files $uri $uri/ /index.html serves the file if it exists and the app shell otherwise.

Proxy headers your app needs

Behind a proxy, your app sees every request as coming from 127.0.0.1 over HTTP. The X-Forwarded-For and X-Forwarded-Proto headers pass on the real client address and scheme, so redirects, secure cookies and rate limits behave correctly. Tell your framework to trust the proxy (for example app.set('trust proxy', 1) in Express).

How to use it

  1. 1Pick a preset or choose what nginx serves.
  2. 2Enter your domain and how www should be handled.
  3. 3Choose HTTPS and the performance options you want.
  4. 4Download the .conf, test it with nginx -t, and reload.

Frequently asked questions

Where do I put the nginx config file?

On Debian and Ubuntu, in /etc/nginx/sites-available/, linked into /etc/nginx/sites-enabled/. On other systems, in /etc/nginx/conf.d/ with a .conf extension.

How do I test the config before reloading?

Run sudo nginx -t. It checks syntax and file paths without touching the running server. If it passes, sudo systemctl reload nginx applies the change with no downtime.

Why does my WebSocket connection fail behind nginx?

nginx does not forward the Upgrade and Connection headers by default. Tick WebSocket support to add them, along with HTTP/1.1 and a longer read timeout.

How do I get a free SSL certificate?

Install Certbot and run certbot certonly --nginx -d yourdomain.com. The Let’s Encrypt option uses the paths Certbot writes, and Certbot renews the certificate automatically.

What does client_max_body_size do?

It caps the size of a request body. The default is 1 MB, so larger file uploads fail with 413 Request Entity Too Large until you raise it.

Is the http2 directive right for my nginx version?

http2 on; was added in nginx 1.25.1. On older versions, remove that line and write listen 443 ssl http2; instead.

Related tools