Cloudflare Tunnel + Zero Trust — homelab bez wystawiania portów
Mam 4 maszyny, kilkadziesiąt usług i zero portów otwartych do internetu. Cały dostęp leci przez Cloudflare Tunnel z autoryzacją Zero Trust. Pokazuję jak to ustawiłem i co warto wiedzieć.

Klasyczny homelab: VPN albo otwarty port 443 z reverse proxy. Ja nie chciałem żadnego z tych. Postawiłem Cloudflare Tunnel, tunel wychodzący z mojej sieci do CF, oni terminują TLS i autoryzują. Zero ekspozycji od strony WAN.
Architektura
[Internet]
↓ HTTPS
[Cloudflare CDN + Zero Trust auth]
↓ tunel (cloudflared)
[Mini PC 172.25.100.36]
↓ HTTP
[Lokalne usługi: Vikunja, Obsidian sync, blog, agent]Klient łączy się do app.kamilkaletka.dev, CF go autoryzuje (Google SSO + email allowlist), dopiero wtedy proxy do mojego serwisu. Mój router nie ma żadnych otwartych portów do internetu.
Setup w 4 krokach
1. Konto Cloudflare + domena. Domenę mam na CF od dawna. Free tier wystarczy.
2. Stwórz tunel.
cloudflared tunnel login
cloudflared tunnel create homelab
# zapisuje credentials.json3. Konfiguracja routingu.
# ~/.cloudflared/config.yml
tunnel: homelab
credentials-file: /home/kkaletka/.cloudflared/credentials.json
ingress:
- hostname: vikunja.kamilkaletka.dev
service: http://localhost:3456
- hostname: obsidian-sync.kamilkaletka.dev
service: http://localhost:5984
- hostname: betting.kamilkaletka.dev
service: http://172.25.100.49:3002
- service: http_status:4044. Uruchom jako systemd.
sudo cloudflared service install
sudo systemctl enable --now cloudflaredPo minucie subdomeny żyją.
Zero Trust — autoryzacja
To jest ten kluczowy element. Sam tunel daje publiczny URL. Zero Trust to dodatkowa warstwa.
W panelu CF Zero Trust:
- Application → Self-hosted
- Domain:
vikunja.kamilkaletka.dev - Identity Provider: Google (free integration)
- Policy:
email is in [[email protected]]
Każde wejście wymaga zalogowania Google, mail musi być na liście. Linki które wysyłam komuś, proszę go o dodanie maila do allowlisty.
Pułapka #1: forge IP
Mam serwisy na różnych maszynach. Mini PC = 172.25.100.36, Forge PC = 172.25.100.49. Reguła ingress dla forge'owych serwisów MUSI używać IP, nie localhost. Bo cloudflared żyje na mini PC.
# ŹLE
- hostname: betting.kamilkaletka.dev
service: http://localhost:3002 # localhost = mini PC
# DOBRZE
- hostname: betting.kamilkaletka.dev
service: http://172.25.100.49:3002Kosztowało mnie godzinę debugowania pierwszego dnia.
Pułapka #2: NO_PROXY i Docker
Mam SOCKS5 proxy w niektórych projektach. Bez NO_PROXY Docker próbuje resolve'ować zewnętrznie hostname'y wewnętrzne i się sypie.
export NO_PROXY="172.25.0.0/16,localhost,127.0.0.1,*.kamilkaletka.dev"Każdy nowy serwis wewnętrzny dopisuję tutaj.
Pułapka #3: Caddy reload
Często chcę zmienić konfigurację Caddy (między tunelem a kontenerem). docker exec caddy caddy reload NIE działa gdy Caddy jest bind-mountowany, bo sygnał reload czyta inode, a nie ścieżkę. Musi być pełny restart kontenera.
# DZIAŁA
docker restart caddy
# NIE DZIAŁA NIEKIEDY (bind mount)
docker exec caddy caddy reload --config /etc/caddy/CaddyfileCo zyskałem
1. Zero portów otwartych. Mój router ma WAN zamknięty. Atakujący nie może nawet zeskanować otwartych portów.
2. Wszędzie HTTPS gratis. CF terminuje TLS, mam darmowy cert dla każdej subdomeny.
3. Logi audit'owe. CF Zero Trust loguje każde wejście. Mogę zobaczyć z jakiego IP się logowałem rok temu.
4. WAF za free. Cloudflare automatycznie blokuje typowe ataki przed dotarciem do mojego serwera.
Czego brakuje
1. WebSocket przez tunel działa, ale latency jest +20-30ms względem bezpośredniego połączenia. Dla większości serwisów ok, dla real-time gier, nie.
2. Tunel jest single-point-of-failure. Jak cloudflared padnie, wszystkie serwisy znikną. Mam systemd unit z restart=always, działa, ale to wciąż jeden proces.
3. CF rate limity. Free tier ma limit 100k requestów dziennie na zone. Wystarcza, ale duży traffic spike mógłby być problemem.
Cloudflare Tunnel + Zero Trust to najlepszy stosunek bezpieczeństwa do wysiłku jaki znalazłem dla homelab'u. Kosztuje 0 PLN, daje TLS, autoryzację, WAF i zero portów otwartych. Jeśli jeszcze masz wystawione 443 do reverse proxy, przerzuć się.