Home DNS Lookup Ping Traceroute IP Location IP Calculator MAC Lookup iPerf IPv6 Calc Port Check Port Scaner Speedtest Blog

Using Reverse Proxy with Nginx and Apache for Better Security and Caching

Introduction

A reverse proxy sits in front of your app servers and handles incoming requests on their behalf. Done right, it improves security, performance, and resilience while simplifying TLS, caching, and scaling.

How a reverse proxy works

The proxy terminates client connections, applies policies (TLS/headers/rate limits), forwards requests to one or more backends, then returns responses to the client. It can also cache content and balance load across instances.

Key benefits

  • Shield origin: backends are not exposed to the public Internet.
  • Load balancing: distribute traffic across multiple servers.
  • Caching: serve hot assets from the proxy to cut latency and origin load.
  • TLS offload: centralize certificates and enable HTTP/2/3 at the edge.
  • Policy control: add security headers, WAF, rate limiting, IP allow/deny lists.

Nginx quick start (reverse proxy + SSL + cache)

# /etc/nginx/conf.d/app.conf
upstream app_backend {
    server 127.0.0.1:3000 max_fails=3 fail_timeout=10s;
    # server 10.0.0.12:3000;
    # server 10.0.0.13:3000;
}

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=STATIC:100m
                 inactive=60m max_size=2g;

server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/ssl/example.crt;
    ssl_certificate_key /etc/ssl/example.key;

    # Security headers at the edge
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self' https:" always;

    # Static caching (tune by path or mime)
    location ~* \.(css|js|png|jpg|jpeg|gif|svg|woff2?)$ {
        proxy_pass http://app_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache STATIC;
        proxy_cache_valid 200 301 302 10m;
        proxy_cache_valid 404 1m;
        add_header X-Cache $upstream_cache_status;
    }

    # Default proxy
    location / {
        proxy_pass http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header Connection "";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 30s;
        client_max_body_size 25m;  # uploads
    }
}

server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;  # HSTS after validating TLS
}

Tip: For APIs that must not be cached, set Cache-Control: no-store at the app or add a proxy_no_cache rule.

Apache (httpd) quick start (mod_proxy + mod_cache)

# Enable modules (Debian/Ubuntu examples)
# a2enmod proxy proxy_http headers ssl http2 cache cache_disk

<VirtualHost *:443>
  ServerName example.com
  Protocols h2 http/1.1
  SSLEngine on
  SSLCertificateFile      /etc/ssl/example.crt
  SSLCertificateKeyFile   /etc/ssl/example.key

  # Security headers
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set X-Content-Type-Options "nosniff"
  Header always set Referrer-Policy "strict-origin-when-cross-origin"
  Header always set Content-Security-Policy "default-src 'self' https:"

  # Forward to backend
  ProxyPreserveHost On
  ProxyPass        / http://127.0.0.1:3000/
  ProxyPassReverse / http://127.0.0.1:3000/

  # Disk cache for static
  CacheQuickHandler On
  CacheRoot "/var/cache/apache2/mod_cache_disk"
  CacheEnable disk "/"
  CacheIgnoreHeaders Set-Cookie
  CacheDefaultExpire 600
  ExpiresActive On
  ExpiresByType text/css "access plus 10 minutes"
  ExpiresByType application/javascript "access plus 10 minutes"
  ExpiresByType image/* "access plus 30 minutes"

  # Limit request size
  LimitRequestBody 26214400  # 25 MB
</VirtualHost>

# Redirect HTTP to HTTPS
<VirtualHost *:80>
  ServerName example.com
  Redirect permanent / https://example.com/
</VirtualHost>

Hardening checklist

Item Why
Hide origins (no public access) Reduce attack surface; only proxy is exposed.