Reverse Proxy Basics
Introduction
A reverse proxy accepts public HTTP traffic and forwards it to an application on your server—usually Spring Boot on port 8080 or Node on port 3000. Nginx handles connections, TLS, and static files; your app focuses on business logic. This chapter explains reverse vs forward proxy, a minimal proxy_pass setup, and why binding apps to localhost is a security win.
Prerequisites
- Serving Static Files
- Your First Virtual Host
- An app listening locally for testing (or use the examples as templates)
Forward Proxy vs Reverse Proxy
| Type | Who it serves | Example |
|---|---|---|
| Forward proxy | Clients inside a network | Corporate HTTP proxy for outbound web |
| Reverse proxy | Servers behind it | Nginx in front of your API |
Client Reverse proxy (Nginx) Backend app
│ │ │
│ GET /api/users │ │
├───────────────────►│ GET /api/users │
│ ├────────────────────────►│
│ │◄────────────────────────┤
│◄───────────────────┤ JSON response │Code explanation:
- The client only knows Nginx’s address (port 80/443)
- The backend is not directly exposed on the public internet
Minimal proxy_pass
Assume Spring Boot runs on 127.0.0.1:8080:
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}Enable and test:
sudo nginx -t && sudo systemctl reload nginx
curl -I -H "Host: api.example.com" http://127.0.0.1/Code explanation:
proxy_passforwards the request URI and method to the upstream URL- Backend must be running before
curlreturns success (502 if down)
Tip
Bind the App to Localhost
Start Java or Node with 127.0.0.1, not 0.0.0.0, when only Nginx should be public:
# Spring Boot application.properties
server.address=127.0.0.1
server.port=8080proxy_http_version 1.1
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
}Code explanation:
- HTTP/1.1 enables keepalive between Nginx and upstream
- Clearing
Connectionheader helps reuse upstream connections (advanced tuning)
For basic setups, many teams add proxy_http_version 1.1 with standard headers (next chapter).
Common Upstream Errors
| Status | Meaning | Typical fix |
|---|---|---|
| 502 Bad Gateway | Nginx cannot reach upstream | App not running; wrong port; firewall |
| 504 Gateway Timeout | Upstream too slow | Increase timeouts; fix slow app |
| 404 from app | Proxy works; route missing | Fix backend routing, not Nginx |
Check error log:
sudo tail -f /var/log/nginx/error.logStatic + Proxy on One Host
Frontend files on disk, API proxied:
Code explanation:
/api/goes to the backend/serves the SPA static files- Order and prefix specificity matter—
/api/is more specific than/
Path stripping with trailing slash is covered in the next chapter.
Why Not Expose Port 8080 Publicly?
- TLS termination stays in one place (Nginx + Certbot)
- Rate limiting, WAF, and access rules at the edge
- Firewall allows only 80/443 from the internet
- Multiple apps on one VPS via
server_name
See Linux networking and security basics for firewall context.
FAQ
Is reverse proxy required for Spring Boot?
No, but standard for production VPS deploy. Embedded Tomcat can listen on 443 with custom certs—Nginx is simpler for most teams.
Can I proxy to another machine?
Yes: proxy_pass http://10.0.0.5:8080; on a private network.
Does Nginx buffer request bodies?
Yes by default for uploads—large file settings in a later chapter.
HTTP vs HTTPS to upstream?
On same server, http://127.0.0.1 is normal. HTTPS to upstream is for strict internal security (advanced).
WebSocket through proxy?
Needs extra headers—dedicated WebSocket chapter.
Difference from load balancer?
Single upstream is reverse proxy; multiple upstreams with upstream block is load balancing (chapter 11).