Nginx Reverse Proxy & Public SSL
Traffic Ingress Architecture
Section titled “Traffic Ingress Architecture”Once traffic passes through Cloudflare, it hits the Hetzner server. Nginx Proxy Manager (NPM) is the primary ingress point, listening on ports 80 and 443. It reads the Host header and routes each request to the correct Docker container on proxy-network.
Nginx Proxy Manager Setup
Section titled “Nginx Proxy Manager Setup”NPM runs in its own docker-compose.yml and connects to the proxy-network alongside the web containers. This keeps internal web servers off the public interface.
# Snippet: NPM Ingress configurationservices: proxy-manager: image: 'jc21/nginx-proxy-manager:latest' container_name: nginx-proxy-manager restart: unless-stopped ports: - '80:80' # Public HTTP routing - '443:443' # Public HTTPS routing - '100.x.x.x:81:81' # OOB Management: bound to Tailscale IP only volumes: - ./data:/data - ./letsencrypt:/etc/letsencrypt networks: - proxy-networkProxy Hosts
Section titled “Proxy Hosts”Inside the NPM dashboard, public traffic is routed using Docker’s internal DNS resolver (container names) over proxy-network:
| Domain | Forward Host | Forward Port | Container |
|---|---|---|---|
pablorosi.dev | astro-site | 80 | Portfolio (Astro) |
docs.pablorosi.dev | starlight-docs | 80 | Documentation (Starlight) |
Legacy .com domains are not configured here. Their 301 redirects are handled at the Cloudflare edge — see Cloudflare DNS & Edge Routing.
SSL: Cloudflare to Origin
Section titled “SSL: Cloudflare to Origin”Traffic is encrypted in two hops:
- Browser → Cloudflare: TLS terminated at the Cloudflare edge.
- Cloudflare → Hetzner: TLS terminated at NPM using a Let’s Encrypt certificate.
Cloudflare SSL/TLS mode is set to Full (strict). NPM must present a valid origin certificate; self-signed certs are rejected. Let’s Encrypt certificates are issued per domain inside NPM.
Real Client IP
Section titled “Real Client IP”Because Cloudflare sits in front of the origin, NPM receives Cloudflare proxy IPs unless configured otherwise. Enable Trust Proxy in NPM (or equivalent forwarded-header settings) so logs and access rules see the real client IP from CF-Connecting-IP / X-Forwarded-For.
Validation
Section titled “Validation”- Both proxy hosts (
pablorosi.dev,docs.pablorosi.dev) show a valid Let’s Encrypt certificate in the NPM dashboard. curl -I https://pablorosi.devandcurl -I https://docs.pablorosi.devreturn200with no certificate warnings in the browser.- Cloudflare SSL/TLS mode is Full (strict) and the origin handshake succeeds without errors.
- NPM access logs show real client IPs (not only Cloudflare ranges) when Trust Proxy is enabled.
Proceed to Tailscale Private Admin Access for the management-plane architecture.