A reverse proxy is a server that sits in front of internal services (such as web servers) and forwards client requests (e.g. from the internet) to them. It acts as an intermediary that can handle load balancing, SSL termination, caching, and security filtering.

Nginx and Cloudflare are famous examples of reverse proxies, both of which are used in this Homelab.

It’s the opposite of a Forward Proxy, which connects internal clients to the outer world.

The double reverse-proxy

One use of a reverse proxy is to hide one’s IP address. It’s (theoretically) impossible to figure out my home router’s address because it is shielded by Cloudflare. The DNS entry for https://one137.dev points to their server and this is all the user can know. When the user connects and asks for resources, Cloudflare transparently fetches them on the user’s behalf from my server, and serve them back as if they were stored on their own servers. (In one137’s case, this is further secured by using the Cloudflared tunnel, which means http ports are not even open on my router and no DNS record needs pointing to it).

It isn’t complicated to implement a reverse proxy that does the core of what Cloudflare does in this situation. It’s sometimes referred to as a “double reverse proxy”, because this proxy isn’t directly connected to any of your services. Rather, it’s connected to your primary reverse proxy: the one connected to your services on your LAN, through your router.

Here’s a complete Nginx configuration for this purpose:

user nginx;
worker_processes  auto;
worker_rlimit_nofile 4096;
 
# load_module modules/ngx_http_modsecurity_module.so; # See modsecurity below
 
events {
    worker_connections  4096;
    use epoll;
}
 
error_log /var/log/nginx/system.log notice;
 
http {
    include mime.types;
 
    gzip on;
    gzip_types text/plain text/css application/json application/javascript application/xml image/svg+xml;
    gzip_min_length 1024;
 
    resolver 1.1.1.1 valid=300s;
    resolver_timeout 5s;
 
  	server {
        listen 443 ssl http2;
    	listen [::]:443 ssl http2;
        server_name one137.dev;
 
        ssl_certificate /var/lib/nginx/certs/fullchain.pem;
        ssl_certificate_key /var/lib/nginx/certs/privkey.pem;
 
        ssl_session_cache shared:SSL:10m;
        ssl_session_tickets off;
 
      	# Block Exploits (TODO)
 	 	# include conf.d/include/block-exploits.conf;
 
        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
        add_header X-Content-Type-Options "nosniff";
        add_header X-Frame-Options "SAMEORIGIN";
        add_header Referrer-Policy "no-referrer-when-downgrade";
 
        location / {
            # modsecurity on; # (TODO)
      
			access_log /var/log/nginx/revprox.access.log;
			error_log /var/log/nginx/revprox.error.log notice;
 
            add_header X-Served-By $host;
      
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header Host one137.dev; # While SECRETSUBDOMAIN.one137.dev points to the router's public IP, one137.dev is the host configured in NPM
 
      		proxy_ssl_server_name on;
   			proxy_ssl_protocols TLSv1.3;
      		
            proxy_pass https://SECRETSUBDOMAIN.one137.dev$request_uri;
        }
    }
 
    server {
        listen 80;
        listen [::]:80;
        server_name one137.dev;
        return 301 https://$host$request_uri;
    }
}

Besides this Nginx instance running somewhere in the cloud, the following is needed:

  1. A public static IP address associated with Nginx
  2. A static DNS A record that point yourwebsite.com to that Nginx IP
  3. A DynDNS A record that points SECRETSUBDOMAIN.yourwebsite.com to your router’s public IP (make SECRETSUBDOMAIN hard to guess)
  4. Port 443 open on your router and forwarding traffic to your internal reverse proxy
  5. You’ll need to deal with your SSL certificates’ renewals.

One can easily have all this running for just a few dollars per month. That being said, Cloudflare (or other comparable services) is free and provides additional layers of security, so it is a good option.