Autonomiczny serwer domowy Docker-Compose z Traefik, SSL i Watchtower
Część 4 z 4 serii Homelab na Raspberry Pi

Spis treści
Przegląd architektury: Projekt autonomicznego serwera domowego na Raspberry Pi
Wdrożenie samodzielnie hostowanego laboratorium domowego na platformie Raspberry Pi wymaga zastosowania odpornej na awarie i bezobsługowej architektury orkiestracji. Udostępnianie wewnętrznych kontenerów Docker w sieci lokalnej lub publicznej bez centralnego terminowania ruchu SSL/TLS podnosi stopień skomplikowania administracji i rodzi poważne zagrożenia bezpieczeństwa. Ręczne odnawianie certyfikatów, statyczna konfiguracja serwerów proxy oraz manualne aktualizacje kontenerów nieuchronnie prowadzą do przerw w świadczeniu usług i wygasania certyfikatów kryptograficznych.
Autonomiczna architektura serwera domowego łączy trzy kluczowe technologie w ramach jednego deklaratywnego stosu Docker Compose: Traefik v3 działa jako dynamiczny router brzegowy, który monitoruje gniazdo systemu Docker i kieruje przychodzący ruch HTTP/HTTPS na podstawie etykiet kontenerów. Integracja z Let’s Encrypt ACME automatyzuje generowanie oraz odnawianie certyfikatów SSL za pomocą weryfikacji HTTP-01 lub DNS-01; natomiast Watchtower zapewnia automatyczne zarządzanie cyklem życia aplikacji poprzez regularne sprawdzanie rejestrów obrazów i bezkolizyjne aktualizowanie kontenerów bez interwencji manualnej.

