NoctisNode
← PoradnikiSieci2026-10-239 min

Caddy jako reverse proxy TCP i proxy SSH z caddy-l4

Podstawowy Caddy przekazuje tylko HTTP. Dla surowego TCP i SSH zbuduj Caddy z aplikacją layer4 caddy-l4, przekierowuj porty albo współdziel port 443 między SSH a HTTPS według protokołu.

Krótko: standardowy Caddy nie potrafi przekazywać surowego TCP ani SSH, bo jego `reverse_proxy` mówi tylko HTTP. Aby przekierować TCP, budujesz Caddy z modułem caddy-l4 (github.com/mholt/caddy-l4) za pomocą xcaddy, a następnie konfigurujesz jego aplikację `layer4` tak, by nasłuchiwała na porcie i przekazywała połączenia — opcjonalnie wybierając upstream według protokołu, dzięki czemu SSH i HTTPS mogą dzielić port 443.

caddy-l4 to osobny moduł, który nie wchodzi w skład domyślnej dystrybucji Caddy, a jego README wciąż opisuje go jako projekt w toku, którego konfiguracja może zmieniać się między wersjami. Ten poradnik używa konfiguracji JSON, która bezpośrednio odpowiada udokumentowanej strukturze modułu. Jeśli potrzebujesz tylko proxy HTTP lub HTTPS, wystarczy Ci poradnik o reverse proxy w Caddy.

Dlaczego podstawowy Caddy obsługuje tylko HTTP

Wbudowane aplikacje Caddy to `http`, `tls` i `pki`. Handler `reverse_proxy` znajduje się wewnątrz aplikacji HTTP, więc potrzebuje sparsowanego żądania HTTP, zanim cokolwiek przekieruje. Klient SSH, klient PostgreSQL czy protokół gry nigdy go nie wysyłają, więc Caddy odpowiedziałby błędem TLS lub HTTP.

caddy-l4 dodaje osobną aplikację `layer4`, która działa na surowych połączeniach. Potrafi dopasować pierwsze bajty połączenia (banner SSH, TLS ClientHello z SNI, linię żądania HTTP, start PostgreSQL i inne), a następnie przekazać ruch, zakończyć TLS lub oddać strumień innemu handlerowi. Ponieważ jest aplikacją taką jak `http`, obie mogą działać w tym samym procesie.

PotrzebaPodstawowy CaddyCaddy + caddy-l4
Reverse proxy HTTPS z auto TLSTakTak
Zwykłe przekierowanie portów TCPNieTak (handler `proxy`)
Przekierowanie UDPNieTak (nasłuch na `udp/:port`)
TLS passthrough według SNINieTak (matcher `tls` z `sni`)
SSH i HTTPS na tym samym porcieNieTak (matchery `ssh` i `tls`)
Obsługa CaddyfilePełnaCzęściowa; JSON jest formatem referencyjnym

Zbuduj Caddy z modułem layer4

xcaddy kompiluje Caddy z dodatkowymi modułami. Alternatywnie wybierz `mholt/caddy-l4` na oficjalnej stronie pobierania Caddy i pobierz gotową binarkę. Tak czy inaczej, zanim napiszesz konfigurację, sprawdź przez `list-modules`, że moduły `layer4` są na liście.

# Current Caddy needs a recent Go toolchain; distro golang-go packages are
# often too old, so install the latest release from https://go.dev/dl/
# and make sure /usr/local/go/bin is in PATH, then:
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

# Build Caddy with the layer4 app
~/go/bin/xcaddy build --with github.com/mholt/caddy-l4

# Confirm the modules are present
./caddy list-modules | grep layer4

Bezpieczna podmiana binarki z pakietu

Jeśli Caddy został zainstalowany z oficjalnego repozytorium apt, udokumentowanym sposobem podmiany na własny build jest `dpkg-divert` plus `update-alternatives`, dzięki czemu aktualizacje pakietu nie nadpiszą Twojej binarki. Pamiętaj, że od teraz aktualizacje Caddy wymagają ponownego zbudowania.

sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy
sudo mv ./caddy /usr/bin/caddy.custom
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50
sudo systemctl restart caddy

Przykład 1: zwykły reverse proxy TCP

Ta konfiguracja nasłuchuje na porcie 5432 i przekazuje każde połączenie do serwera PostgreSQL pod prywatnym adresem, np. na drugim końcu tunelu WireGuard. Brak matchera oznacza, że każde połączenie idzie tą trasą. Upstreamy przyjmują kilka adresów `dial` na potrzeby failover, a handler `proxy` obsługuje load balancing i health checki podobnie jak HTTP `reverse_proxy`.

Backend widzi IP Caddy, a nie klienta. Jeśli backend rozumie protokół PROXY, ustaw `"proxy_protocol": "v2"` w handlerze proxy, aby przekazać oryginalny adres.

{
  "apps": {
    "layer4": {
      "servers": {
        "postgres": {
          "listen": [":5432"],
          "routes": [
            {
              "handle": [
                {
                  "handler": "proxy",
                  "upstreams": [{"dial": ["10.8.0.2:5432"]}]
                }
              ]
            }
          ]
        }
      }
    }
  }
}

Przykład 2: SSH i HTTPS multipleksowane na porcie 443

