Wolkra

Handleidingen

Caddy instellen als reverse proxy

Zet Caddy op als reverse proxy op Ubuntu of Debian: automatisch HTTPS, meerdere apps op één server, basic auth, load balancing en echte Caddyfile-voorbeelden.

Bijgewerkt 5 min. leestijd

Een reverse proxy ontvangt al het webverkeer op poort 80 en 443 en stuurt elk verzoek door naar de juiste app op de server. Caddy is een goede keuze omdat hij zelf HTTPS-certificaten ophaalt en vernieuwt: één regel zoals reverse_proxy localhost:3000 per site is genoeg.

Deze gids installeert Caddy op Ubuntu 24.04 of Debian 12 en bouwt de configuratie stap voor stap op.

Waarom een proxy ervoor zetten?

  • Eén toegangspunt. Meerdere apps op één server, elk op een eigen domein of pad.
  • HTTPS op één plek. Apps praten gewoon HTTP op localhost; Caddy regelt TLS.
  • Beveiliging. Apps luisteren nooit op publieke poorten. In de proxy kun je headers, rate limits of een wachtwoord toevoegen.
  • Flexibiliteit. Verhuis een app naar een andere poort of server en pas één regel aan.

1. Vereisten

  • Een server waarop de eerste stappen zijn gedaan.
  • DNS-records voor elk domein die naar de server verwijzen (A voor IPv4, AAAA voor IPv6).
  • Poort 80 en 443 open:
bash
sudo ufw allow 80,443/tcp
sudo ufw allow 443/udp     # HTTP/3

Open dezelfde poorten in je cloudfirewall als je die gebruikt.

2. Caddy installeren

bash
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
  sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install -y caddy
systemctl status caddy

Het pakket draait Caddy als systemd-service, met de configuratie in /etc/caddy/Caddyfile.

3. De kleinste nuttige Caddyfile

Stel dat een app luistert op localhost:3000. Vervang het bestand door:

text
app.example.com {
    reverse_proxy localhost:3000
}

Valideer en herlaad:

bash
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Bij het eerste verzoek haalt Caddy een certificaat op, stuurt HTTP door naar HTTPS en serveert de app. Meer is het niet.

4. Meerdere apps op één server

Voeg per site een blok toe:

text
app.example.com {
    reverse_proxy localhost:3000
}

api.example.com {
    reverse_proxy localhost:8080
}

status.example.com {
    reverse_proxy localhost:3001
}

Of verdeel één domein op pad:

text
example.com {
    handle_path /api/* {
        reverse_proxy localhost:8080
    }
    handle {
        root * /var/www/site
        file_server
    }
}

handle_path haalt /api weg voordat het verzoek wordt doorgestuurd; gebruik handle als de backend het prefix verwacht.

5. Handige standaardinstellingen met een snippet

Snippets houden herhaalde instellingen op één plek:

text
(common) {
    encode zstd gzip
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server
    }
    log {
        output file /var/log/caddy/access.log {
            roll_size 50MiB
            roll_keep 5
        }
    }
}

app.example.com {
    import common
    reverse_proxy localhost:3000
}

Maak de logmap één keer aan: sudo mkdir -p /var/log/caddy && sudo chown caddy:caddy /var/log/caddy.

6. Een beheertool beveiligen met een wachtwoord

Genereer een wachtwoordhash:

bash
caddy hash-password

Gebruik die in het siteblok:

text
admin.example.com {
    basic_auth {
        alice <paste-hash-here>
    }
    reverse_proxy localhost:9000
}

In oudere Caddy-versies heet de directive basicauth. Beperk voor alles wat gevoelig is ook op adres:

text
admin.example.com {
    @outside not remote_ip 198.51.100.0/24
    respond @outside 403
    reverse_proxy localhost:9000
}

Het bereik is een voorbeeld. Vul het bereik van je kantoor of VPN in; met de WireGuard-gids kan dat je VPN-subnet zijn.

7. Doorsturen naar Docker-containers

Draait Caddy op de host, bind containers dan aan localhost zodat ze niet publiek zijn:

yaml
services:
  app:
    image: ghcr.io/example/app:1.0
    ports:
      - "127.0.0.1:3000:3000"

Draait Caddy in Docker, zet hem dan in hetzelfde Compose-project en stuur door naar servicenamen (reverse_proxy app:3000). De Docker Compose-gids laat een complete stack zien.

8. Load balancing over meerdere backends

Caddy kan verzoeken verdelen over meerdere app-instanties, op dezelfde server of op andere servers via een privénetwerk:

text
app.example.com {
    reverse_proxy 10.0.0.11:3000 10.0.0.12:3000 {
        lb_policy least_conn
        health_uri /healthz
        health_interval 10s
    }
}

De adressen zijn voorbeelden uit een privébereik. Wil je de verdeling buiten je servers houden, dan doet een beheerde load balancer hetzelfde werk met health checks, en die kan ook servers zonder publiek IP bereiken.

9. WebSockets en echte client-IP's

WebSockets werken via reverse_proxy zonder extra instellingen. Caddy stuurt X-Forwarded-For, X-Forwarded-Proto en X-Forwarded-Host naar de backend; stel je app zo in dat hij die alleen vanaf 127.0.0.1 vertrouwt.

Staat Caddy zelf achter een andere proxy of load balancer, vertel hem dan welke adressen hij moet vertrouwen:

text
{
    servers {
        trusted_proxies static 10.0.0.0/24
    }
}

Dit globale blok hoort helemaal bovenaan de Caddyfile.

10. Logs en probleemoplossing

bash
journalctl -u caddy --since "10 min ago"
sudo tail -f /var/log/caddy/access.log
curl -I https://app.example.com

Veelvoorkomende problemen:

Probleem Oplossing
Certificaat niet uitgegeven DNS moet naar deze server wijzen; poort 80/443 open in UFW en de cloudfirewall
502 Bad Gateway De backend draait niet of luistert op een andere poort: ss -tlnp
Redirect-lus De app stuurt zelf ook door naar HTTPS; laat Caddy dat doen en vertrouw X-Forwarded-Proto
Wijzigingen genegeerd Voer systemctl reload caddy uit en controleer de uitvoer van caddy validate

Uitgevers van certificaten hanteren rate limits bij herhaalde mislukkingen, dus los DNS op voordat je het vaak opnieuw probeert.

Redirects en canonieke domeinen

De meeste sites horen op één naam te antwoorden en de andere door te sturen. Stuur www naar het kale domein:

text
www.example.com {
    redir https://example.com{uri} permanent
}

example.com {
    reverse_proxy localhost:3000
}

Caddy haalt voor beide namen certificaten op. Draai ze om als je liever www als hoofdadres gebruikt.

Rate limiting en verzoekgrootte

Caddy houdt de kern klein, dus voor rate limiting heb je een plug-in nodig. Voor de meeste kleine sites is Fail2ban op het toegangslog of een limiet in de applicatie genoeg. Het beperken van de grootte van de request body is wel ingebouwd:

text
app.example.com {
    request_body {
        max_size 20MB
    }
    reverse_proxy localhost:3000
}

Zo houd je te grote uploads tegen voordat ze je app bereiken.

Statische bestanden naast een app

Assets rechtstreeks van schijf serveren is sneller dan ze via de app te laten lopen:

text
app.example.com {
    handle /static/* {
        root * /var/www/app
        file_server
        header Cache-Control "public, max-age=604800"
    }
    handle {
        reverse_proxy localhost:3000
    }
}

11. Waar certificaten staan

Caddy bewaart certificaten en sleutels onder /var/lib/caddy/.local/share/caddy. Neem dat pad mee in je back-ups, zodat je na een herstel niet alles opnieuw hoeft uit te geven. Ontbreekt het, dan haalt Caddy gewoon nieuwe certificaten op.

Volgende stappen

Met Caddy ervoor kun je veel apps op één server hosten. Logische volgende stappen zijn WordPress, een Docker-stack of een zelfgehoste tool uit self-hosting. Vergeet de basisbeveiliging en back-ups niet.

Veelgestelde vragen

Haalt Caddy echt automatisch HTTPS-certificaten op?

Ja. Als een siteadres in de Caddyfile een publiek domein is dat naar de server verwijst, en poort 80 en 443 bereikbaar zijn, haalt Caddy zelf certificaten op bij een publieke ACME-autoriteit en vernieuwt ze ook.

Is Caddy snel genoeg voor productie?

Ja. Bij gangbare webapps is de reverse proxy zelden de bottleneck, en Caddy ondersteunt HTTP/2 en HTTP/3 direct uit de doos.

Kan Caddy doorsturen naar apps in Docker?

Ja. Draai Caddy in hetzelfde Compose-netwerk en gebruik servicenamen, of bind containers aan 127.0.0.1 en stuur door naar poorten op localhost.

Caddy of Nginx?

Caddy vraagt minder configuratie en regelt certificaten zelf. Nginx heeft een groter ecosysteem van voorbeelden en modules. Beide zijn solide keuzes.

Waarom krijgt Caddy geen certificaat?

Meestal wijst DNS nog niet naar de server, of wordt poort 80 of 443 door een firewall geblokkeerd. Controleer beide en kijk daarna in journalctl -u caddy.

Start een server in Frankfurt

Maak een account aan, waardeer op en draai een server vanaf €3.49 per maand. Je betaalt alleen voor de uren die je gebruikt. Onbemeterde bandbreedte bij elk pakket.