Nginx Server Block Generator

Build the server { } blocks that make Nginx serve your domains, local applications and static websites — without hand-writing the config or copying half-broken snippets. Pick a starting preset (static site on your LAN, HTTPS with Let's Encrypt, a single-page app, or a local app behind a proxy), add one card per virtual host, and get a live Nginx site file you can drop straight into /etc/nginx/sites-available/. The generator writes the parts people forget — the HTTP→HTTPS redirect, the ACME webroot so certbot can renew, the SPA fallback so deep links don't 404, the forwarded-IP headers your app needs — and checks the mistakes that actually break site files: TLS with no certificate paths, a proxy pointed at Nginx's own port, duplicate server_names, a relative root.

🔒 100% private — nothing is uploaded or stored. The server block configuration is generated entirely in your browser. If you upload an existing site file it is parsed locally and never sent to a server, so you can safely import configs that contain your domains, internal paths or certificate locations.

1 · Starting point

Pick a preset to fill the form with a working baseline. Choosing a preset replaces the current sites — everything can be edited afterwards.

2 · Sites (one card per virtual host)

Each site gets its own server block. List every domain the block should answer for in Server name(s) — space-separated, e.g. example.com www.example.com. A Default (catch-all) site absorbs traffic that matches nothing else.

3 · Global settings

Port Nginx answers on when TLS is off. 80 is standard; use 8080 if something else owns 80.
A path inside the site's root, e.g. /404.html. Leave empty for Nginx's default error page.

Import an existing config (optional)

Paste an nginx site file (e.g. from cat /etc/nginx/sites-available/mysite) or upload it — it is parsed in your browser and loaded into the form above. One card per server block: static sites keep their root/index, proxied ones keep their backend host and port, and TLS settings, certificate paths, the HTTP→HTTPS redirect and the ACME webroot are picked up too. Everything else is reported and left out.

Your Nginx server blocks

ready

Install it (three commands)

Run on the server. Step 3 is the safety net: nginx -t validates the file and only reloads if it parses — a typo can't take Nginx (and every site behind it) down.

How virtual hosting works

Nginx can serve hundreds of sites from one machine because every HTTP request carries a Host header. Each server { } block declares the names it answers for in its server_name; when a request arrives, Nginx matches the Host header against those lists and hands the request to the matching block. No match? It goes to the block flagged default_server — which is why a catch-all card exists here.

That one mechanism covers everything on this page: example.com and www.example.com can share a block, your static site and your proxied app live in separate blocks on the same ports, and a default block drops (or redirects) traffic for names you don't host. The only real constraint is that two blocks must not claim the same name on the same port — Nginx will serve whichever it reads first, and your edits to the "right" file will appear to do nothing.

The mistakes that actually break server blocks

  1. SPAs 404 on refresh. A single-page app serves every route from index.html, but Nginx's default behaviour asks the filesystem for /settings, finds no such file, and answers 404. The fix is try_files $uri $uri/ /index.html; — tick Single-page app on the site card and this generator writes it.
  2. 403 Forbidden from a missing index file. With autoindex off (the default), a request to the site root needs one of the files listed in index. If root /var/www/mysite; points at a folder that has no index.html, every visitor gets 403. The generator flags an empty index; check the folder with ls /var/www/mysite.
  3. The proxy points at its own port. proxy_pass http://127.0.0.1:80 where Nginx itself listens on 80 is an infinite loop — requests bounce forever until they time out. The generator flags any backend port that equals the listen port.
  4. The redirect swallows certbot. A server-level return 301 https://... runs before location matching, so an ACME challenge location can never be reached and renewals fail. This generator puts the redirect inside location /, leaving /.well-known/acme-challenge/ free — a certificate that can't renew is a site that breaks in ~90 days.
  5. Duplicate server_name across site files. Two blocks claiming the same name (often in two different files under sites-enabled/) and Nginx serves whichever it reads first. The generator flags duplicates within this config; check old files with grep -r server_name /etc/nginx/sites-enabled/.
  6. The stock default site still wins. Debian ships sites-enabled/default, which is a default_server on port 80. If your real site isn't the default, unmatched Hosts keep landing on it — the install commands remove it, and the optional catch-all card lets you decide what happens to unknown names afterwards.
  7. Apps see 127.0.0.1 instead of the real client. Without X-Forwarded-For/X-Real-IP, every request in your app's logs looks like it came from localhost, and rate limiters or geo features misbehave. This generator always sends the forwarded-IP headers on proxied locations.

Key directives reference

DirectiveWhat it does
listen 80; / listen 443 ssl;The ports this block answers on. ssl terminates TLS here (the certificate lives in Nginx, not in every app).
server_nameThe Host names this block answers for. Space-separated; _ is the conventional "nothing" for a catch-all.
default_serverFlags this block as the fallback for unmatched Hosts on that port. Only one block per port can claim it.
root /var/www/mysite;The folder static files are served from. Must be an absolute path; the request path is appended to it.
index index.html;Files tried for a directory request, in order. None found + autoindex off = 403.
try_files $uri $uri/ /index.html;The SPA fallback: try the real file, then the directory, then hand everything else to the app shell so client-side routing works on refresh.
location ~* \.(css|js|...)$Regex location for static assets. ~* = case-insensitive; regex locations beat prefix ones, so assets get their own rules (like expires 30d;) regardless of other locations.
proxy_pass http://127.0.0.1:8000;Where the request actually goes for a proxied site. No trailing slash = the full path is forwarded unchanged.
proxy_set_header Host $host;Forward the original hostname (not 127.0.0.1) so virtual-hosted apps and URL generation work behind the proxy.
return 301 https://$host$request_uri;The permanent HTTP→HTTPS redirect. Placed inside location / here so the ACME challenge path is still reachable for certbot.
error_page 404 /404.html;Serve your own not-found page instead of Nginx's default. The file must exist inside the site's root.
client_max_body_sizeLargest request body Nginx accepts before answering 413. The default is 1M — uploads bigger than that fail at the proxy, not the app.

Luke Keam
Spot a bug or want a custom utility built? I'd love to hear from you. Get in touch
Luke Keam | techgeek.biz