Most self-hosted apps listen on a local port like 127.0.0.1:3000 and speak plain HTTP. A reverse proxy sits in front on ports 80/443, terminates HTTPS with a real certificate, and forwards traffic to that local port — giving you a clean https://app.yourdomain.com and letting you run several apps behind one IP. Here are both common ways.
Prerequisites
- A domain with an A record pointing at your server's IP (wait for DNS to propagate).
- Ports 80 and 443 open — see how to configure a UFW firewall.
- Your app running locally, e.g. on
127.0.0.1:3000.
Option A — Caddy (automatic HTTPS, one line)
sudo apt install -y caddy
echo 'app.yourdomain.com { reverse_proxy 127.0.0.1:3000 }' | sudo tee /etc/caddy/Caddyfile
sudo systemctl restart caddy
That's it — Caddy obtains a Let's Encrypt certificate for the domain and renews it automatically.
Option B — nginx + Certbot
sudo apt install -y nginx certbot python3-certbot-nginx
Create /etc/nginx/sites-available/app:
server {
listen 80;
server_name app.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:3000;
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 add HTTPS:
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d app.yourdomain.com
Certbot edits the config to serve HTTPS and sets up auto-renewal.
Honest cautions
- DNS and ports are the usual failures. The A record must point here and have propagated, and 80/443 must be reachable, or certificate issuance fails. Both tools retry once that's fixed.
- Only expose what you mean to. Keep the app bound to
127.0.0.1so it's reachable only through the proxy, not directly. - HTTPS needs a domain, not a bare IP — Let's Encrypt issues for names.
Next steps
A reverse proxy is what lets one box serve many things — see self-hosting multiple services behind one IP. Running the app in a container? Start with how to install Docker. To keep the app itself alive across reboots and crashes, see how to create a systemd service.
Comments
No comments yet. Be the first.