Instrukcja wdrożenia krok po kroku
Krok 1: Przygotowanie systemu i architektura systemu plików
W celu zapewnienia trwałości danych oraz czystego podziału ról na hostującym urządzeniu Raspberry Pi, konieczne jest utworzenie standardowej struktury katalogów w ścieżce /opt/containers/:
mkdir -p /opt/containers/traefik/data
mkdir -p /opt/containers/watchtower
touch /opt/containers/traefik/data/acme.json
chmod 600 /opt/containers/traefik/data/acme.json
Krytyczna uwaga dotycząca bezpieczeństwa: Plik acme.json, w którym przechowywane są prywatne klucze kryptograficzne Let’s Encrypt, musi posiadać uprawnienia ograniczone rygorystycznie do wartości 600. Usługa Traefik odmówi uruchomienia, jeśli prawa odczytu i zapisu będą zbyt szerokie.
Krok 2: Projektowanie dynamicznego routera brzegowego Traefik v3
Infrastruktura routingu definiowana jest w pliku docker-compose.yml zlokalizowanym w katalogu /opt/containers/traefik/. Konfiguracja ta określa punkty wejściowe dla portu 80 (HTTP) z obowiązkowym przekierowaniem na port 443 (HTTPS), aktywuje automatyczną weryfikację Let’s Encrypt HTTP-01 oraz zamieszcza gniazdo uniksowe Dockera w trybie tylko do odczytu:
services:
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
networks:
- proxy
ports:
- "80:80"
- "443:443"
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=proxy"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=admin@lukaswojcik.com"
- "--certificatesresolvers.myresolver.acme.storage=/data/acme.json"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "/opt/containers/traefik/data:/data"
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`proxy.lukaswojcik.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=myresolver"
- "traefik.http.routers.dashboard.middlewares=dashboard-ip"
- "traefik.http.middlewares.dashboard-ip.ipallowlist.sourcerange=192.168.0.0/16, 10.0.0.0/8"
networks:
proxy:
external: true
Krok 3: Tworzenie zewnętrznej sieci Docker Proxy
Przed uruchomieniem stosu usług konieczne jest zainicjowanie izolowanej sieci mostkowej w systemie gospodarza, co pozwoli usłudze Traefik na bezpieczną komunikację z podrzędnymi kontenerami aplikacji:
docker network create proxy
Krok 4: Integracja narzędzia Watchtower w celu automatyzacji cyklu życia
Aby wyeliminować konieczność ręcznego kontrolowania i instalowania aktualizacji kontenerów, narzędzie Watchtower jest dodawane w charakterze autonomicznej usługi tła. Ponieważ pierwotne repozytorium containrrr/watchtower zostało zarchiwizowane 17 grudnia 2025 roku i nie otrzymuje już poprawek ani aktualizacji bezpieczeństwa, wykorzystywany jest tutaj aktywnie rozwijany fork nickfedor/watchtower, który zastępuje je bez zmian w konfiguracji. Skrypt sprawdza skonfigurowane rejestry co 24 godziny (86400 sekund), pobiera zaktualizowane obrazy zgodne z aktualnymi etykietami, w sposób kontrolowany wyłącza stare instancje kontenerów oraz automatycznie usuwa osierocone obrazy z dysku:
services:
watchtower:
image: nickfedor/watchtower:latest
container_name: watchtower
restart: unless-stopped
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_POLL_INTERVAL=86400
- WATCHTOWER_INCLUDE_RESTARTING=true
- WATCHTOWER_ROLLING_RESTART=true
Krok 5: Wdrożenie bezpiecznego mikroserwisu docelowego przez etykiety
W celu podłączenia dowolnej własnej aplikacji do routera brzegowego Traefik bez edytowania centralnych plików konfiguracyjnych proxy, dynamiczne etykiety routingu deklaruje się bezpośrednio w definicji kontenera docelowego:
services:
whoami:
image: traefik/whoami:latest
container_name: whoami
restart: unless-stopped
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.lukaswojcik.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=myresolver"
- "traefik.http.services.whoami.loadbalancer.server.port=80"
networks:
proxy:
external: true
Krok 6: Kontrola jakości i audyt systemu
Po uruchomieniu usług poleceniem docker compose up -d cała infrastruktura musi zostać systematycznie zweryfikowana:
- Weryfikacja wydawania certyfikatów: Sprawdzenie logów kontenera poleceniem
docker logs -f traefikw celu potwierdzenia pomyślnego ukończenia weryfikacji Let’s Encrypt ACME oraz upewnienie się, że plikacme.jsonzawiera poprawne certyfikaty RSA/ECDSA. - Audyt automatycznych przekierowań: Wykonanie zapytania cURL przez czyste HTTP (
curl -I http://whoami.lukaswojcik.com) w celu potwierdzenia natychmiastowego zwrotu nagłówka308 Permanent Redirectlub301 Moved Permanentlykierującego na HTTPS. - Symulacja wyzwolenia aktualizacji: Wykonanie jednorazowego, nieingerującego przebiegu narzędzia Watchtower poleceniem
docker exec -it watchtower /watchtower --run-once --monitor-onlyw celu weryfikacji poprawności uprawnień dostępu do gniazda Dockera. Flaga--no-pullnie nadaje się do tego celu: blokuje jedynie pobieranie obrazów z rejestru, natomiast nowszy obraz obecny już lokalnie nadal prowadzi do zatrzymania i odtworzenia kontenera.
Podsumowanie i mierzalna wartość dodana
Co da się osiągnąć dzięki instrukcji: Całkowite zastąpienie ręcznej konfiguracji routingu proxy, awaryjnych skryptów odnawiających certyfikaty SSL oraz manualnych aktualizacji kontenerów przez autonomiczną, deklaratywną infrastrukturę Docker Compose opartą na rozwiązaniach Traefik v3 i Watchtower.
Resultujący wartość dodana:
- Bezobsługowe utrzymanie SSL/TLS: Certyfikaty kryptograficzne są automatycznie wnioskowane, wdrażane i odnawiane przez Let’s Encrypt, zapobiegając ostrzeżeniom przeglądarek i przerwom w dostępności usług.
- Dynamiczne wykrywanie serwisów: Nowe aplikacje na serwerze domowym są natychmiast kierowane i szyfrowane poprzez dodanie etykiet Docker, co eliminuje konieczność edycji plików Nginx/Apache oraz przeładowywania serwera.
- Ciągłe, automatyczne łatanie luk: Poprawki bezpieczeństwa oraz aktualizacje aplikacji są wdrażane automatycznie w ciągu 24 godzin od publikacji w rejestrach nadrzędnych, skutecznie zabezpieczając Raspberry Pi przed znanymi podatnościami. Gwarancja ta obowiązuje jedynie tak długo, jak samo narzędzie aktualizujące jest rozwijane; dlatego miejsce zarchiwizowanego oryginału zajmuje aktywnie utrzymywany fork
nickfedor/watchtower.
Pytania i odpowiedzi
Czy :ro przy gnieździe Dockera sprawia, że dostęp Traefika jest nieszkodliwy?
Nie. :ro uniemożliwia jedynie modyfikację samego pliku gniazda przez kontener. Przez gniazdo Traefik rozmawia jednak z API Dockera, a ono nie rozróżnia wywołań odczytujących i zapisujących tylko dlatego, że plik zamontowano w trybie tylko do odczytu. Kto uzyska dostęp do gniazda, może przez nie uruchamiać kontenery, także takie z zamontowanym katalogiem głównym hosta, i tym samym ma w praktyce uprawnienia roota na Raspberry Pi.
Ryzyko leży więc w powierzchni ataku Traefika: to jedyna usługa, która przyjmuje połączenia bezpośrednio z internetu. Luka w Traefiku nie skończyłaby się na kontenerze. Watchtower i tak potrzebuje gniazda z prawem zapisu, żeby podmieniać kontenery, ale nie przyjmuje połączeń z zewnątrz.
Zaradzić temu może proxy gniazda: mały kontener, który trzyma gniazdo i przekazuje dalej tylko te odczytujące punkty końcowe API, których Traefik potrzebuje do wykrywania kontenerów. Traefik dostaje wtedy zamiast gniazda adres sieciowy tego proxy, a dostawcę Docker da się na niego skierować parametrem endpoint.
Jakie aktualizacje instaluje Watchtower i jak uniknąć skoków do nowej wersji głównej?
Watchtower podąża za tagiem, z którym obraz jest wpisany, a nie za numerem wersji. Kontener na latest dostaje więc także skok do nowej wersji głównej, gdy tylko zostanie ona opublikowana pod latest, razem ze zmienioną konfiguracją czy formatem danych. Drogi powrotnej nie przewidziano: po sprzątaniu z WATCHTOWER_CLEANUP=true starego obrazu nie ma już nawet na dysku.
Konfiguracja w artykule pokazuje już środek zaradczy: Traefik stoi na traefik:v3.1 i dostaje tylko nowe obrazy pod tym tagiem, czyli poprawki w obrębie 3.1, ale żadnego skoku do innej wersji. Warto tak samo postąpić z każdą usługą przechowującą własne dane, na przykład z bazą danych. Przy usługach na latest, w artykule whoami i samym Watchtowerze, ryzyko jest mniejsze, bo nie przechowują one danych.
Czy panel Traefika pod adresem proxy.lukaswojcik.com jest chroniony?
Tak, w obrębie sieci domowej: router panelu ma oprócz TLS middleware dashboard-ip, listę dozwolonych adresów IP (ipAllowList), która przepuszcza tylko adresy z 192.168.0.0/16 i 10.0.0.0/8. Bez niej każdy, kto zna nazwę hosta, widziałby wszystkie routery, usługi i nazwy hostów serwera domowego. Jeśli panel ma być osiągalny także spoza domu, dochodzi middleware Basic Auth.
Czy weryfikacja HTTP-01 działa na każdym łączu domowym?
Tylko wtedy, gdy Let’s Encrypt może połączyć się z Raspberry Pi z internetu na porcie 80: nazwa hosta musi publicznie wskazywać na łącze, a router musi przekierowywać port 80 na Raspberry Pi. Na łączach bez własnego publicznego adresu IPv4, na przykład za carrier-grade NAT albo DS-Lite, przez IPv4 to się nie uda; zadziała wtedy tylko, jeśli nazwa hosta ma rekord AAAA, a sam Raspberry Pi jest osiągalny przez IPv6. To samo ograniczenie dotyczy usług, które mają być dostępne wyłącznie w sieci domowej.
Na takie przypadki przewidziana jest wymieniona w artykule weryfikacja DNS-01. Potwierdza ona kontrolę nad domeną rekordem TXT w DNS, nie potrzebuje otwartego portu i pozwala też na certyfikaty wieloznaczne (wildcard). W zamian Traefik potrzebuje danych dostępowych do API dostawcy DNS, a te dane wymagają wtedy takiej samej ochrony jak plik acme.json.
Homelab na Raspberry Pi
- Raspberry Pi 4 i 5: uruchamianie systemu z dysku SSD przez zmianę bootloadera
- Zasilanie awaryjne (UPS) dla Raspberry Pi 4 i 5: Top 5 urządzeń do wymagających projektów
- Lokalny CI/CD dla Raspberry Pi: Automatyzacja wdrożeń Docker Compose
- Autonomiczny serwer domowy Docker-Compose z Traefik, SSL i Watchtower