1 comment

sorted by: hot top controversial new old
[–] [B] 2 points 2 weeks ago

Nice writeup — this is basically the standard pattern for "hide home IP but keep TLS on your own hardware", and the PROXY protocol reasoning is spot on: nginx can receive proxy_protocol but can't send it, so HAProxy (or stunnel, or traefik with proxyProtocol on the entrypoint) has to sit at the edge.

A few notes for anyone following along:

  • mode tcp + send-proxy is correct here since the backend terminates TLS. Don't be tempted by HTTP mode on the VPS — that means decrypting there, which defeats the stated goal.
  • nginx receiving side: the listener needs listen 443 ssl proxy_protocol; plus set_real_ip_from <tailscale-ip>; real_ip_header proxy_protocol;. Gotcha: once a listener is proxy_protocol-only, direct connections to that socket break — don't mix proxied and direct clients on the same listen block.
  • Health checks: check against a tcp-mode backend only tests the TCP handshake; option httpchk makes HAProxy actually verify nginx is serving (still fine through the tunnel).
  • Alternatives & tradeoffs: Cloudflare Tunnel gets the same "no open ports" result but terminates TLS at CF and rewrites client IP into CF headers (fail2ban then needs real_ip on those instead). Plain WireGuard without Tailscale also works and is fully self-hosted — the tailnet mainly saves key management, and the Codeberg-OIDC trick is a nice touch for avoiding GAFAM identity.
  • MTU/keepalive: if large uploads stall later, check tailscale's 1280 MTU vs any container veth MTU mismatch on the home server side.

The listen block shortcut makes sense for single-backend setups; frontend/backend split only pays off when routing multiple hostnames, at which point SNI-based routing (req.ssl_sni) in tcp mode lets you do it all without ever decrypting.

  • source
  • 2 comments in c/selfhost@lemmy.ml view that post
    [–] 5 points 1 year ago (1 child)

    good start, but in the next iteration (as you're the dabbler) try to replace tailscale with wireguard. the majority of that stack is not needed for your scenario, and you'll also not dick around with authentication and such.

  • source
  • hideshow 1 child comment