How to Set Up a Reverse Proxy with Nginx (One Address for All Your Apps)

Reverse proxy: one address for every app — No more port numbers.

After a few Docker apps your server is a list of port numbers: :3001 for monitoring, :8080 for Nextcloud, :8096 for Jellyfin. A reverse proxy sits in front and routes by name instead: status.home.example.com goes to 3001, cloud.home.example.com to 8080, and every one of them gets HTTPS from a single Certbot run. Nginx does this with a six-line block per app.

Quick reference

TaskWhat
One app behind a nameproxy_pass http://127.0.0.1:3001; in a server block
Headers apps needproxy_set_header Host $host; and X-Forwarded-* lines
WebSockets (live updates)proxy_http_version 1.1; + Upgrade/Connection headers
Add HTTPSsudo certbot --nginx -d status.example.com
No-typing alternativeNginx Proxy Manager (a Docker app with a web UI)

1. Bind apps to localhost

Change each app's port mapping so it only listens on the server itself, not the network:

ports:
- "127.0.0.1:3001:3001"

Now the only way in is through Nginx.

2. A server block per app

sudo nano /etc/nginx/sites-available/status.example.com

server {
listen 80;
server_name status.example.com;

location / {
proxy_pass http://127.0.0.1:3001;
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;

# WebSockets (needed by Uptime Kuma, Home Assistant, Jellyfin, code-server...)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

sudo ln -s /etc/nginx/sites-available/status.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Copy the file for each app, changing only server_name and the port.

3. DNS

Each name needs to resolve to the server. Easiest is a wildcard record: *.home.example.com → your IP, then every subdomain works without adding records. Inside your home network, Pi-hole (tutorial 34) can do the same with a local DNS entry.

4. HTTPS for all of them

sudo certbot --nginx -d status.example.com -d cloud.example.com -d media.example.com

Certbot edits every matching server block. Add -d names as you add apps, or get a wildcard certificate with the DNS challenge.

5. Big uploads

Nginx limits uploads to 1 MB by default, which breaks Nextcloud and anything else that takes files. In the server block:

client_max_body_size 10G;

Prefer clicking to typing?

Nginx Proxy Manager is a Docker container that runs Nginx and gives you a web page to add hosts, certificates and redirects. Same result, no config files. It's a good choice if you'll be adding apps often.

Troubleshooting

502 Bad Gateway. Nginx is fine but the app behind it isn't answering. docker ps — is it running? Is the port in proxy_pass right? Can you curl http://127.0.0.1:3001 on the server?

The app loads but says "untrusted domain" / "invalid host". Apps like Nextcloud keep a list of allowed hostnames. Add the new name in the app's config (trusted_domains for Nextcloud).

Live updates don't work / page keeps reconnecting. Missing WebSocket lines. Add the three proxy_http_version and Upgrade lines.

The app thinks it's on http and makes http links. It needs X-Forwarded-Proto and to be told to trust the proxy — look for "proxy" or "trusted proxies" in its settings.

Redirect loop. The app has its own HTTPS redirect, and Nginx is talking to it over HTTP. Turn the app's redirect off; Nginx handles it.

Wrapping up

Bind apps to localhost, one small server block each, wildcard DNS, one Certbot command. From then on every new app is a copied file and a reload, and nobody in your house has to remember a port number again.

Call us