How to set up a reverse proxy in front of your app
The short version: A reverse proxy sits between the internet and your app, handling TLS termination, routing, buffering, and limits — so your app focuses on logic and never faces raw traffic. nginx is the common choice: your app listens on a high local port, and nginx forwards to it with proxy_pass. This guide gives a minimal working config and the timeouts and body-size limits worth setting.
What a reverse proxy does for you
Your app could listen on port 443 directly — but then it has to handle TLS certificates, slow clients, request limits, and routing itself. A reverse proxy takes all of that off its plate:
TLS termination
The proxy holds your certificate and handles HTTPS, so your app speaks plain HTTP locally.
Routing
Send /api to one service, / to another, by path or hostname — without changing app code.
Limits & buffering
Cap body size, set timeouts, and buffer slow clients so they don't tie up your app.
A single control point
Rate limits, headers, and gzip live in one place in front of everything you run.
A minimal nginx config that works
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
The X-Forwarded-* headers matter: without them your app sees every request as coming from 127.0.0.1 over HTTP, which breaks client-IP logging and HTTPS redirects.
The limits worth setting
Two defaults bite people constantly — the body-size cap and the read timeout:
client_max_body_size 10m; # default 1m -> uploads fail with 413
proxy_read_timeout 30s; # how long to wait on a slow app -> 504
proxy_connect_timeout 5s;
Set the body size to your largest legitimate upload, and keep the read timeout aligned with how long your slowest real endpoint takes.
Errors you might hit
Most reverse-proxy problems surface as one of these:
A gateway, built in
Infraveil ships with a built-in traffic gateway in front of your services on your own servers — so routing, health-gated traffic, and security rules (rate limiting, geo-blocking) live in one place without hand-maintaining proxy config per service. You still own your TLS and certs; the gateway handles the routing and protection layer for you.
Frequently asked questions
What is a reverse proxy?
A server that sits in front of your app and forwards client requests to it, handling TLS, routing, buffering, and limits. nginx, HAProxy, and Caddy are common choices.
Why do I need a reverse proxy?
It offloads TLS, protects your app from slow clients, gives you one place for limits and routing, and keeps your app off privileged ports. It's the standard way to expose a backend safely.
What does proxy_pass do?
It tells nginx where to forward a matched request — e.g. proxy_pass http://127.0.0.1:3000 sends traffic to your app listening locally on port 3000.
Why does my app see 127.0.0.1 as the client IP?
Because the proxy is the immediate client. Forward the real client IP with proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for and have your app trust that header.