Jak działa reverse proxy: Nginx i Traefik w konfiguracji dla aplikacji self hosted

0
39
Rate this post

Nawigacja:

Reverse proxy w świecie self hosted – po co to wszystko?

Czym jest reverse proxy w praktyce domowego serwera

Reverse proxy to serwer pośredniczący, który stoi przed Twoimi aplikacjami self hosted i przyjmuje ruch z Internetu (lub z sieci lokalnej), a następnie przekazuje go dalej do właściwego backendu – kontenera, usługi, aplikacji na innym porcie. Dla klienta (przeglądarki, aplikacji mobilnej, innego serwera) reverse proxy wygląda jak docelowy serwer, ale w środku to tylko „dyspozytor” kierujący żądania w odpowiednie miejsca.

W środowisku self hosted typowy scenariusz wygląda tak: na jednym serwerze (lub VPS, czy nawet Raspberry Pi) działa jednocześnie wiele usług – np. Nextcloud, Jellyfin, Gitea, Home Assistant, panel do routera, kilka mniejszych mikroserwisów. Każda nasłuchuje na innym porcie, często tylko na localhost lub w sieci Docker. Reverse proxy umożliwia:

  • udostępnienie wszystkich tych usług pod jednym adresem IP,
  • rozróżnienie ich po domenie lub ścieżce URL (np. cloud.mojadomena.pl, git.mojadomena.pl),
  • terminowanie TLS – czyli obsługę HTTPS i certyfikatów w jednym miejscu,
  • wprowadzenie centralnych zasad bezpieczeństwa, logowania i kompresji.

Bez reverse proxy każda usługa wymagałaby osobnego portu wystawionego na świat, osobnego zarządzania certyfikatami i trudnego do zapamiętania adresu. Reverse proxy porządkuje ten chaos i działa jak brama do całej infrastruktury self hosted.

Reverse proxy a klasyczny serwer HTTP

Klasyczny serwer HTTP (np. Apache w trybie statycznym) często jest bezpośrednim gospodarzem plików i aplikacji. Reverse proxy zwykle nie przechowuje logiki aplikacyjnej – tylko pośredniczy. Jego rola to:

  • parsowanie nagłówków HTTP,
  • wybór backendu na podstawie hosta, ścieżki lub innych kryteriów,
  • przepisywanie nagłówków (np. X-Forwarded-For, X-Forwarded-Proto),
  • buforowanie odpowiedzi (w niektórych konfiguracjach),
  • opcjonalna kompresja gzip/brotli.

Nginx i Traefik mogą być jednocześnie reverse proxy oraz serwerem statycznych plików (np. plików frontendu SPA), ale w świecie self hosted pełnią głównie rolę bramy do wielu usług, często działających w kontenerach Docker lub w klastrach Kubernetes.

Najczęstsze zastosowania reverse proxy w self hostingu

W domowych lub małych serwerowniach najbardziej typowe scenariusze użycia reverse proxy to:

  • Wystawianie wielu aplikacji za jednym adresem IP – np. VPS z jednym publicznym adresem, za którym działają dziesiątki usług.
  • Ukrywanie portów i topologii sieci – świat widzi tylko port 80/443, a wewnątrz można dowolnie zmieniać porty i hosty backendów.
  • Centralne HTTPS – jeden mechanizm Let’s Encrypt / certbot / ACME, zamiast instalowania certyfikatów w każdej aplikacji.
  • Autoryzacja przed aplikacjami – reverse proxy może chronić serwisy za pomocą SSO, Basic Auth, OAuth2 Proxy itp.
  • Segmentacja dostępu – różne usługi dostępne tylko z LAN, inne z Internetu, niektóre tylko z VPN.

W praktyce reverse proxy staje się centralnym elementem infrastruktury – od jego konfiguracji zależy, czy dostęp do usług jest wygodny, bezpieczny i łatwy w utrzymaniu.

Jak działa reverse proxy od środka – przepływ żądania

Ścieżka żądania HTTP krok po kroku

Dobrze zrozumieć, co się dzieje z momentem wpisania https://cloud.mojadomena.pl do przeglądarki, aż do odpowiedzi z Twojego Nextclouda:

  1. Rozwiązanie DNS – domena cloud.mojadomena.pl wskazuje publiczny adres IP Twojego serwera.
  2. Połączenie TCP/TLS – przeglądarka łączy się z portem 443; reverse proxy (Nginx lub Traefik) przyjmuje połączenie i wykonuje handshake TLS.
  3. Odczyt nagłówków HTTP – reverse proxy analizuje nagłówek Host, metodę, ścieżkę URL i inne parametry.
  4. Dobór reguły routingu – na podstawie konfiguracji wybierany jest odpowiedni upstream / backend (np. kontener nextcloud na porcie 8080).
  5. Tworzenie połączenia z backendem – reverse proxy otwiera (lub wykorzystuje istniejące) połączenie do usługi backendowej w sieci lokalnej lub Docker.
  6. Przekazanie żądania – żądanie jest wysyłane do backendu, często z modyfikacją nagłówków (np. X-Forwarded-For z IP klienta).
  7. Odpowiedź backendu – aplikacja odsyła odpowiedź HTTP do reverse proxy.
  8. Opcjonalna obróbka – reverse proxy może wykonać kompresję, dodać nagłówki bezpieczeństwa, zbuforować odpowiedź.
  9. Zwrot odpowiedzi klientowi – użytkownik widzi stronę, nawet nie wiedząc, że po drodze działało kilka warstw.

