A self-written reverse proxy and auth service for my home server.
  • Go 95.6%
  • Dockerfile 4.4%
Find a file Use this template
2026-09-29 21:02:59 +01:00
cmd/rb-proxy Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00
config Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00
internal Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00
.gitignore Initial commit 2026-09-28 20:31:38 +00:00
docker-compose.yml Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00
Dockerfile Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00
go.mod Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00
LICENSE Initial commit 2026-09-28 20:31:38 +00:00
README.md Reverse Proxy and config hot reloading 2026-09-29 21:02:59 +01:00

rb-proxy

A self-written reverse proxy and auth service for my home server.

All my projects run in separate Docker containers on a personal PC, exposed to the internet through a Cloudflare Tunnel. Instead of one tunnel rule per project, the tunnel sends every subdomain to this proxy. The proxy looks at the hostname and forwards the request to the right container. Private apps (like logs) are protected by access codes checked by a small auth service.

Cloudflare Tunnel
   ├── r-barroso.com    → portfolio (direct)
   └── *.r-barroso.com  → proxy → auth (if protected) → container

Routes are defined in proxy/routes.json:

{
  "logs.r-barroso.com": { "upstream": "http://logs:8080", "protected": true },
  "demo.r-barroso.com": { "upstream": "http://demo:3000", "protected": false }
}

Rules

  1. Requests are routed by hostname.
  2. r-barroso.com goes straight to the portfolio through cloudflared, so the portfolio stays up even if the proxy is down.
  3. Unknown hostnames return 404.
  4. Public routes are forwarded directly.
  5. Protected routes are forwarded only if the auth service says the request is allowed. Otherwise the user is redirected to auth.r-barroso.com/login.
  6. After a valid code is entered, the user is sent back to the page they originally asked for.
  7. Streaming responses (SSE, live logs) and WebSockets are passed through without buffering.
  8. Adding a project means adding one line to routes.json. No Cloudflare changes are needed.

Security rules

  • Access codes are stored as bcrypt hashes, never in plain text.
  • Each code has scopes, so a code shared with a friend only opens the apps it lists.
  • Each code has an expiry and a version. Bumping the version revokes every session created with it.
  • Login attempts are rate-limited per IP, using Cloudflare's CF-Connecting-IP header.
  • Session cookies are signed (HMAC-SHA256) and set with HttpOnly, Secure and SameSite=Lax.
  • The auth cookie is removed before forwarding, so apps never see it.
  • Redirects after login only go to *.r-barroso.com, to prevent open redirects.
  • The proxy fails closed: if the auth service is down, protected apps return an error instead of opening up.