Zašto upravo Caddy + Tailscale, a ne nginx + WireGuard ili Cloudflare Tunnel

Ako ste u 2024./2025. namještali homelab sa nginx + Let's Encrypt certbot + ručno otvaranje 443 porta, vjerojatno vam je u nekom trenutku istekao certifikat, popila vam je IP HEP-ovi blokovi, ili je Cloudflare Tunnel zatrebao plaćeni plan za WebSocket podršku. Posljednje dvije godine su pomakle "best practice" u potpuno novi smjer:

  1. Caddy v2.10 (izdano u veljači 2026.) ima native podršku za distributed ACME preko Tailscale tailnet-a — više instanca Caddy-ja dijele certifikate kroz tailnet, bez vanjskog Redis-a ili etcd-a. Plus, Caddyfile ostaje 20× kraći od nginx config-a za istu funkciju.
  2. Tailscale 1.78 (lipanj 2026.) je dodao node-level HTTPS proxy koji izdaje vlastiti <machine>.ts.net certifikat od Tailscale CA — ne trebate ni Let's Encrypt za pristup unutar tailnet-a (dosadno objašnjavanje "self-signed certifikat" obitelji konačno staje).
  3. MagicDNS + Funnel: ako iznimno trebate pristup izvana (npr. dijeljenje Jellyfin linka roditeljima), Tailscale Funnel besplatno dijeli pojedinačni port na javni internet. Više ne otvaramo 443/80 na ruteru.

Ovaj vodič pokriva homelab postavljen na jedan stroj (typično Mini-PC Beelink SER5/SER6, Intel N100, Raspberry Pi 5 ili stara desktop Linux mašina) s Docker-om i 5-15 servisima. Ako imate proxmox cluster ili kubernetes, Caddy radi isto, ali specifična caddy-docker-proxy integracija nije ovdje opisana — koristite caddy-docker-proxy v2.10 koji čita Docker labele direktno.

Što trebate prije početka

  • Linux mašina (Ubuntu 24.04 LTS, Debian 12 ili Mint 22). Pretpostavka: Docker + Docker Compose v2.30+ instalirani.
  • Vlastita domena (jeftina opcija u 2026.: .online od Hostinger za 0,49 EUR/godina, .eu.com od Cloudflare za 8,57 EUR/godina). Domena vam treba samo za Caddy-jevu vanjsku verifikaciju ACME-a; pristup je preko tailnet-a.
  • Tailscale račun (besplatno do 100 uređaja + 3 korisnika).
  • 2-3 servisa već postavljena (Nextcloud / Jellyfin / Home Assistant / Vaultwarden / Frigate — bilo što).
  • 30 minuta vremena.

Korak 1 — Instalacija Tailscale na homelab server

# Ubuntu/Debian/Mint:
curl -fsSL https://tailscale.com/install.sh | sh

# Pokretanje s preautoriziranim ključem (preporučeno za servere):
sudo tailscale up --advertise-tags=tag:homelab \
                  --ssh \
                  --hostname=homelab-01 \
                  --accept-routes=false

Argumentacija parametara:

  • --advertise-tags=tag:homelab — taggira ovaj uređaj za lakše ACL pravilo (vidimo u koraku 4).
  • --ssh — omogućava Tailscale SSH bez ručnog upravljanja SSH ključevima. Više nema "kopiraj public key na server". Tailscale provjerava identitet preko OAuth-a.
  • --hostname=homelab-01 — postavlja MagicDNS ime; pristupat ćemo https://homelab-01.tail-scale.ts.net/.
  • --accept-routes=false — ne primamo trasiranja od drugih nodes-a (siguran default).