Ten mechanizm jest podobny w Nginxie i Traefiku, choć sposób opisywania reguł i konfiguracji różni się dość znacząco.

Routing po domenie i ścieżce

Najprostszy i najczęściej używany sposób routingu w reverse proxy to rozróżnianie żądań po:

  • domenie (vhost) – np. cloud.mojadomena.pl, media.mojadomena.pl, git.mojadomena.pl,
  • ścieżce URL – np. mojadomena.pl/cloud, mojadomena.pl/git, mojadomena.pl/monitoring.

Routing po domenie jest czytelniejszy i rzadziej sprawia problemy z aplikacjami, które generują absolutne linki. Routing po ścieżce bywa praktyczny przy jednej domenie i wielu prostych usługach, ale wymaga starannego przepisywania ścieżek (zwłaszcza dla frontendów SPA i aplikacji, które oczekują, że działają w /).

Reverse proxy może też brać pod uwagę inne parametry – nagłówki, metodę HTTP, adres IP klienta – ale w self hostingu to scenariusz bardziej niszowy, zwykle zarezerwowany dla zaawansowanych instalacji.

Terminowanie TLS i nagłówki X-Forwarded-*

Gdy reverse proxy przyjmuje połączenie HTTPS, mają miejsce dwa istotne mechanizmy:

  1. Terminowanie TLS – szyfrowanie kończy się na reverse proxy. To tutaj są klucze prywatne i certyfikaty, a dalej do backendu żądania zwykle lecą już „czystym” HTTP w sieci lokalnej (czasem również HTTPS, ale wewnątrz).
  2. Nagłówki przekazujące kontekst – reverse proxy dodaje nagłówki typu:
    • X-Forwarded-For – oryginalny adres IP klienta,
    • X-Forwarded-Proto – protokół użyty przez klienta (http lub https),
    • X-Real-IP – też często IP klienta (popularne w Nginx + PHP-FPM).
Sprawdź też ten artykuł:  Serwer NAS na Open Source – budowa krok po kroku

Aplikacje działające za reverse proxy zwykle potrafią korzystać z tych nagłówków, aby poprawnie rozpoznawać adres klienta oraz generować linki https:// zamiast http://. W konfiguracjach self hosted kluczowe jest włączenie opcji „siedzę za reverse proxy” w samych aplikacjach (np. w Nextcloud, Gitea, Grafana), aby nie myliły się co do adresu zewnętrznego.

Komputer między szafami serwerowymi w nowoczesnym centrum danych
Źródło: Pexels | Autor: Brett Sayles

Nginx jako reverse proxy – fundamenty konfiguracji

Podstawowa struktura konfiguracji Nginx

Nginx ma konfigurację opartą na blokach: główny blok http, w nim bloki server (wirtualne hosty), a w nich bloki location (dopasowanie ścieżek). Minimalny przykład prostego reverse proxy dla jednej aplikacji wygląda tak:

