Caddy jako reverse proxy dla Dockera: konfiguracja Compose z automatycznym HTTPS
Uruchom Caddy jako reverse proxy dla Dockera: jeden stos compose, wspólna sieć, reverse_proxy do nazw usług i automatyczny HTTPS — plus kiedy pomagają etykiety caddy-docker-proxy.
Krótko: uruchom Caddy we własnym kontenerze, który publikuje porty 80 i 443, podłącz go i kontenery aplikacji do jednej wspólnej sieci Dockera i skieruj `reverse_proxy` na nazwę każdej usługi i jej wewnętrzny port (na przykład `reverse_proxy app:3000`). Caddy rozwiązuje nazwę przez wbudowany DNS Dockera i automatycznie uzyskuje certyfikat TLS dla każdego adresu strony.
Ten poradnik najpierw pokazuje podejście ze zwykłym Caddyfile, potem wariant caddy-docker-proxy oparty na etykietach, i wyjaśnia, kiedy każdy z nich pasuje na pojedynczym VPS. Jeśli uruchamiasz Caddy bezpośrednio na hoście, a nie w Dockerze, zobacz podstawowy poradnik o reverse proxy w Caddy.
Jak elementy do siebie pasują
Tylko kontener Caddy publikuje porty na zewnątrz. Każdy kontener backendu dołącza do zdefiniowanej przez użytkownika sieci typu bridge (tutaj `web`) i udostępnia swój port wyłącznie w tej sieci. Wbudowany serwer DNS Dockera, dostępny w sieciach zdefiniowanych przez użytkownika, pozwala Caddy dotrzeć do `app:3000` po nazwie usługi lub kontenera, więc nigdy nie wpisujesz na sztywno adresów IP kontenerów, które zmieniają się przy każdym odtworzeniu.
Niepublikowanie portów backendów ma większe znaczenie, niż się wydaje: Docker zapisuje własne reguły iptables, więc port opublikowany przez `ports:` może być osiągalny z internetu, nawet gdy ufw twierdzi, że jest zablokowany. Dla wszystkiego, co ma stać za proxy, używaj `expose:` albo nie mapuj portów wcale.
| Komponent | Rola | Opublikowany na hoście? |
|---|---|---|
| Kontener caddy | Kończenie TLS, routing po nazwie hosta, przekierowanie HTTP na HTTPS | Tak: 80/tcp, 443/tcp, 443/udp |
| Sieć web | Wspólna sieć bridge z wbudowanym DNS dla nazw usług | Nie |
| Kontenery aplikacji | Twoje usługi (aplikacje webowe, API, dashboardy) | Nie, osiągalne tylko przez Caddy |
| Wolumen caddy_data | Certyfikaty, klucze prywatne, konto ACME | Nie, ale musi być trwały |
Krok po kroku: zwykły Caddyfile z docker compose
- 01.Przed uruchomieniem Caddy skieruj rekord A (i AAAA, jeśli używasz IPv6) każdej nazwy hosta na VPS, inaczej wystawienie certyfikatu się nie powiedzie.
- 02.Utwórz raz wspólną sieć: `docker network create web`.
- 03.Utwórz `/opt/proxy/compose.yaml` i `/opt/proxy/Caddyfile` jak poniżej, a następnie uruchom `docker compose up -d` w `/opt/proxy`.
- 04.Podłącz każdy stos aplikacji do zewnętrznej sieci `web` i uruchom go przez `docker compose up -d`.
- 05.Obserwuj wystawianie pierwszego certyfikatu przez `docker compose logs -f caddy` w `/opt/proxy`.
- 06.Po edycji Caddyfile przeładuj bez przestoju: `docker compose exec -w /etc/caddy caddy caddy reload`.
# /opt/proxy/compose.yaml
services:
caddy:
image: caddy:2
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data # certificates and ACME account keys
- caddy_config:/config
networks:
- web
volumes:
caddy_data:
caddy_config:
networks:
web:
external: truePodłącz aplikację i napisz Caddyfile
Każdy stos aplikacji deklaruje tę samą sieć zewnętrzną. Nazwa usługi staje się nazwą hosta, z którą łączy się Caddy. Wolumen `caddy_data` to ten, którego nie wolno Ci stracić: jego usunięcie zmusza Caddy do ponownego zamówienia wszystkich certyfikatów, co może skończyć się przekroczeniem limitów ACME.
# /opt/app/compose.yaml
services:
app:
image: ghcr.io/example/app:latest
restart: unless-stopped
expose:
- "3000" # reachable on the network, NOT published on the host
networks:
- web
networks:
web:
external: true
# /opt/proxy/Caddyfile
{
email [email protected]
}
app.example.com {
reverse_proxy app:3000
}
grafana.example.com {
reverse_proxy grafana:3000
}
api.example.com {
reverse_proxy api-1:8080 api-2:8080 {
lb_policy round_robin
health_uri /healthz
health_interval 10s
}
}Backendy w Caddy: upstreamy, load balancing i health checki
W terminologii Caddy backend to upstream dyrektywy `reverse_proxy`. W jednej dyrektywie możesz podać kilka upstreamów, wybrać `lb_policy`, np. `round_robin`, `least_conn` lub `ip_hash`, i dodać aktywne health checki przez `health_uri`, aby niedziałające kontenery wypadały z rotacji. Pasywne kontrole (`fail_duration`, `max_fails`) też się przydają, gdy aplikacja nie ma endpointu zdrowia.
Caddy domyślnie ustawia `X-Forwarded-For`, `X-Forwarded-Proto` i `X-Forwarded-Host` w przekazywanych żądaniach. Skonfiguruj aplikację tak, by ufała zakresowi sieci proxy — wtedy zobaczy prawdziwy IP klienta i będzie budować linki `https://`. WebSockety i gRPC działają przez `reverse_proxy` bez dodatkowych ustawień; dla gRPC bez szyfrowania użyj `reverse_proxy h2c://service:50051`.
Etykiety zamiast Caddyfile: caddy-docker-proxy
Osoby szukające „Caddy proxy manager” zwykle chcą tego, co oferuje Nginx Proxy Manager: dodajesz kontener i dostajesz nazwę hosta oraz certyfikat bez edycji centralnego pliku. Caddy nie ma oficjalnego GUI, ale społecznościowy projekt caddy-docker-proxy (github.com/lucaslorentz/caddy-docker-proxy) generuje Caddyfile z etykiet kontenerów i przeładowuje Caddy, gdy kontenery startują lub się zatrzymują.
Wymaga on dostępu do odczytu gniazda Dockera, co w praktyce oznacza uprawnienia roota na hoście. Montuj je tylko do odczytu, aktualizuj obraz proxy i wybierz zwykły Caddyfile, jeśli masz tylko kilka usług.
services:
caddy:
image: lucaslorentz/caddy-docker-proxy:ci-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- CADDY_INGRESS_NETWORKS=web
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- caddy_data:/data
networks:
- web
whoami:
image: traefik/whoami
networks:
- web
labels:
caddy: whoami.example.com
caddy.reverse_proxy: "{{upstreams 80}}"
volumes:
caddy_data:
networks:
web:
external: trueZwykły Caddyfile czy caddy-docker-proxy
| Zwykły Caddyfile | Etykiety caddy-docker-proxy | |
|---|---|---|
| Konfiguracja znajduje się w | Jednym pliku wersjonowanym w git | Etykietach rozsianych po plikach compose |
| Dostęp do gniazda Dockera | Niepotrzebny | Wymagany (wrażliwy pod kątem bezpieczeństwa) |
| Nowa usługa | Edytuj Caddyfile, uruchom `caddy reload` | Dodaj etykiety, uruchom kontener |
| Obraz | Oficjalny `caddy:2` | Obraz społecznościowy oparty na Caddy |
| Debugowanie | Czytasz plik bezpośrednio | Sprawdzasz wygenerowaną konfigurację w logach |
| Najlepszy dla | Małych, stabilnych konfiguracji VPS | Wielu krótkotrwałych lub często zmienianych usług |
Uruchomienie na VPS
Na VPS KVM w NoctisNode dostajesz pełny root i dedykowany IPv4, więc opublikowanie 80 i 443 z jednego kontenera Caddy i ukrycie całej reszty jest proste. Wisp (1 vCPU, 1 GB RAM) wystarczy dla Caddy i kilku lekkich kontenerów; cięższe stosy zmieszczą się na Pulse lub Umbra. Szczegóły wystawiania certyfikatów i typowe awarie opisuje jak działa automatyczny HTTPS w Caddy, a surowe przekierowanie TCP lub SSH — proxy TCP i SSH w Caddy. Zabezpiecz SSH hosta, korzystając z poradnika o hardeningu SSH.
FAQ
QJak skonfigurować Caddy jako reverse proxy do kontenera Dockera?
AUmieść Caddy i kontener w tej samej sieci Dockera zdefiniowanej przez użytkownika i użyj `reverse_proxy service-name:port` w Caddyfile. Nie używaj `localhost`, bo wewnątrz kontenera Caddy oznacza on sam Caddy.
QDlaczego Caddy zwraca 502 Bad Gateway dla mojego kontenera?
AZwykle kontenery nie są we wspólnej sieci, port jest zły (użyj wewnętrznego portu kontenera, a nie opublikowanego portu hosta) albo aplikacja nasłuchuje tylko na 127.0.0.1 wewnątrz swojego kontenera. Ustaw aplikację na 0.0.0.0 i sprawdź `docker network inspect web`.
QCzy caddy-docker-proxy jest bezpieczny?
ADziała dobrze, ale wymaga gniazda Dockera, które daje kontrolę nad hostem równoważną rootowi. Montuj je tylko do odczytu, aktualizuj obraz i nie wystawiaj endpointu administracyjnego Caddy.
QGdzie Caddy przechowuje certyfikaty w Dockerze?
AW `/data` wewnątrz oficjalnego obrazu, więc zamontuj tam nazwany wolumen. Jego utrata oznacza ponowne wystawienie wszystkich certyfikatów i możliwe przekroczenie limitów ACME.
QCzy istnieje Caddy proxy manager z interfejsem webowym?
ASam Caddy nie ma oficjalnego interfejsu webowego; konfiguruje się go przez Caddyfile, JSON lub API administracyjne. Narzędzia oparte na etykietach, takie jak caddy-docker-proxy, dają podobny przepływ pracy: dodajesz kontener i gotowe.