After fumbling around with CloudFront for entirely too long, I came up with a solution that seems to work reliably.
AWS CloudFront
Verify you have the following enabled:
- ViewerProtocolPolicy = "allow-all"
- OriginProtocolPolicy = "match-viewer"
- DistributionHTTPProtocolVersions = "http2-and-http3"
- DistributionSSLSupportMethod = "sni-only"
- CachePolicyExclusionPath = "/.well-known/*"
- OriginRequestPolicy
- Include Headers
- Origin
- Accept-Charset
- Accept
- Access-Control-Request-Method
- Access-Control-Request-Headers
- Referer
- Host
- Accept-Language
- Accept-Datetime
- Include Query Strings: all
- Include Cookies: all
Caddy
The config for Caddy is straightforward, this is my tls.automation.policy block (to support HTTP/3, make sure tcp+udp/443 are open to your Caddy instance):
{
"issuers": [
{
"ca": "https://acme-v02.api.letsencrypt.org/directory",
"challenges": {
"http": {
"disabled": false
},
"tls-alpn": {
"disabled": false
}
},
"email": "somebody@example.org",
"module": "acme"
}
],
"on_demand": true
}
And, on my http listener, I added a route/match like this to redirect to https, if the URL does not contain /.well-known/...:
"servers": {
"http": {
"listen": [
"0.0.0.0:80"
],
"routes": [
{
"group": "default",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "static_response",
"headers": {
"Location": [
"https://{http.request.host}{http.request.uri}"
]
},
"status_code": 301
}
],
"match": [
{
"not": [
{
"path": [
"/.well-known/*"
]
}
]
}
]
}
]
},
{
"body": "DEFAULT ROUTE",
"close": true,
"handler": "static_response",
"status_code": "200"
}
]
}
]
},
Notes
- In this setup, you will NOT have AWS CloudFront doing any
http→httpsredirection because you need at least some requests from ACME to get through to the origin viahttp. -
Caveat: You may be able to add a CachePolicy that would allow http or https for
/.well-known/*only, but I decided not to do that since my I need my Caddy instance to generally redirecthttp→httpsfor other use-cases anyways (but I have an exception in for/.well-known/*). If you did that in AWS CloudFront, that would allow you to only enable http + https access to the origin for a single URL/.well-known/*–YMMV, and I did not test that case since I did not need it.
Thank you for the help and pointers!!