http {
    upstream nextcloud_backend {
        server 127.0.0.1:8080;
    }

    server {
        listen 80;
        server_name cloud.mojadomena.pl;

        location / {
            proxy_pass http://nextcloud_backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Blok upstream definiuje backend (pojedynczy serwer lub pulę serwerów). Blok server opisuje, pod jaką domeną i portem dostępna jest usługa. W location / odbywa się kluczowe proxy_pass i ustawianie nagłówków dla aplikacji.

Konfiguracja virtual hostów i proxy_pass

Dla wielu usług self hosted typowe jest stworzenie osobnego pliku konfiguracji Nginx dla każdej domeny, np. w katalogu /etc/nginx/sites-available/. Przykładowo:

server {
    listen 80;
    server_name git.mojadomena.pl;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Jeśli aplikacja działa w Dockerze i nasłuchuje na porcie kontenera (np. gitea:3000 w sieci dockerowej), można użyć nazwy hosta kontenera jako backendu, jeśli Nginx jest w tej samej sieci Docker:

upstream gitea_backend {
    server gitea:3000;
}

W takim scenariuszu Nginx też działa w kontenerze podpiętym do tej samej sieci. W praktyce w świecie self hosted są dwa popularne podejścia: Nginx na hoście + aplikacje w Docker (proxy na host: 127.0.0.1:PORT) lub Nginx w Docker, a wszystko połączone przez sieci Docker.

Przekazywanie nagłówków i poprawne adresy klienta

Bez poprawnie ustawionych nagłówków aplikacja backendowa będzie widzieć IP reverse proxy zamiast IP użytkownika, a także nie będzie wiedzieć, że zewnętrznie używany jest HTTPS. Standardowy zestaw dyrektyw w Nginx to:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

W konfiguracjach bardziej zaawansowanych dołącza się też nagłówki X-Forwarded-Host, X-Forwarded-Port, albo wykorzystuje gotowy blok include proxy_params; dostępny w wielu dystrybucjach, który zawiera sensowny zestaw domyślny. W self hostingu wygodnie jest stworzyć własny plik proxy_common.conf i dołączać go w wielu vhostach, aby nie powielać konfiguracji.

Nginx i HTTPS dla self hosted – Let’s Encrypt i bezpieczeństwo

Integracja Nginx z Let’s Encrypt (certbot, acme.sh)

Najczęstszy sposób na uzyskanie certyfikatów HTTPS dla usług self hosted to Let’s Encrypt. Z Nginx można go zintegrować na kilka sposobów:

  • certbot + wtyczka nginx – automatyczna edycja konfiguracji Nginx przez certbota, prostsza dla początkujących, ale mniej przewidywalna przy złożonych setupach.
  • certbot + tryb webroot – ręczna konfiguracja lokalizacji /.well-known/acme-challenge/, certbot tylko zapisuje pliki i odnawia certyfikaty.
  • acme.sh lub inne skrypty ACME – elastyczne narzędzia, często wygodniejsze przy DNS-01, wildcardach i bardziej zaawansowanych scenariuszach.

Przykład prostego vhosta z HTTP, który służy do walidacji HTTP-01 i przekierowuje ruch na HTTPS:

server {
    listen 80;
    server_name cloud.mojadomena.pl;

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

Po wydaniu certyfikatu powstaje dodatkowy blok server nasłuchujący na 443 z dyrektywą ssl_certificate i konfiguracją backendu. Odnawianie certyfikatów można zautomatyzować w cronie lub systemd timers, co jest szczególnie ważne przy wielu usługach i domenach.

Konfiguracja serwera HTTPS w Nginx

Typowy, uproszczony blok HTTPS w Nginx wygląda tak:

server {
    listen 443 ssl http2;
    server_name cloud.mojadomena.pl;

    ssl_certificate /etc/letsencrypt/live/cloud.mojadomena.pl/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/cloud.mojadomena.pl/privkey.pem;

    # opcjonalne, mocniejsze ustawienia TLS
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://127.0.0.1:8080;
        include /etc/nginx/proxy_common.conf;
    }
}

W konfiguracji dla wielu usług część parametrów TLS lepiej wynieść do bloku http lub do osobnego pliku ssl_params.conf włączanego w każdym serwerze.

Reverse proxy a cache, kompresja i limity

Reverse proxy może nie tylko przekazywać żądania dalej, ale też optymalizować ruch. W Nginx często łączy się kilka mechanizmów:

  • cache odpowiedzi HTTP (statyczne pliki, zasoby API z krótkim TTL),
  • kompresję gzip/brotli dla zasobów tekstowych,
  • limity rozmiaru żądania (np. uploadów) i limity szybkości (rate limiting).

Przy typowym self hostingu wystarczy prosty cache na statyczne pliki i rozsądny limit uploadu, np. dla Nextclouda:

http {
    # katalog na cache
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=static_cache:10m
                     inactive=60m use_temp_path=off;

    server {
        listen 443 ssl http2;
        server_name cloud.mojadomena.pl;

        # ...

        # cache tylko na statyczne pliki
        location ~* .(css|js|png|jpg|jpeg|gif|svg|ico|webp|avif)$ {
            proxy_pass http://127.0.0.1:8080;
            proxy_cache static_cache;
            proxy_cache_valid 200 301 302 60m;
            add_header X-Cache-Status $upstream_cache_status;
            include /etc/nginx/proxy_common.conf;
        }

        # cała reszta bez cache
        location / {
            proxy_pass http://127.0.0.1:8080;
            include /etc/nginx/proxy_common.conf;
        }

        # limit rozmiaru uploadu
        client_max_body_size 2G;
    }
}

Do tego można dołożyć globalną kompresję:

http {
    gzip on;
    gzip_types text/css application/javascript application/json application/xml;
    gzip_min_length 1024;
    gzip_vary on;
}

Obsługa WebSocketów i HTTP/2 w Nginx

Coraz więcej usług self hosted korzysta z WebSocketów (np. interfejsy webowe, narzędzia do streamingu logów, panele administracyjne). Reverse proxy musi poprawnie przekazać upgrade połączenia:

location /ws/ {
    proxy_pass http://127.0.0.1:9000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    include /etc/nginx/proxy_common.conf;
}

Dla HTTP/2 wystarczy dopisać http2 w dyrektywie listen, co już było użyte w przykładach HTTPS. Backend nadal może działać na zwykłym HTTP/1.1 – to reverse proxy realizuje terminowanie HTTP/2.

Reverse proxy jako punkt centralnego logowania

Ponieważ cały ruch przechodzi przez reverse proxy, to ono jest naturalnym miejscem na logi dostępu i błędów. W Nginx można stworzyć wspólny format logów dla wszystkich vhostów:

http {
    log_format main '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '"$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    server {
        # ...
    }
}

Przy wielu usługach przydaje się oddzielny log per domena:

server {
    listen 443 ssl http2;
    server_name git.mojadomena.pl;

    access_log /var/log/nginx/git_access.log main;
    error_log  /var/log/nginx/git_error.log warn;

    # ...
}

Dzięki temu łatwiej przejrzeć, kto logował się do konkretnego serwisu, bez mieszania wpisów z innych usług.

Korytarz nowoczesnego data center z rzędami serwerów
Źródło: Pexels | Autor: Brett Sayles

Traefik jako reverse proxy w środowiskach kontenerowych

Filozofia Traefika w porównaniu z Nginx

Nginx opiera się głównie na statycznych plikach konfiguracyjnych. Traefik został zaprojektowany z myślą o środowisku dynamicznym – Docker, Kubernetes, usługi powstające i znikające automatycznie. Zamiast edytować pliki i przeładowywać proces, Traefik:

  • nasłuchuje na API Dockera / Kubernetesa,
  • odkrywa kontenery na podstawie etykiet (labels),
  • sam generuje routing i reguły,
  • automatycznie wystawia i odnawia certyfikaty Let’s Encrypt.

W praktyce oznacza to mniejszą liczbę ręcznie tworzonych plików i większy porządek przy dużej liczbie kontenerów. Z drugiej strony konfiguracja Traefika bywa mniej intuicyjna dla osób przyzwyczajonych do klasycznych vhostów.

Podstawowa architektura Traefika: entrypoints, routers, services, middlewares

Traefik dzieli konfigurację reverse proxy na kilka pojęć:

  • entrypoints – porty/wejścia (np. :80, :443),
  • routers – reguły dopasowania żądań (domena, ścieżka, metoda HTTP),
  • services – backendy (adresy kontenerów / serwerów),
  • middlewares – filtry po drodze (redirect, auth, nagłówki bezpieczeństwa, strippath itd.).

W konfiguracji statycznej definiuje się entrypointy i integrację z ACME, a reszta może być tworzona dynamicznie z etykiet Dockera.

Przykładowa konfiguracja Traefika w docker-compose

Przy self hostingu Traefik najczęściej uruchamia się jako kontener reverse-proxy w sieci współdzielonej z innymi usługami. Minimalny przykład:

version: "3.8"

services:
  traefik:
    image: traefik:v3.0
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.le.acme.httpchallenge=true"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.le.acme.email=admin@mojadomena.pl"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./letsencrypt:/letsencrypt"
    networks:
      - proxy

  gitea:
    image: gitea/gitea:latest
    networks:
      - proxy
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gitea.rule=Host(`git.mojadomena.pl`)"
      - "traefik.http.routers.gitea.entrypoints=websecure"
      - "traefik.http.routers.gitea.tls.certresolver=le"
      - "traefik.http.services.gitea.loadbalancer.server.port=3000"

networks:
  proxy:
    external: false

Traefik automatycznie zauważy kontener gitea i wystawi go pod wskazaną domeną z HTTPS. Nie ma tu osobnych plików konfiguracyjnych per domena – wszystko definiują etykiety.

Sprawdź też ten artykuł:  Czym różni się Free Software od Open Source?

Dynamiczne routowanie po domenie i ścieżce w Traefiku

Reguły routerów Traefika wykorzystują prosty język wyrażeń. Kilka typowych przykładów:

  • Host(`cloud.mojadomena.pl`) – dopasowanie po domenie,
  • PathPrefix(`/grafana`) – dopasowanie po prefiksie ścieżki,
  • Host(`monitor.mojadomena.pl`) && PathPrefix(`/api`) – połączenie warunków.

Jeśli kilka usług ma działać na jednej domenie pod różnymi ścieżkami, można skonfigurować różne routery wskazujące na inne backendy. Przykład z Grafaną i Prometheusem pod wspólną domeną:

labels:
  - "traefik.enable=true"

  # Grafana pod /grafana
  - "traefik.http.routers.grafana.rule=Host(`monitor.mojadomena.pl`) && PathPrefix(`/grafana`)"
  - "traefik.http.routers.grafana.entrypoints=websecure"
  - "traefik.http.routers.grafana.tls.certresolver=le"
  - "traefik.http.services.grafana.loadbalancer.server.port=3000"
  - "traefik.http.middlewares.grafana-stripprefix.stripprefix.prefixes=/grafana"
  - "traefik.http.routers.grafana.middlewares=grafana-stripprefix"

  # Prometheus pod /prometheus
  - "traefik.http.routers.prom.rule=Host(`monitor.mojadomena.pl`) && PathPrefix(`/prometheus`)"
  - "traefik.http.routers.prom.entrypoints=websecure"
  - "traefik.http.routers.prom.tls.certresolver=le"
  - "traefik.http.services.prom.loadbalancer.server.port=9090"
  - "traefik.http.middlewares.prom-stripprefix.stripprefix.prefixes=/prometheus"
  - "traefik.http.routers.prom.middlewares=prom-stripprefix"

Middleware StripPrefix usuwa fragment ścieżki, dzięki czemu backend uważa, że działa w /, choć z perspektywy użytkownika widoczny jest np. /grafana.

Traefik i automatyczne certyfikaty Let’s Encrypt

Traefik ma wbudowaną obsługę ACME, więc nie trzeba uruchamiać osobnego certbota. Po skonfigurowaniu certificatesresolvers wystarczy dodać do routera:

traefik.http.routers.cloud.entrypoints=websecure
traefik.http.routers.cloud.tls.certresolver=le

oraz odpowiednią regułę Host(). Traefik sam:

  • wystawi challenge HTTP-01 na porcie 80 (entrypoint web),
  • uzyska certyfikat,
  • zapisze go w pliku acme.json,
  • odnowi certyfikat przed wygaśnięciem.

Przy wielu domenach nie trzeba dopisywać nowych wpisów w cronie ani odświeżać serwera – routery z nowymi regułami po prostu pojawiają się po uruchomieniu kontenerów.

Traefik jako reverse proxy dla usług spoza Dockera

Choć Traefik kojarzy się z Dockerem, potrafi także proxować usługi działające „na hoście” lub na innych serwerach. Służy do tego tzw. file provider (dodatkowy plik YAML/TOML) albo provider http. Przykład prostego pliku dynamicznego dynamic.yml dla usługi na 127.0.0.1:8080:

http:
  routers:
    cloud:
      rule: "Host(`cloud.mojadomena.pl`)"
      entryPoints:
        - websecure
      tls:
        certResolver: le
      service: cloud_svc

  services:
    cloud_svc:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8080"

W części statycznej Traefika wystarczy włączyć tego providera:

--providers.file.filename=/etc/traefik/dynamic.yml

Takie połączenie przydaje się, gdy na jednym serwerze współistnieją aplikacje dockerowe i kilka „gołych” usług, np. stary panel WWW albo serwer mediów bez Dockera.

Nagłówki X-Forwarded-* i adres klienta w Traefiku

Traefik automatycznie ustawia standardowe nagłówki X-Forwarded-* dla backendów:

  • X-Forwarded-For – adres klienta,
  • X-Forwarded-Proto – protokół zewnętrzny,
  • X-Forwarded-Host – domena, pod którą przyszło żądanie.

Jeśli aplikacja dodatkowo chroni się przed spoofingiem nagłówków, czasem trzeba wskazać reverse proxy jako zaufane (np. w konfiguracji Symfony, Django, Nextclouda). Sytuacja jest analogiczna jak przy Nginx – różni się tylko to, że tu nie ma ręcznego konfigurowania proxy_set_header.

Bezpieczeństwo: nagłówki HSTS, redirect HTTP→HTTPS, rate limiting

Nginx i Traefik mogą wymusić korzystanie z HTTPS i dodać nagłówki bezpieczeństwa. W Nginx typowy blok dla przekierowania HTTP:

server {
    listen 80;
    server_name cloud.mojadomena.pl;
    return 301 https://$host$request_uri;
}

Dla HSTS w Nginx:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

W Traefiku takie nagłówki ustawia się jako middleware:

labels:
  - "traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000"
  - "traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true"
  - "traefik.http.routers.cloud.middlewares=secure-headers"

Jeśli usługa jest intensywnie atakowana (np. panel logowania), można dołożyć limitowanie żądań – w Nginx przez limit_req_zone, w Traefiku przez middleware rateLimit. Umiarkowane limity wystarczą, by odciążyć backend przy prostych atakach brute force.

Gdzie Nginx, gdzie Traefik – praktyczne scenariusze self hosted

Prosty serwer VPS z kilkoma usługami

Przy klasycznym scenariuszu: jeden VPS, kilka usług (Nextcloud, Gitea, Photoprism, Grafana) i głównie ruch HTTP(S), Nginx wciąż jest wygodnym wyborem:

  • konfiguracja czytelna w plikach,
  • łatwe przeniesienie na inny serwer (skopiowanie /etc/nginx),
  • dobra dokumentacja aplikacji pod Nginx (często gotowe snippet-y).

Jeśli część usług jest w Dockerze, a część na hoście, Nginx może działać na hoście i proxować do portów Dockera (127.0.0.1:PORT) i usług lokalnych. To najprostsza architektura dla osoby, która chce mieć pełną kontrolę nad każdym vhostem.

Większa instalacja z wieloma kontenerami i automatyzacją

Środowisko z orkiestracją (Docker Swarm, Kubernetes, Nomad)

Przy wielu hostach i klastrze kontenerów role Nginxa i Traefika rozjeżdżają się mocniej. Nginx zwykle pełni wtedy funkcję klasycznego reverse proxy / ingressu, konfigurowanego z zewnątrz (pliki, ConfigMapy), natomiast Traefik staje się elementem bardziej „świadomym” platformy – czyta metadane z API Dockera, Swarma czy Kubernetesa i sam buduje konfigurację.

Przykładowy układ przy Swarmie:

  • Traefik działa jako stack reverse-proxy w trybie globalnym (po jednym tasku na nodzie),
  • poszczególne usługi definiowane są jako kolejne stacki z labelkami Traefika,
  • certyfikaty Let’s Encrypt są wspólne dla całego klastra (współdzielony wolumen z acme.json).

W Kubernetesie Traefik występuje jako Ingress Controller. Zamiast etykiet Dockera używa się CRD Traefika (IngressRoute, Middleware, TraefikService), a routery powstają na podstawie obiektów w klastrze. To rozwiązanie pasuje do bardziej rozrośniętych instalacji, gdzie kolejne aplikacje są wdrażane przez CI/CD, a nie ręcznie na jednym VPS-ie.

Nginx także ma swoje wersje „kubernetesowe” (Nginx Ingress Controller) i dobrze sprawdza się w klastrach. Różnica polega na poziomie „magii”: Nginx zwykle wymaga bardziej jawnej konfiguracji (Ingress, ConfigMapy), Traefik mocniej polega na dynamicznych providerach i etykietach.

Hybrid: Nginx jako frontend, Traefik jako router usług

Ciekawy scenariusz to połączenie obu narzędzi. Na brzegu stoi Nginx, który:

  • nasłuchuje na 80/443,
  • robi wstępny TLS (np. z certyfikatem wildcard),
  • dodaje spójne nagłówki bezpieczeństwa i polityki (Content-Security-Policy, Referrer-Policy, Permissions-Policy),
  • terminuje ruch do jednego lub kilku Traefików, pracujących w sieciach Dockera.

Nginx ma wtedy kilka prostych bloków:

server {
    listen 443 ssl http2;
    server_name *.mojadomena.pl;

    ssl_certificate     /etc/ssl/wildcard.crt;
    ssl_certificate_key /etc/ssl/wildcard.key;

    # Nagłówki bezpieczeństwa wspólne dla wszystkich subdomen
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin";
    add_header X-Content-Type-Options "nosniff";

    location / {
        proxy_pass http://127.0.0.1:8080; # Traefik
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Traefik działa wtedy wyłącznie jako router „wewnętrzny”, nie musi wystawiać 80/443 na zewnątrz, a do zarządzania certyfikatami można użyć klasycznego ACME po stronie Nginxa lub ręcznie utrzymywanego certyfikatu wildcard. Przydaje się to np. gdy:

  • lista subdomen zmienia się rzadko, ale usług kontenerowych jest dużo,
  • trzeba mieć bardzo dopieszczoną konfigurację TLS (np. pod testy PCI),
  • Traefik jest okresowo przeładowywany / aktualizowany, a Nginx ma gwarantować stabilny front.

Kiedy zostać przy Nginx, a kiedy wejść w Traefika

Jeżeli konfiguracja reverse proxy polega głównie na:

  • kilku–kilkunastu hostach wirtualnych,
  • pojedynczym serwerze VPS lub bare-metal,
  • mieszance aplikacji w Dockerze i bez Dockera,

Nginx będzie wystarczający, prosty i przewidywalny. Typowy zestaw:

  • osobny plik w /etc/nginx/sites-available na każdą domenę,
  • dzielenie konfiguracji na snippet-y (np. /etc/nginx/snippets/ssl.conf),
  • certbot lub inny „zewnętrzny” mechanizm ACME.

Traefik sprawdza się lepiej, gdy:

  • większość usług jest dockerowa,
  • często pojawiają się i znikają nowe kontenery (dev, staging, testy),
  • routowanie zależy głównie od etykiet i chcesz, by docker-compose był jedynym źródłem prawdy.

Z praktyki: przy małym, staticznym serwerze domowym Nginx jest mniej ruchomy, czyli mniej kusi, żeby robić „magiczne” konfiguracje. Z kolei przy homelabie z kilkunastoma docker-compose’ami i automatycznym deployem Traefik redukuje liczbę plików konfiguracyjnych i powtarzalnych fragmentów.

Szafa serwerowa z nowoczesnymi serwerami w centrum danych
Źródło: Pexels | Autor: panumas nikhomkhai

Konfiguracje przykładowe: Nginx vs Traefik dla tych samych usług

Nextcloud za Nginx – konfiguracja typowa

Popularne aplikacje, takie jak Nextcloud, mają gotowe, dopracowane konfiguracje pod Nginxa. Dają one m.in.:

  • zabezpieczenie plików .htaccess / .user.ini,
  • specyficzne reguły try_files,
  • buforowanie statycznych zasobów,
  • obsługę well-known dla WebDav, CalDav, CardDav.

Przykładowy skrócony vhost:

server {
    listen 80;
    server_name cloud.mojadomena.pl;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name cloud.mojadomena.pl;

    root /var/www/nextcloud;
    index index.php index.html /index.php$request_uri;

    # SSL, HSTS itd. (pominięte dla czytelności)

    location = /.well-known/carddav { return 301 /remote.php/dav/; }
    location = /.well-known/caldav  { return 301 /remote.php/dav/; }

    location / {
        rewrite ^ /index.php$request_uri;
    }

    location ~ .php(?:$|/) {
        fastcgi_split_path_info ^(.+?.php)(/.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }

    location ~ .(?:css|js|woff2?|svg|gif)$ {
        try_files $uri /index.php$request_uri;
        add_header Cache-Control "public, max-age=15778463";
    }

    location ~ .(?:htaccess|xml|user.ini)$ {
        deny all;
    }
}

Cała logika jest po stronie Nginxa; backend (PHP-FPM) tylko wykonuje skrypty. Taki układ pasuje wielu administratorom, bo łatwo się go debugguje (logi Nginxa i PHP są rozdzielone).

Sprawdź też ten artykuł:  Minimalistyczne systemy Open Source – szybko, lekko, bezpiecznie

Nextcloud za Traefikiem – bardziej „aplikacyjnie”

Uruchamiając Nextclouda w Dockerze, można całą „wiedzę” o nim przerzucić do kontenera (np. obraz nextcloud:fpm + kontener z Nginxem wewnątrz sieci Dockera) i wystawić tylko front reverse-proxy.

Jeden wariant:

  • wewnętrzny Nginx przy Nextcloudzie (z konfigiem jak wyżej, ale bez SSL),
  • Traefik na brzegu, który przekazuje ruch do nextcloud-nginx po HTTP.

Przykładowe labelki przy kontenerze z Nginxem Nextclouda:

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.nextcloud.rule=Host(`cloud.mojadomena.pl`)"
  - "traefik.http.routers.nextcloud.entrypoints=websecure"
  - "traefik.http.routers.nextcloud.tls.certresolver=le"
  - "traefik.http.services.nextcloud.loadbalancer.server.port=80"

Cały złożony vhost siedzi w środku kontenera aplikacyjnego; Traefik jedynie szyfruje, terminuje TLS i robi routing. Przy aktualizacji Nextclouda z gotowych obrazów często taki embedded Nginx jest już dopięty zgodnie z zaleceniami producenta.

Serwowanie statycznych plików, obrazów i dużych uploadów

Nginx słynie z wydajnego serwowania statycznych zasobów i strumieniowania dużych plików:

  • można ustawić sendfile on;, tcp_nopush on;,
  • przerzucić logikę obsługi duplikatów ETag / Last-Modified na serwer,
  • łatwo włączyć cache na poziomie reverse proxy.

Przykładowa uproszczona konfiguracja statycznego katalogu:

location /media/ {
    alias /srv/media/;
    autoindex off;
    expires 30d;
    add_header Cache-Control "public";
}

Traefik także radzi sobie z plikami statycznymi, ale nie ma aż tylu „niskopoziomowych” gałek. Tam, gdzie wymagana jest maksymalna kontrola nad buforowaniem, kompresją czy wielkością buforów uploadu, Nginx bywa wygodniejszy.

Diagnostyka i logowanie w reverse proxy

Logi dostępu i błędów – co widać w Nginx, a co w Traefiku

Przy debugowaniu problemów istotne są logi:

  • Nginx: access.log i error.log w formacie ustawianym przez log_format,
  • Traefik: logi aplikacyjne oraz osobne logi access log, jeśli są włączone.

W Nginx można dopasować szczegółowo format access logów:

log_format main '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '"$http_referer" "$http_user_agent" '
                '$request_time $upstream_response_time';

access_log /var/log/nginx/access.log main;

Dzięki temu w jednym wierszu widać np. czas odpowiedzi backendu i całego żądania. Gdy Nextcloud nagle zwalnia, wystarczy przejrzeć kilka wpisów i porównać czasy.

W Traefiku access logi włącza się flagą statyczną:

--accesslog=true
--accesslog.format=json

Domyślnie logi pojawiają się na stdout kontenera i można je zbierać np. Promtailem lub Filebeatem. W przypadku self hostingu na jednym VPS-ie wystarczy zwykłe docker logs traefik, ale przy większych instalacjach dobrze jest mieć scentralizowany system logowania.

Podgląd routingów i metryk w Traefiku

Traefik ma panel webowy (dashboard), który pokazuje:

  • jakie routery są aktywne,
  • jakie middlewares są używane,
  • na jakie serwisy wskazuje dany router.

Podstawowa konfiguracja panelu:

--api.dashboard=true
--api.insecure=false

Następnie tworzy się router dla panelu, najlepiej pod nietrywialną domeną z ochroną hasłem:

labels:
  - "traefik.http.routers.traefik.rule=Host(`router.mojadomena.pl`)"
  - "traefik.http.routers.traefik.entrypoints=websecure"
  - "traefik.http.routers.traefik.tls.certresolver=le"
  - "traefik.http.routers.traefik.service=api@internal"

Z poziomu panelu szybko wychodzi na jaw, dlaczego konkretna usługa nie działa – brakujące etykiety, literówki w nazwach entrypointów, konflikt reguł Host(). Przy Nginx jedyną podpowiedzią są zazwyczaj logi i ręczne przejrzenie plików konfiguracyjnych.

Wydajność i zasoby przy self hostingu

Zużycie pamięci i CPU

Na małych maszynach (domowy serwer, tani VPS) liczy się każdy megabajt RAM-u. W przybliżeniu:

  • Nginx jest bardzo lekki; pojedyncza instancja z kilkoma vhostami potrafi działać bez problemu na 256–512 MB RAM (oczywiście razem z resztą systemu trzeba liczyć więcej),
  • Traefik, napisany w Go, też jest oszczędny, ale dochodzi narzut na funkcje dynamiczne (watchowanie providera Docker, dashboard, ACME).

Przy jednym–dwóch serwisach reverse proxy często nie jest w ogóle wąskim gardłem – obciążają głównie same aplikacje (baza danych, PHP, JVM, Node). W takim przypadku wybór między Nginx a Traefikiem powinien wynikać z wygody zarządzania, a nie z samej wydajności.

Bufory, limity rozmiaru żądania i uploady

Problemy z dużymi uploadami (np. w Nextcloudzie albo własnym serwerze kopii zapasowych) wynikają zwykle z limitów po stronie reverse proxy:

  • w Nginx: client_max_body_size, client_body_buffer_size,
  • w Traefiku: opcje maxRequestBodyBytes lub limity w backendzie.

Nginx przykładowo:

server {
    # ...
    client_max_body_size 2G;
}

W Traefiku (v3) wielkość requestu ustawia się na poziomie serwisu:

Najczęściej zadawane pytania (FAQ)

Co to jest reverse proxy i po co mi ono w domowym serwerze (self hosted)?

Reverse proxy to serwer pośredniczący, który przyjmuje ruch z Internetu lub sieci lokalnej na standardowych portach (zwykle 80 i 443), a następnie przekazuje go do właściwych usług działających na innych portach lub hostach. Dla użytkownika wygląda jak jeden serwer, ale w środku działa jak „dyspozytor” kierujący żądania do różnych aplikacji.

W self hostingu reverse proxy pozwala wystawić wiele usług (np. Nextcloud, Jellyfin, Gitea, Home Assistant) za jednym adresem IP i jedną bramą. Ułatwia to zarządzanie, zwiększa bezpieczeństwo, upraszcza używanie HTTPS i sprawia, że adresy usług są czytelne i łatwe do zapamiętania.

Jaka jest różnica między reverse proxy a zwykłym serwerem WWW (Apache, Nginx)?

Klasyczny serwer WWW często bezpośrednio serwuje pliki (HTML, CSS, JS) lub uruchamia aplikację (np. PHP, Python) i jest „gospodarzem” logiki aplikacji. Reverse proxy z założenia nie przechowuje logiki biznesowej – jedynie przyjmuje żądania i przekazuje je do innych usług, które tę logikę realizują.

Nginx czy Traefik mogą pełnić obie role, ale w świecie self hosted zazwyczaj używa się ich przede wszystkim jako reverse proxy. Odpowiadają za terminowanie TLS, routowanie po domenach i ścieżkach, modyfikację nagłówków oraz opcjonalne logowanie, cache czy kompresję.

Jak reverse proxy rozróżnia, którą usługę self hosted wybrać (routing po domenie i ścieżce)?

Najczęściej reverse proxy korzysta z dwóch mechanizmów routingu: domeny (nagłówka Host) oraz ścieżki URL. Dzięki temu możesz mieć np. cloud.mojadomena.pl wskazujące na Nextclouda, git.mojadomena.pl na Giteę, a media.mojadomena.pl na Jellyfin.

Możliwe jest też routowanie po ścieżce, np. mojadomena.pl/cloud dla Nextclouda, mojadomena.pl/git dla Gitey. Wymaga to jednak staranniejszej konfiguracji (przepisywanie ścieżek, poprawka linków), ponieważ wiele aplikacji zakłada, że działa w katalogu głównym /.

Jak reverse proxy obsługuje HTTPS i certyfikaty (terminowanie TLS)?

Reverse proxy przyjmuje połączenia HTTPS z przeglądarki i to na nim kończy się szyfrowanie TLS (tzw. terminowanie TLS). Na tym serwerze znajdują się certyfikaty SSL/TLS (np. z Let’s Encrypt) oraz klucze prywatne. Po stronie backendu ruch najczęściej przekazywany jest już zwykłym HTTP w zaufanej sieci lokalnej lub wewnątrz Dockera.

Dzięki temu nie musisz konfigurować certyfikatów osobno w każdej aplikacji. Jeden mechanizm ACME/Let’s Encrypt (np. w Nginxie, Traefiku) może automatycznie odnawiać i podawać certyfikaty wszystkim usługom stojącym za reverse proxy.

Do czego służą nagłówki X-Forwarded-For i X-Forwarded-Proto w konfiguracji reverse proxy?

Nagłówki X-Forwarded-For, X-Forwarded-Proto i często X-Real-IP służą do przekazywania informacji o oryginalnym żądaniu klienta do aplikacji działającej za reverse proxy. Aplikacja „widzi” wtedy prawdziwy adres IP użytkownika oraz to, czy użył on HTTP czy HTTPS.

  • X-Forwarded-For – zawiera adres IP klienta (i ewentualnie kolejne pośredniki).
  • X-Forwarded-Proto – informuje, czy klient łączył się po http czy https.
  • X-Real-IP – często używany przez Nginxa do przekazania IP klienta.

W wielu aplikacjach self hosted (np. Nextcloud, Gitea, Grafana) trzeba włączyć opcję pracy „za reverse proxy”, aby poprawnie korzystały z tych nagłówków i generowały właściwe linki HTTPS.

Jak wygląda podstawowa konfiguracja Nginx jako reverse proxy dla jednej aplikacji?

W Nginxie konfiguracja opiera się na blokach http, server i location. W typowym scenariuszu definiujesz blok upstream z backendem (np. 127.0.0.1:8080), a następnie tworzysz blok server z domeną (np. cloud.mojadomena.pl), w którym w location / umieszczasz dyrektywę proxy_pass.

W tym samym miejscu ustawiasz nagłówki przekazujące IP i protokół (Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto). Dla wielu usług self hosted najwygodniej jest tworzyć osobny plik konfiguracyjny Nginx dla każdej domeny i aktywować go poprzez sites-available / sites-enabled.

Czy muszę używać Nginxa, czy mogę zamiast tego wybrać Traefika jako reverse proxy?

Nie musisz ograniczać się do Nginxa – Traefik jest bardzo popularną alternatywą, szczególnie w środowiskach opartych na Dockerze i Kubernetesie. Oba narzędzia pełnią tę samą funkcję (reverse proxy + terminowanie TLS + routing), ale różnią się podejściem do konfiguracji.

Nginx zwykle konfiguruje się statycznymi plikami konfiguracyjnymi, natomiast Traefik oferuje dynamiczne wykrywanie usług (np. z etykiet Dockera), zintegrowane zarządzanie certyfikatami Let’s Encrypt oraz rozbudowane opcje routingu. Wybór zależy od Twojego ekosystemu: dla prostego VPS często wystarczy Nginx, a dla intensywnego użycia Dockera/Kubernetesa Traefik bywa wygodniejszy.

Najważniejsze lekcje

  • Reverse proxy działa jako pośrednik przed aplikacjami self hosted – przyjmuje ruch na jednym adresie/porcie i przekazuje go do właściwych usług działających na różnych portach lub hostach.
  • Dzięki reverse proxy wiele usług może być udostępnionych pod jednym publicznym adresem IP, rozróżnianych po domenach (vhost) lub ścieżkach URL, co upraszcza dostęp dla użytkownika.
  • Reverse proxy centralizuje obsługę HTTPS (TLS), certyfikatów oraz wybranych mechanizmów bezpieczeństwa, logowania i kompresji, odciążając poszczególne aplikacje backendowe.
  • W typowym przepływie żądania reverse proxy rozwiązuje DNS, terminuję TLS, analizuje nagłówki HTTP, wybiera backend na podstawie reguł routingu, modyfikuje nagłówki (np. X-Forwarded-For) i opcjonalnie buforuje/kompresuje odpowiedź.
  • Routing po domenie jest zwykle prostszy i mniej problematyczny dla aplikacji (szczególnie generujących absolutne linki) niż routing po ścieżce, który często wymaga dodatkowego przepisywania URL-i.
  • Reverse proxy pozwala ukryć wewnętrzną topologię i porty usług, segmentować dostęp (LAN/Internet/VPN) oraz dodawać warstwy autoryzacji (SSO, Basic Auth, OAuth2 Proxy) przed aplikacjami.
  • Nginx i Traefik pełnią w self hostingu rolę centralnej „bramy” do wielu kontenerów i usług, a ich poprawna konfiguracja jest kluczowa dla wygody, bezpieczeństwa i utrzymania całej infrastruktury.