Nakon tailscale up, dobit ćete login URL — otvorite ga u browseru, autorizirate uređaj. Trajno autorizirajte ("Disable key expiry") u Tailscale admin panelu (https://login.tailscale.com/admin/machines) jer inače server padne s tailnet-a za 180 dana.

Verifikacija: tailscale status na drugom Tailscale-spojenom uređaju (npr. vaš mobitel s Tailscale aplikacijom) treba pokazati homelab-01.tail-scale.ts.net kao online.

Korak 2 — Instalacija Caddy v2.10

Najlakše preko Docker Compose. Stvorite /srv/caddy/docker-compose.yml:

services:
  caddy:
    image: caddy:2.10-alpine
    container_name: caddy
    restart: unless-stopped
    network_mode: host  # bitno za Tailscale interfacing
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    environment:
      - TAILSCALE_CERT_DOMAIN=tail-scale.ts.net
    cap_add:
      - NET_ADMIN

volumes:
  caddy_data:
  caddy_config:

network_mode: host je nužan jer Caddy mora doseći Tailscale interface (tailscale0), a default Docker bridge to ne dopušta bez ručnog kapsuliranja. Trade-off: Caddy "vidi" sve host portove, pa pazite koji port koji servis koristi.

Korak 3 — Caddyfile za 4 typical homelab servisa

Caddyfile (/srv/caddy/Caddyfile):

{
    # Globalne postavke
    auto_https disable_redirects
    storage file_system /data

    # Tailscale TLS — koristi tailnet CA umjesto Let's Encrypt-a
    # za sve `*.ts.net` hostname-ove
    servers {
        listener_wrappers {
            http_redirect
            tls
        }
    }
}

# Nextcloud — file sync
nextcloud.homelab-01.tail-scale.ts.net {
    reverse_proxy localhost:8080

    encode gzip zstd

    # CalDAV/CardDAV redirekcija (Nextcloud zahtijeva ovo)
    redir /.well-known/carddav /remote.php/dav 301
    redir /.well-known/caldav /remote.php/dav 301

    header {
        Strict-Transport-Security "max-age=31536000;"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "no-referrer"
    }
}

# Jellyfin — media streaming
jellyfin.homelab-01.tail-scale.ts.net {
    reverse_proxy localhost:8096 {
        flush_interval -1  # streaming, ne bufferirati
    }
    encode gzip
}

# Vaultwarden — password manager
vault.homelab-01.tail-scale.ts.net {
    reverse_proxy localhost:8000

    # WebSocket za real-time sync
    @websockets {
        header Connection *Upgrade*
        header Upgrade websocket
    }
    reverse_proxy @websockets localhost:8000
}

# Home Assistant
ha.homelab-01.tail-scale.ts.net {
    reverse_proxy localhost:8123 {
        flush_interval -1
    }

    # WebSocket
    @ws {
        header Connection *Upgrade*
        header Upgrade websocket
    }
    reverse_proxy @ws localhost:8123
}

Pokrenite Caddy: cd /srv/caddy && docker compose up -d. Pogledajte log: docker compose logs -f caddy. Trebali biste vidjeti tailnet certificate manager ready u prvih 30 sekundi.

Korak 4 — Tailscale ACL za ograničavanje pristupa

Otvorite Access controls u Tailscale admin panelu. Default policy file je previše permissive. Zamijenite s ovim:

{
  "tagOwners": {
    "tag:homelab": ["autogroup:admin"],
    "tag:family":  ["autogroup:admin"]
  },
  "acls": [
    // Admin (vi) imate puni pristup svemu
    {
      "action": "accept",
      "src":    ["autogroup:admin"],
      "dst":    ["*:*"]
    },
    // Obitelj može doći do Jellyfin-a i Vaultwarden-a, ali NE do
    // Nextcloud-a (privatni file-i) i Home Assistant-a (kontrole kuće)
    {
      "action": "accept",
      "src":    ["tag:family"],
      "dst":    ["tag:homelab:443"]
    }
  ],
  "ssh": [
    {
      "action": "accept",
      "src":    ["autogroup:admin"],
      "dst":    ["tag:homelab"],
      "users":  ["root", "claudeuser"]
    }
  ]
}

Sad supruga, partner ili dijete mogu doći do jellyfin.homelab-01.tail-scale.ts.net s mobitela bez VPN klijenta? Ne — trebaju Tailscale aplikaciju. Ali jednom kad je instalirana i taggirana s tag:family, sve radi automatski s HTTPS-om i bez password-a (Tailscale identitet je dovoljan; opcionalno možete dodati ime/passwordove za pojedine servise iznad toga).

Korak 5 — Vanjski pristup preko Tailscale Funnel (samo ako trebate)

Ako baš želite poslati jednom prijatelju link na vašu Frigate live-cameru bez instaliranja Tailscale-a:

# Uključi Funnel za jedan hostname:
tailscale funnel --bg https://localhost:8971

Ovo otvara https://homelab-01.tail-scale.ts.net/ prema javnom internetu, bez otvaranja portova na ruteru. Tailscale je proxy. Saobraćaj prolazi kroz Tailscale relay servere (DERP). Throughput: ~50 Mbps po Funnel sesiji, ali za sporadičan use je sasvim dovoljno.

Sigurnosno upozorenje: Funnel ide u public internet. Stavite autentifikaciju na razini aplikacije (npr. Jellyfin user/pass), ne pretpostavljajte da je tailnet privatnost dovoljna.

Najčešćih 5 grešaka — kako ih izbjeći

  1. "Tailscale ne vidi servis na localhost". Caddy je u Docker mreži host, ali vaš servis (npr. Nextcloud) je možda u različitoj bridge mreži. Rješenje: ili stavite servis isto na host, ili reverzni proxy preko extra_hosts: ["host.docker.internal:host-gateway"] i u Caddyfile koristite reverse_proxy host.docker.internal:8080.
  2. Certifikat istječe svakih 90 dana neovisno. Tailscale tailnet CA daje 90-dnevne certifikate. Caddy ih obnavlja automatski 30 dana prije isteka — ali samo ako proces nije pao. Provjerite caddy_data volume da nije obrisan. Mountati ga lokalno (./data:/data) je preporučeno.
  3. MagicDNS ne radi za novi servis. Tailscale MagicDNS resolva imena nodes-a, ali ne subdomene unutar node-a. nextcloud.homelab-01.tail-scale.ts.net traži explicit DNS zapis. Rješenje: u Tailscale admin panelu, DNS → Custom nameservers, dodajte vlastiti AdGuard Home ili Pi-hole na tailnet IP-u homelab-01, i tamo CNAME-ujte sve subdomene na homelab-01.tail-scale.ts.net. Alternativa: stavite sve servise na pojedinačne portove istog hostname-a (manje lijepo).
  4. Caddy povremeno gubi internet pristup. Ako vam je default route preko Tailscale-a (--accept-routes=true ili exit-node moda), DNS lookup za ACME staging može pasti. Držite --accept-routes=false na homelab server-u, ili koristite Tailscale tailnet TLS i nemate potrebu za vanjskim ACME-om.
  5. Docker Compose ne pokreće Caddy nakon reboot-a. Restart policy unless-stopped se primjenjuje samo na servise koji su jednom uspješno pokrenuti. Provjerite da systemd ima docker.service u WantedBy=multi-user.target. Test: sudo systemctl is-enabled docker mora biti enabled. Ako nije: sudo systemctl enable docker.

Što dalje

Sada kad imate temelj, dodavanje novog servisa je copy-paste:

  1. Pokrenite servis na nekom localhost portu (npr. Frigate na 5000).
  2. Dodajte novi blok u Caddyfile sa subdomenom frigate.homelab-01.tail-scale.ts.net.
  3. docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile.
  4. Frigate je dostupan s mobitela kroz Tailscale aplikaciju za 5 sekundi.

Ako ste prije ovog tutoriala imali otvorene portove na ruteru — zatvorite ih sada. 443/80 više ne treba biti otvoren. Cijela kuća sigurnija za nekoliko minuta.

Veza s drugim našim člancima