Klienci SSH wysyłają swój banner wersji (`SSH-2.0-...`) zaraz po połączeniu, więc caddy-l4 może rozpoznać SSH przed jakąkolwiek odpowiedzią serwera. Poniższa konfiguracja kieruje SSH do lokalnego sshd, TLS dla `git.example.com` do usługi, która sama kończy TLS, a cały pozostały TLS do aplikacji HTTP Caddy nasłuchującej na 8443. Ponieważ port 443 należy teraz do layer4, aplikacja HTTP nie może go również zajmować: ustaw `https_port 8443` w globalnych opcjach Caddyfile lub równoważny adres `listen` w JSON i zostaw otwarty port 80 dla wyzwań HTTP-01. Przy `https_port 8443` automatyczne przekierowanie HTTP na HTTPS w Caddy wskazywałoby port 8443, więc ustaw `auto_https disable_redirects` i dodaj własną stronę `http:// { redir https://{host}{uri} permanent }`.

Protokołów, w których pierwszy odzywa się serwer, takich jak SMTP, FTP czy MySQL, nie da się wykryć w ten sposób, bo klient czeka w milczeniu. Daj im osobny port.

{
  "apps": {
    "layer4": {
      "servers": {
        "mux443": {
          "listen": [":443"],
          "routes": [
            {
              "match": [{"ssh": {}}],
              "handle": [
                {"handler": "proxy", "upstreams": [{"dial": ["127.0.0.1:22"]}]}
              ]
            },
            {
              "match": [{"tls": {"sni": ["git.example.com"]}}],
              "handle": [
                {"handler": "proxy", "upstreams": [{"dial": ["127.0.0.1:3443"]}]}
              ]
            },
            {
              "match": [{"tls": {}}],
              "handle": [
                {"handler": "proxy", "upstreams": [{"dial": ["127.0.0.1:8443"]}]}
              ]
            }
          ]
        }
      }
    }
  }
}

Uruchom i przetestuj

  1. 01.Zapisz JSON jako `/etc/caddy/caddy.json` i zwaliduj go.
  2. 02.Zatrzymaj usługę i uruchom Caddy na pierwszym planie, aby obserwować log podczas łączenia.
  3. 03.Wskaż jednostce systemd plik JSON przez nadpisanie drop-in, a potem wykonaj `sudo systemctl daemon-reload` i `sudo systemctl start caddy`.
  4. 04.Połącz się przez `ssh -p 443` i otwórz stronę HTTPS w przeglądarce, aby potwierdzić, że obie trasy działają.
# Validate and test in the foreground first
sudo caddy validate --config /etc/caddy/caddy.json
sudo systemctl stop caddy
sudo caddy run --config /etc/caddy/caddy.json

# Make the service use the JSON file: sudo systemctl edit caddy
[Service]
ExecStart=
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/caddy.json
ExecReload=
ExecReload=/usr/bin/caddy reload --config /etc/caddy/caddy.json --force

# Client side
ssh -p 443 [email protected]

Kiedy zamiast tego użyć HAProxy lub sslh

caddy-l4 dobrze się sprawdza, gdy już używasz Caddy i chcesz jednego procesu dla HTTPS i kilku tras TCP. Przy konfiguracji z przewagą TCP dojrzałe alternatywy z repozytoriów Debiana i Ubuntu mogą być prostsze w utrzymaniu: HAProxy w `mode tcp` kieruje ruch według SNI przez `req.ssl_sni` i ma szczegółowe statystyki oraz health checki, a sslh to mały demon stworzony wyłącznie do współdzielenia jednego portu między SSH, TLS, OpenVPN i innymi. Oba instaluje się przez apt i aktualizuje razem z resztą systemu, bez własnego buildu do utrzymania.

Wystawienie SSH na 443 pomaga w sieciach, które przepuszczają tylko porty webowe, ale nie jest funkcją bezpieczeństwa. Zachowaj uwierzytelnianie wyłącznie kluczami z poradnika o hardeningu SSH. Na VPS NoctisNode masz pełny root, więc każde z tych narzędzi może zająć potrzebne porty; zachowanie certyfikatów po stronie HTTPS opisuje automatyczny HTTPS w Caddy, a dla kontenerów — Caddy jako reverse proxy dla Dockera.

NarzędzieMocne stronyKompromisy
Caddy + caddy-l4Jeden proces dla auto HTTPS i TCP, matchery protokołów, API JSONWłasny build, moduł wciąż się rozwija
HAProxyDojrzałe proxy TCP/HTTP, routing według SNI, rozbudowane health checki i statystykiWięcej konfiguracji, brak wbudowanego klienta ACME
sslhMalutki, wyspecjalizowany do współdzielenia portu dla SSH/TLS/VPNTylko multipleksuje; bez kończenia TLS i load balancingu

FAQ

QCzy Caddy może przekazywać ruch TCP?

ANie od razu po instalacji. Podstawowy Caddy przekazuje tylko HTTP; do surowego TCP lub UDP potrzebujesz buildu Caddy z zewnętrznym modułem caddy-l4 (layer4).

QJak przekazać SSH przez Caddy?

AZbuduj Caddy z caddy-l4, dodaj serwer layer4, który dopasowuje `ssh` i przekazuje do `127.0.0.1:22`, a potem połącz się przez `ssh -p <port>`. Na porcie 443 możesz połączyć to z trasą `tls`, aby HTTPS nadal działał.

QCzy SSH i HTTPS mogą dzielić port 443?

ATak. caddy-l4, sslh i HAProxy potrafią sprawdzić pierwsze bajty połączenia i skierować SSH oraz TLS do różnych backendów na tym samym porcie.

QCzy caddy-l4 obsługuje Caddyfile?

AObsługuje Caddyfile przez globalną opcję `layer4`, ale JSON pozostaje najpełniejszym i najlepiej udokumentowanym formatem. Sprawdź README modułu dla wersji, którą budujesz.

Caddy jako reverse proxy TCP i proxy SSH z caddy-l4 · NoctisNode