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

Forward Proxy vs Reverse Proxy

TypeWho it servesExample
Forward proxyClients inside a networkCorporate HTTP proxy for outbound web
Reverse proxyServers behind itNginx in front of your API
text
  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:

nginx
server {
    listen 80;
    server_name api.example.com;
 
    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

Enable and test:

bash
sudo nginx -t && sudo systemctl reload nginx
curl -I -H "Host: api.example.com" http://127.0.0.1/

Code explanation:

  • proxy_pass forwards the request URI and method to the upstream URL
  • Backend must be running before curl returns 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:

bash
# Spring Boot application.properties
server.address=127.0.0.1
server.port=8080

proxy_http_version 1.1

nginx
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 Connection header 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

StatusMeaningTypical fix
502 Bad GatewayNginx cannot reach upstreamApp not running; wrong port; firewall
504 Gateway TimeoutUpstream too slowIncrease timeouts; fix slow app
404 from appProxy works; route missingFix backend routing, not Nginx

Check error log:

bash
sudo tail -f /var/log/nginx/error.log

Static + 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).