Automatische HTTPS in Caddy: zo werkt auto-TLS en zo los je fouten op
Caddy haalt en vernieuwt via ACME TLS-certificaten voor elk domein in je config. Leer over HTTP-01, TLS-ALPN-01, wildcards via DNS-01, on-demand TLS en veelvoorkomende fouten.
Kort gezegd: Caddy schakelt HTTPS automatisch in voor elk siteadres dat een publieke domeinnaam is. Het vraagt een certificaat aan via ACME (standaard Let's Encrypt of ZeroSSL), bewijst de controle over het domein via de HTTP-01- of TLS-ALPN-01-challenge op poort 80 en 443, stuurt HTTP door naar HTTPS en vernieuwt het certificaat voordat het verloopt, zonder extra configuratie.
Een Caddy-reverse proxy is simpelweg Caddy die die HTTPS-verbinding afhandelt en het verzoek met de directive `reverse_proxy` doorstuurt naar een app op een andere poort, container of host. Die combinatie — TLS plus proxying in een paar regels — is de belangrijkste reden dat mensen voor Caddy kiezen.
Reverse proxy met SSL in drie regels
Als DNS naar de server wijst en poort 80 en 443 bereikbaar zijn, is deze Caddyfile een complete HTTPS-reverse proxy voor twee hostnamen. Caddy haalt bij het opstarten certificaten op voor beide namen, serveert HTTP/1.1, HTTP/2 en HTTP/3, en geeft `X-Forwarded-For`, `X-Forwarded-Proto` en `X-Forwarded-Host` door aan de backend. De optie `email` is optioneel, maar laat de CA contact met je opnemen over verlopende of ingetrokken certificaten.
Installatie vanuit de officiële apt-repository en de basis van systemd staan in de handleiding voor Caddy als reverse proxy; voor containers zie Caddy als Docker-reverse proxy. Pas wijzigingen toe met `sudo systemctl reload caddy`.
# /etc/caddy/Caddyfile
{
email [email protected]
}
example.com, www.example.com {
reverse_proxy 127.0.0.1:8080
}Hoe auto-TLS in Caddy onder de motorkap werkt
Wanneer Caddy een config laadt, verzamelt het elke hostnaam uit de siteadressen en bepaalt het wie elk certificaat moet uitgeven. Publieke domeinen gaan naar de publieke ACME-uitgevers; `localhost`, IP-adressen en uitsluitend interne namen krijgen certificaten van Caddy's eigen lokale CA (hetzelfde als `tls internal` schrijven). Certificaten, sleutels en het ACME-account worden opgeslagen in de datamap van Caddy: `/var/lib/caddy/.local/share/caddy` voor het apt-pakket, `/data` in de officiële Docker-image.
Vernieuwing gebeurt op de achtergrond, ruim voor het verlopen, en Caddy staplet OCSP-antwoorden waar de CA dat ondersteunt. Mislukt de uitgifte, dan probeert Caddy het opnieuw met exponential backoff en gebruikt het voor herhaalpogingen het staging-endpoint van de CA, zodat je de rate limits van productie niet opbrandt. Meerdere Caddy-instanties met dezelfde opslag stemmen zich af, zodat er maar één een bepaald certificaat aanvraagt.
| Challenge | Wat de CA controleert | Vereist | Wildcards? |
|---|---|---|---|
| HTTP-01 | Een token geserveerd op `http://domain/.well-known/acme-challenge/` | Poort 80 bereikbaar vanaf internet | Nee |
| TLS-ALPN-01 | Een speciaal certificaat dat tijdens een TLS-handshake wordt getoond | Poort 443 bereikbaar vanaf internet | Nee |
| DNS-01 | Een TXT-record op `_acme-challenge.domain` | API-token van de DNS-provider en een Caddy-build met die providermodule | Ja |
Wildcardcertificaten met DNS-01
Wildcardcertificaten zoals `*.example.com` kunnen alleen via de DNS-01-challenge worden uitgegeven. De standaard Caddy-binary bevat geen plugins voor DNS-providers, dus bouw je er een met xcaddy (of kies je de provider op de officiële downloadpagina) en geef je Caddy een API-token dat beperkt is tot het bewerken van DNS voor die zone. DNS-01 werkt ook als poort 80 en 443 niet vanaf internet bereikbaar zijn, bijvoorbeeld op een uitsluitend interne server.
Houd het token uit de Caddyfile: zet het in een environment-bestand dat de systemd-unit gebruikt (`sudo systemctl edit caddy`, dan `EnvironmentFile=/etc/caddy/caddy.env` onder `[Service]`) en scherm het bestand af met `chmod 600`.
# Build Caddy with a DNS provider module (example: Cloudflare)
xcaddy build --with github.com/caddy-dns/cloudflare
# Caddyfile: one wildcard certificate for all subdomains
*.example.com {
tls {
dns cloudflare {env.CF_API_TOKEN}
}
@app host app.example.com
handle @app {
reverse_proxy 127.0.0.1:3000
}
handle {
respond "Unknown host" 404
}
}On-demand TLS en staging
Met on-demand TLS haalt Caddy een certificaat op tijdens de eerste TLS-handshake voor een hostnaam die het nog niet eerder zag. Dat is bedoeld voor platforms waar klanten hun eigen domeinen naar jouw server laten wijzen. Configureer altijd het `ask`-endpoint: Caddy roept het aan met `?domain=name` en gaat alleen door bij een 200-antwoord. Zonder dat endpoint kan iedereen willekeurige namen naar je IP laten wijzen en je tegen rate limits laten aanlopen.
Schakel tijdens het experimenteren over op de staging-CA van Let's Encrypt met de globale optie `acme_ca`. Staging-certificaten worden niet door browsers vertrouwd, maar de limieten zijn veel hoger, zodat je vrij dingen kunt breken en repareren. Verwijder de optie als je klaar bent, en verwijder eventueel de staging-certificaten uit de datamap.
{
on_demand_tls {
ask http://127.0.0.1:5555/allowed
}
}
https:// {
tls {
on_demand
}
reverse_proxy 127.0.0.1:8080
}
# Global options block for testing
{
email [email protected]
# Test against Let's Encrypt staging; remove when everything works
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}Veelvoorkomende TLS-fouten in Caddy en hoe je ze oplost
- 01.DNS wijst niet naar de server: het A- of AAAA-record ontbreekt, wijst nog naar een oude server of zit in een cache. Een verouderd AAAA-record is een klassieke valkuil, omdat de CA IPv6 verkiest als dat bestaat. Controleer beide met `dig`.
- 02.Poort 80 of 443 dicht: de firewall op de host, een cloudfirewall of een router blokkeert inkomend verkeer, waardoor HTTP-01 noch TLS-ALPN-01 kan slagen. Open 80/tcp en 443/tcp (en 443/udp voor HTTP/3).
- 03.Poort al in gebruik: Apache, nginx of een andere container is aan 80 of 443 gebonden, waardoor Caddy niet kan luisteren. Stop de andere dienst of zet hem achter Caddy.
- 04.CDN-proxy ervoor: een proxy in oranje-wolkje-stijl beëindigt TLS vóór Caddy, wat TLS-ALPN-01 kan breken. Gebruik DNS-01, of zet het record tijdens de uitgifte op alleen DNS.
- 05.Rate limits: herhaalde mislukte pogingen of het wissen van de datamap laten je tegen de limieten van de CA aanlopen (Let's Encrypt beperkt mislukte validaties per hostnaam per uur en dubbele certificaten per week). Los de oorzaak op, gebruik staging en houd de datamap persistent.
- 06.CAA-record: een CAA-record dat alleen een andere CA toestaat, blokkeert de uitgifte. Sta `letsencrypt.org` en `sectigo.com` (gebruikt door ZeroSSL) toe of verwijder de beperking.
# Does the name resolve to this server (both IPv4 and IPv6)?
dig +short A example.com
dig +short AAAA example.com
curl -4 -s https://ifconfig.me ; echo
# Are ports 80 and 443 open in the host firewall?
sudo ufw status
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp
# Is something else already bound to 80/443?
sudo ss -ltnp '( sport = :80 or sport = :443 )'
# What does Caddy say?
sudo journalctl -u caddy --no-pager -n 100Ook HTTPS naar de backend
De meeste backends op dezelfde host spreken gewoon HTTP op localhost, en dat is prima. Staat de upstream op een andere machine of eist hij TLS, gebruik dan een `https://`-upstream en vertel Caddy welke naam het moet verifiëren en welke CA het moet vertrouwen. Vermijd `tls_insecure_skip_verify` buiten snelle tests, want het haalt de bescherming tegen onderschepping tussen proxy en backend weg. Voor verkeer tussen servers is een privé WireGuard-tunnel vaak eenvoudiger dan het beheren van backendcertificaten.
Op een NoctisNode-VPS met volledige root en een dedicated IPv4-adres is de gebruikelijke opzet: laat een A-record (geen AAAA tenzij de server IPv6 heeft) naar de server wijzen, open 80 en 443 en laat Caddy de rest doen. Moet je niet-HTTP-verkeer doorsturen, zie dan TCP- en SSH-proxying met Caddy.
example.com {
reverse_proxy https://10.0.0.5:8443 {
transport http {
tls_server_name backend.internal
tls_trust_pool file /etc/caddy/backend-ca.pem
}
}
}Veelgestelde vragen
QWat is een Caddy-reverse proxy?
ADat is de Caddy-webserver die clientverbindingen accepteert, meestal HTTPS afhandelt, en verzoeken met de directive `reverse_proxy` doorstuurt naar een of meer backenddiensten. Caddy haalt en vernieuwt de TLS-certificaten daarvoor automatisch.
QVernieuwt Caddy certificaten automatisch?
AJa. Caddy vernieuwt certificaten op de achtergrond ruim voordat ze verlopen en laadt ze opnieuw zonder herstart, zolang het domein nog naar de server resolvet en de challengepoorten bereikbaar blijven.
QWaarom krijgt Caddy geen certificaat?
ADe meest voorkomende oorzaken zijn DNS-records die ergens anders heen wijzen (inclusief een verouderd AAAA-record), geblokkeerde poorten 80 en 443, een ander programma dat die poorten gebruikt, of rate limits na herhaalde mislukkingen. `journalctl -u caddy` toont de exacte ACME-fout.
QKan Caddy een wildcardcertificaat uitgeven?
AJa, maar alleen via de DNS-01-challenge, waarvoor je een Caddy-build nodig hebt met de module van je DNS-provider en een API-token voor die zone.
QHoe schakel ik automatische HTTPS in Caddy uit?
AGebruik een `http://`-siteadres voor één site, of zet de globale optie `auto_https off`. Je kunt ook `auto_https disable_redirects` gebruiken om de certificaten te houden maar de doorverwijzing van HTTP naar HTTPS te stoppen.