Fix ACME HTTP-01 passthrough in HAProxy config

Add an ACL that routes /.well-known/acme-challenge/ requests on :80
to Caddy instead of redirecting to HTTPS, so Let's Encrypt certificate
issuance works out of the box.

Also simplify Caddyfile to use Caddy's http_port/https_port directives.
This commit is contained in:
dolonet
2026-04-10 10:50:26 +00:00
parent 0c1d001949
commit d0412b21f6
4 changed files with 19 additions and 24 deletions
+5 -13
View File
@@ -1,19 +1,11 @@
{ {
# Caddy listens on 8443 behind HAProxy, which passes raw TLS through. # Caddy sits behind HAProxy which passes raw TLS through on :8443.
# Caddy terminates TLS itself and auto-obtains a Let's Encrypt certificate. # ACME HTTP-01 challenges arrive on :80 via HAProxy's acl passthrough.
# http_port 80
# If your domain's DNS already points to this server, ACME HTTP-01 challenge https_port 8443
# works through the HAProxy http frontend (:80 → redirect). For DNS-01
# or other ACME methods, see https://caddyserver.com/docs/automatic-https
} }
{$DOMAIN}:8443 { {$DOMAIN} {
tls {
# Use the ACME HTTP-01 challenge on port 80.
# HAProxy forwards :80 as HTTP, so Caddy can answer the challenge
# if you add an acl exception in haproxy.cfg (see README), or use
# DNS-01 instead.
}
root * /srv root * /srv
file_server file_server
} }
+3 -10
View File
@@ -45,16 +45,9 @@ docker compose exec mtg mtg access /config/config.toml
## ACME (Let's Encrypt) notes ## ACME (Let's Encrypt) notes
Caddy needs to answer the ACME HTTP-01 challenge on port 80. The HAProxy passes `/.well-known/acme-challenge/` requests on `:80` to
default `haproxy.cfg` redirects all `:80` traffic to HTTPS. If Caddy Caddy so that HTTP-01 validation works out of the box. Make sure your
cannot obtain a certificate, either: domain's DNS A/AAAA record points to this server before starting.
1. Temporarily stop HAProxy, let Caddy bind `:80` directly for the
initial certificate, then start the full stack; or
2. Use DNS-01 validation in the Caddyfile (requires a DNS provider
plugin); or
3. Add an HAProxy ACL that passes `/.well-known/acme-challenge/`
requests to the Caddy backend instead of redirecting.
## Architecture ## Architecture
+1
View File
@@ -44,6 +44,7 @@ services:
- caddy_data:/data - caddy_data:/data
- ./www:/srv:ro - ./www:/srv:ro
expose: expose:
- "80"
- "8443" - "8443"
environment: environment:
DOMAIN: ${DOMAIN:-example.com} DOMAIN: ${DOMAIN:-example.com}
+10 -1
View File
@@ -20,11 +20,16 @@ defaults
timeout client 60s timeout client 60s
timeout server 60s timeout server 60s
# --- HTTP :80 — redirect to HTTPS ------------------------------------------- # --- HTTP :80 — ACME challenges + redirect -----------------------------------
frontend http frontend http
bind *:80 bind *:80
mode http mode http
# Let Caddy answer ACME HTTP-01 challenges for Let's Encrypt.
acl is_acme path_beg /.well-known/acme-challenge/
use_backend web_acme if is_acme
http-request redirect scheme https code 301 http-request redirect scheme https code 301
# --- TLS :443 — SNI-based routing ------------------------------------------- # --- TLS :443 — SNI-based routing -------------------------------------------
@@ -45,3 +50,7 @@ backend mtg
backend web backend web
server web web:8443 server web web:8443
backend web_acme
mode http
server web web:80