The Digital Guardian of My Homelab: Setting Up a Secure Reverse Proxy with HTTPS

Goals

  • Access all your internal web services (Proxmox, n8n, and databases) securely over HTTPS domains using a reverse proxy.
  • Use Let’s Encrypt for free, automated SSL certificates.

Why Use a Reverse Proxy?

A reverse proxy acts as a centralized gateway to your homelab services, providing several critical benefits:

  • Unified SSL Management: Single point for certificate management
  • Security Layer: Protection against direct service exposure
  • Custom Domains: Clean URLs instead of IP:PORT combinations
  • Load Balancing: Distribute traffic across multiple backend servers

Architecture Overview

Internet/LAN
    ↓
pfSense Firewall
    ↓
Nginx Proxy Manager (Reverse Proxy)
    ↓
├── Proxmox (192.168.x.x:8006)
├── n8n (192.168.x.x:5678)
├── Databases (192.168.x.x:XXXX)
└── Other Services

Step 1: Deploy Reverse Proxy VM/Container

Option A: Lightweight VM

  • Create a new VM on Proxmox (Debian/Ubuntu recommended)
  • Allocate minimal resources: 1 CPU, 2GB RAM, 10GB storage
  • Install Docker and Docker Compose
  • Use Proxmox helper scripts for faster deployment
  • More efficient resource usage
  • Easier management

Install Docker and Docker Compose

# Update system
sudo apt update && sudo apt upgrade -y

# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Install Docker Compose
sudo apt install docker-compose -y

# Add user to docker group
sudo usermod -aG docker $USER

Step 2: Install Nginx Proxy Manager

Docker Compose Configuration

Create docker-compose.yml:

version: '3'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '80:80'      # HTTP
      - '81:81'      # Admin UI
      - '443:443'    # HTTPS
    environment:
      DB_MYSQL_HOST: "db"
      DB_MYSQL_PORT: 3306
      DB_MYSQL_USER: "npm"
      DB_MYSQL_PASSWORD: "npm"
      DB_MYSQL_NAME: "npm"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
  db:
    image: 'jc21/mariadb-aria:latest'
    container_name: npm-database
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 'npm'
      MYSQL_DATABASE: 'npm'
      MYSQL_USER: 'npm'
      MYSQL_PASSWORD: 'npm'
    volumes:
      - ./data/mysql:/var/lib/mysql

Launch Nginx Proxy Manager

docker-compose up -d

Access Admin UI

  • Navigate to: http://<proxy-vm-ip>:81
  • Default credentials:
    • Email: admin@example.com
    • Password: changeme
  • Immediately change these credentials after first login!

Step 3: Configure Internal DNS

Using pfSense DNS Resolver

  1. Navigate to Services > DNS Resolver
  2. Enable DNS Resolver if not already enabled
  3. Under Host Overrides, add entries:
    • Host: proxmox, Domain: lab, IP: <proxy-ip>
    • Host: n8n, Domain: lab, IP: <proxy-ip>
    • Host: db, Domain: lab, IP: <proxy-ip>

Alternative: Local Hosts File

For testing purposes, edit your local /etc/hosts:

<proxy-ip>  proxmox.lab
<proxy-ip>  n8n.lab
<proxy-ip>  db.lab

Step 4: Add Services as Proxy Hosts

In Nginx Proxy Manager UI

  1. Click “Proxy Hosts”“Add Proxy Host”
  2. Details Tab:
    • Domain Names: n8n.lab
    • Scheme: http
    • Forward Hostname/IP: <n8n-container-ip>
    • Forward Port: 5678
    • Block Common Exploits: ✓
    • Websockets Support: ✓ (important for n8n)
  3. Repeat for other services:
    • Proxmox: Port 8006, Scheme https
    • Databases: Port varies, Scheme http

Step 5: Request SSL Certificates

Enable Let’s Encrypt

  1. In Proxy Host entry, go to SSL Tab
  2. Select “Request a new SSL Certificate”
  3. Options:
    • Force SSL: ✓
    • HTTP/2 Support: ✓
    • HSTS Enabled: ✓ (recommended)
    • Email for Let’s Encrypt: Your email
  4. Click Save

Let’s Encrypt will automatically: - Generate SSL certificate - Configure HTTPS - Set up auto-renewal (every 90 days)

DNS Challenge (For Wildcard Certificates)

If you own a domain and want *.yourdomain.com:

  1. Use DNS challenge method
  2. Configure DNS provider credentials in NPM
  3. Request wildcard certificate: *.yourdomain.com

Step 6: Open Port 443 in Firewall

pfSense Configuration

  1. Navigate to Firewall > NAT > Port Forward
  2. Create rule:
    • Interface: WAN
    • Protocol: TCP
    • Destination Port Range: 443
    • Redirect Target IP: <proxy-vm-ip>
    • Redirect Target Port: 443
    • Description: Reverse Proxy HTTPS
  3. Create corresponding firewall rule if needed

VM/Container Firewall

If using UFW:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 81/tcp  # Admin UI (restrict to LAN only!)

Step 7: Test Access

Internal Testing

From your LAN:

curl -k https://n8n.lab
curl -k https://proxmox.lab:8006

Browser Testing

  1. Open browser
  2. Navigate to https://n8n.lab
  3. Verify:
    • ✅ Valid SSL certificate (green padlock)
    • ✅ Service loads correctly
    • ✅ No certificate warnings

Security Hardening

Restrict Admin UI Access

  1. In Nginx Proxy Manager:

    • Access Lists → Create new
    • Authorization: Require username/password
    • Apply to admin UI proxy host
  2. Firewall rules:

    # Allow admin UI only from LAN
    sudo ufw deny 81/tcp
    sudo ufw allow from 192.168.0.0/16 to any port 81

Enable Fail2Ban

Protect against brute-force attacks:

sudo apt install fail2ban -y

# Create NPM filter
sudo nano /etc/fail2ban/filter.d/npm.conf
[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD).*HTTP.*" (4|5)\d\d
ignoreregex =

Monitoring and Maintenance

Check Certificate Expiry

Nginx Proxy Manager automatically renews certificates 30 days before expiry.

Verify in UI: - SSL Certificates → Check expiry dates

Log Monitoring

# View NPM logs
docker logs -f nginx-proxy-manager

# Access logs location
cd ./data/logs

Performance Monitoring

Add monitoring with: - Prometheus + Grafana - Uptime Kuma for service availability

Common Issues and Solutions

Issue 1: Certificate Request Fails

Problem: Let’s Encrypt challenge fails

Solution: - Verify port 80 is accessible from internet - Check DNS resolution - Try HTTP challenge instead of DNS

Issue 2: WebSocket Connection Fails

Problem: Real-time features don’t work (n8n, Proxmox console)

Solution: - Enable Websockets Support in proxy host - Add custom Nginx configuration: nginx proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";

Issue 3: Proxmox WebUI Access Denied

Problem: Cannot access Proxmox through proxy

Solution: - Set Forward Scheme to https - Add custom headers: nginx proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr;

Conclusion

Setting up a reverse proxy with Nginx Proxy Manager provides centralized, secure access to all your homelab services. The combination of automated SSL certificates, custom domains, and unified management creates a professional infrastructure that’s both secure and easy to maintain.

This setup serves as the digital guardian of your homelab, protecting services while providing convenient access. With proper configuration and security hardening, you can safely expose selected services to the internet while maintaining robust protection against unauthorized access.

Remember: Security is an ongoing process. Regularly update your reverse proxy, monitor logs, and review access patterns.