What this builds
A complete nginx server { } block, assembled live as you fill in the form. Pick a backend mode (static site, reverse proxy, or PHP-FPM), set your domain, flip SSL on, and the directives appear on the right. Copy it, or grab it as a .conf you can scp straight to a box.
It’s all client-side. Nothing you type touches a server, which matters when you’re pasting real cert paths and internal upstream addresses.
The three backend modes
Most server blocks fall into one of three shapes, and this generator covers all three:
- Static / SPA drops in a
root, anindex, and atry_files $uri $uri/ =404so missing files return a clean 404. Good for plain HTML, or a built React/Vue bundle. - Reverse proxy skips
rootentirely and forwardslocation /to whatever upstream you name. It also writes theproxy_set_headerlines you almost always forget (Host,X-Real-IP,X-Forwarded-For,X-Forwarded-Proto) plus theUpgrade/Connectionpair that WebSockets need. - PHP-FPM wires
location ~ \.php$to a FastCGI socket, includessnippets/fastcgi-php.conf, and denies access to.ht*files. Point it atunix:/run/php/php8.3-fpm.sock(or whatever your distro named it) and you’re done.
Switch modes and the irrelevant fields disappear. No root line cluttering a proxy block.
SSL, the right way
Tick “Enable SSL” and three things happen at once. The main block flips to listen 443 ssl with http2 on, your two cert paths get wired into ssl_certificate and ssl_certificate_key, and the protocol line locks to TLS 1.2 and 1.3, no ancient SSLv3 nonsense.
Leave “Redirect 80 → 443” checked and the generator emits a second, tiny server block up top that catches plain HTTP and fires back a 301 to HTTPS. That’s the standard Let’s Encrypt layout. The default cert paths already match certbot’s /etc/letsencrypt/live/<domain>/ convention, so for a lot of setups you barely touch them.
Custom location blocks
Need /api to hit a different upstream than /? Add a custom location. Each one takes a path matcher (/api, ~ \.css$, = /favicon.ico, anything nginx accepts) and a free-text body. Whatever you type in the body gets indented and dropped inside the braces verbatim, so you’re not boxed into proxy-only blocks. Add a cache header, a return 403, an alias, your call.
You can stack as many as you want. They render in order, after the main location /.
A couple of details worth knowing
client_max_body_size defaults to 16m. The nginx built-in default is a measly 1m, which is why file uploads mysteriously die with a 413. Bump this if users upload anything bigger than a small image.
The gzip toggle writes a sane gzip_types list (text, CSS, JS, JSON, SVG) plus gzip_vary on and a gzip_min_length 1024 so it doesn’t bother compressing tiny responses. Every block also gets per-site access_log and error_log paths named after your first server_name, which makes tailing logs a lot less painful when you’re running 20 vhosts.
FAQ
Where does this file go?
Usually /etc/nginx/sites-available/yourdomain.conf, then symlink it into sites-enabled/. On RHEL-style systems it’s /etc/nginx/conf.d/yourdomain.conf instead. Reload with nginx -s reload after a clean nginx -t.
Always run nginx -t first?
Yep. It validates syntax without touching the running server. A reload on a broken config can drop every site on the box, so test, then reload.
Does it generate the SSL certificates too?
Nope, it only references the paths. Get the actual cert and key from certbot, your CA, or a self-signed openssl command, then paste those two paths in.
Can I proxy to a Unix socket instead of a port?
Sure. Put something like http://unix:/run/app.sock:/ in the proxy_pass field, or use a custom location block for finer control.
Why two server blocks when I enable SSL? The small one on port 80 exists only to redirect HTTP visitors to HTTPS. Untick the redirect option and you’ll get a single block that listens on 443 alone.