If you're self-hosting more than one service at home — say, a media server on port 8096 and a file-sync tool on port 8384 — remembering ports gets old fast, and none of them get HTTPS by default. A reverse proxy solves both: it sits in front of everything on ports 80/443, and routes requests to the right internal service based on subdomain.
01Install Nginx
sudo apt update
sudo apt install nginx
Confirm it's running by visiting your server's IP in a browser — you should see the default Nginx welcome page.
02Point your domains at your server
In your DNS provider's dashboard, create A records for each subdomain pointing at your server's public IP, for example media.yourdomain.com and files.yourdomain.com. If this is purely for a home network without a public domain, you can instead edit each client's hosts file, or run a local DNS resolver like Pi-hole with custom entries.
03Create a server block per service
Each service gets its own config file. For the media server example:
sudo nano /etc/nginx/sites-available/media.yourdomain.com
server {
listen 80;
server_name media.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8096;
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;
}
}
Enable it and repeat for each additional service with its own file and port:
sudo ln -s /etc/nginx/sites-available/media.yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
04Add free HTTPS with Certbot
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d media.yourdomain.com -d files.yourdomain.com
Certbot edits your Nginx configs automatically to add certificates and redirect HTTP to HTTPS, and sets up auto-renewal via a systemd timer — you shouldn't need to touch it again.
05Forward the right ports on your router
Only ports 80 and 443 need to be forwarded to your server's local IP — not the individual service ports. This is the actual point of the reverse proxy: everything external only ever talks to Nginx.
proxy_set_header Host $host; causes apps that check the Host header (many do, for security) to reject requests or redirect incorrectly. If a proxied app behaves strangely, check this line first.