How to Set Up a Reverse Proxy on Your VPS: Nginx, HAProxy, and Caddy Compared

Why Use a Reverse Proxy on Your VPS?

A reverse proxy sits in front of your backend services, handling incoming requests and distributing them to the appropriate application. It is essential for running multiple services like Node.js, Python apps, and static sites on a single VPS, providing SSL termination, load balancing, caching, and security filtering. This guide walks through setting up three popular options on your VPS and compares their strengths for different use cases.

  • SSL termination: Handle HTTPS at the proxy layer, keeping backend traffic unencrypted and fast.
  • Port management: Route requests to different internal ports (3000, 8080, 5000) all through port 80/443.
  • Load balancing: Distribute traffic across multiple backend instances for high availability.
  • Caching: Serve static assets from the proxy cache, reducing backend load by 60-80%.
  • Security: Hide backend server details, rate-limit requests, and filter malicious traffic at the edge.

Option 1: Nginx – The Industry Standard

Nginx powers over 30% of websites. It excels as a reverse proxy with low memory usage, as little as 2MB per worker, and excellent concurrency handling with its event-driven architecture.

Nginx Configuration Example

# /etc/nginx/sites-available/reverse-proxy.conf
server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/ssl/certs/cert.pem;
    ssl_certificate_key /etc/ssl/private/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Pros: Proven performance at scale (10,000+ concurrent connections on a 1GB VPS), WebSocket proxying out of the box, extensive module ecosystem, and excellent static file serving.

Cons: Configuration can be verbose, no native active health checking without Nginx Plus, and reloads require SIGHUP.

Option 2: HAProxy – The Load Balancing Specialist

HAProxy is designed specifically for high-availability load balancing. It offers granular health checks, advanced routing algorithms, and an astonishingly small memory footprint of approximately 15MB for 10,000 connections. It is the go-to choice for mission-critical routing.

HAProxy Configuration Example

# /etc/haproxy/haproxy.cfg
global
    log /dev/log local0
    maxconn 4096
    user haproxy
    group haproxy

defaults
    log global
    mode http
    option httplog
    timeout connect 5000
    timeout client 50000
    timeout server 50000

frontend web_front
    bind *:443 ssl crt /etc/haproxy/certs/
    default_backend app_servers

backend app_servers
    balance roundrobin
    option httpchk GET /health
    server app1 127.0.0.1:3000 check inter 10s fall 3 rise 2
    server app2 127.0.0.1:3001 check inter 10s fall 3 rise 2

Pros: Best-in-class health checking (active and passive), lowest memory overhead, advanced ACL engine for traffic routing, and a native stats dashboard.

Cons: No native static file serving (pair with Nginx), SSL configuration less intuitive than Caddy.

Option 3: Caddy – The Modern Automatic Choice

Caddy is a Go-based web server that automates HTTPS via Let’s Encrypt and has a clean, readable configuration language called the Caddyfile. It is the easiest option to set up securely with zero manual certificate management.

Caddy Configuration Example

# Caddyfile
app.example.com {
    reverse_proxy localhost:3000

    # Route /api/* to a different backend
    handle_path /api/* {
        reverse_proxy localhost:8080
    }

    # Static files directly
    handle /static/* {
        root * /var/www/static
        file_server
    }
}

api.example.com {
    reverse_proxy localhost:8080
}

Pros: Automatic HTTPS with Let’s Encrypt, clean minimal configuration, native HTTP/2 and HTTP/3 (QUIC) support, and built-in static file serving.

Cons: Higher memory footprint (~50MB idle vs ~10MB for Nginx/HAProxy), smaller ecosystem of modules, and Go-based debugging can be less familiar.

Which One Should You Choose?

Use CaseRecommendation
Single VPS, multiple apps, want SSL automationCaddy – fastest to set up, automatic HTTPS
High-traffic site needing load balancing and health checksHAProxy – most robust for mission-critical routing
Traditional web serving plus reverse proxyNginx – best all-rounder, largest community
API gateway with multiple microservicesHAProxy or Nginx with proper upstream configs
Minimum setup time with no SSL hassleCaddy – one config file, HTTPS enabled by default

All three can run on a 1GB VPS alongside your applications. For production environments, many administrators run HAProxy as the frontend load balancer and Nginx as the SSL terminator and static file server, combining the strengths of both.

Choosing the right VPS plan matters too. Compare VPS hosting plans to ensure you have enough CPU and RAM for both your proxy layer and your application workloads.

Leave a Reply