1. The problem I’m having:
I work for my university and am trying to migrate from NGINX to Caddy to leverage Caddy’s default HTTP/3 support, so any help is very appreciated!
I am trying to run a Caddy server for my Next.js app which is running inside of a Docker container, a container which is running on my EC2 instance on AWS.
First, since my Docker image runs on 0.0.0.0:3000
, and I start my container by running:
sudo docker run -d -it -p 3000:3000 <CONTAINER_ID>
Then, I start the Caddy server by running:
sudo caddy run --config /etc/caddy/Caddyfile
2. Error messages and/or full log output:
After starting the Caddy server, I navigate to my domain on Chrome and I get the following error:
This page isn't working
mydomain.com redirected you too many times.
Try deleting your cookies.
ERR_TOO_MANY_REDIRECTS
and in Chrome’s console logs, I can see 23 requests being made, with 20 of those requests being GET requests to my domain.
Here are the logs I get from my Caddy server after enabling debug
mode:
2024/06/07 14:38:48.593 INFO using config from file {"file": "/etc/caddy/Caddyfile"}
2024/06/07 14:38:48.595 INFO adapted config to JSON {"adapter": "caddyfile"}
2024/06/07 14:38:48.597 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2024/06/07 14:38:48.597 INFO http.auto_https server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2024/06/07 14:38:48.597 INFO http.auto_https enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2024/06/07 14:38:48.597 WARN http.auto_https server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server {"server_name": "srv1", "http_port": 80}
2024/06/07 14:38:48.597 DEBUG http.auto_https adjusted config {"tls": {"automation":{"policies":[{}]}}, "http": {"servers":{"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"headers","response":{"set":{"Access-Control-Allow-Origin":["*"],"Strict-Transport-Security":["max-age=31536000;"]}}},{"handler":"static_response","headers":{"Location":["https://schuage.com{http.request.uri}"]},"status_code":302},{"encodings":{"gzip":{}},"handler":"encode","prefer":["gzip"]}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}},"srv1":{"listen":[":80"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"headers","response":{"set":{"Access-Control-Allow-Origin":["*"],"Strict-Transport-Security":["max-age=31536000;"]}}},{"encodings":{"gzip":{}},"handler":"encode","prefer":["gzip"]},{"handler":"reverse_proxy","upstreams":[{"dial":"localhost:3000"}]}]}]}],"terminal":true},{},{}],"automatic_https":{"disable":true}}}}}
2024/06/07 14:38:48.598 INFO http enabling HTTP/3 listener {"addr": ":443"}
2024/06/07 14:38:48.599 DEBUG http starting server loop {"address": "[::]:443", "tls": true, "http3": true}
2024/06/07 14:38:48.599 INFO http.log server running {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2024/06/07 14:38:48.599 DEBUG http starting server loop {"address": "[::]:80", "tls": false, "http3": false}
2024/06/07 14:38:48.599 INFO http.log server running {"name": "srv1", "protocols": ["h1", "h2", "h3"]}
2024/06/07 14:38:48.599 INFO http enabling automatic TLS certificate management {"domains": ["schuage.com"]}
2024/06/07 14:38:48.600 DEBUG tls.cache added certificate to cache {"subjects": ["schuage.com"], "expiration": "2024/09/04 20:33:23.000", "managed": true, "issuer_key": "acme-v02.api.letsencrypt.org-directory", "hash": "baf143dc0e2cfb49985889cc289ebac712f45c1c12311c0642db3662c60bdc6e", "cache_size": 1, "cache_capacity": 10000}
2024/06/07 14:38:48.600 DEBUG events event {"name": "cached_managed_cert", "id": "011504f0-d195-46d9-ad0b-69d5255e73ec", "origin": "tls", "data": {"sans":["schuage.com"]}}
2024/06/07 14:38:48.601 INFO autosaved config (load with --resume flag) {"file": "/root/.config/caddy/autosave.json"}
2024/06/07 14:38:48.601 INFO serving initial configuration
2024/06/07 14:38:48.603 INFO tls storage cleaning happened too recently; skipping for now {"storage": "FileStorage:/root/.local/share/caddy", "instance": "8631d928-2596-4766-8d0b-f2c2e9035a4d", "try_again": "2024/06/08 14:38:48.603", "try_again_in": 86399.999999051}
2024/06/07 14:38:48.603 INFO tls finished cleaning storage units
2024/06/07 14:38:48.603 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc000213580"}
2024/06/07 14:38:54.238 DEBUG events event {"name": "tls_get_certificate", "id": "8863eaf1-a190-49de-a3ac-9fcfe13e1601", "origin": "tls", "data": {"client_hello":{"CipherSuites":[23130,4865,4866,4867,49195,49199,49196,49200,52393,52392,49171,49172,156,157,47,53],"ServerName":"schuage.com","SupportedCurves":[10794,25497,29,23,24],"SupportedPoints":"AA==","SignatureSchemes":[1027,2052,1025,1283,2053,1281,2054,1537],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[43690,772,771],"RemoteAddr":{"IP":"76.157.240.140","Port":59908,"Zone":""},"LocalAddr":{"IP":"172.31.29.209","Port":443,"Zone":""}}}}
2024/06/07 14:38:54.238 DEBUG tls.handshake choosing certificate {"identifier": "schuage.com", "num_choices": 1}
2024/06/07 14:38:54.238 DEBUG tls.handshake default certificate selection results {"identifier": "schuage.com", "subjects": ["schuage.com"], "managed": true, "issuer_key": "acme-v02.api.letsencrypt.org-directory", "hash": "baf143dc0e2cfb49985889cc289ebac712f45c1c12311c0642db3662c60bdc6e"}
2024/06/07 14:38:54.238 DEBUG tls.handshake matched certificate in cache {"remote_ip": "76.157.240.140", "remote_port": "59908", "subjects": ["schuage.com"], "managed": true, "expiration": "2024/09/04 20:33:23.000", "hash": "baf143dc0e2cfb49985889cc289ebac712f45c1c12311c0642db3662c60bdc6e"}
Running curl -vL https://schuage.com
yields the same response as the Chrome’s console logs. I would share what curl returns but the results are very long.
3. Caddy version:
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
4. How I installed and ran Caddy:
a. System environment:
- OS:
Amazon Linux 2023
- AMI ID:
ami-00beae93a2d981137
- Size:
t2.micro
- Docker version:
Docker version 25.0.3, build 4debf41
b. Command:
curl -o caddy.tar.gz -L "https://github.com/caddyserver/caddy/releases/download/v2.8.4/caddy_2.8.4_linux_amd64.tar.gz"
tar -zxvf caddy.tar.gz
sudo mv caddy /usr/local/bin/
chmod +x /usr/local/bin/caddy
caddy version
c. Service/unit/compose file:
n/a
d. My complete Caddy config:
{
debug
}
schuage.com {
encode gzip
header {
Strict-Transport-Security "max-age=31536000;"
Access-Control-Allow-Origin "*"
}
redir https://schuage.com{uri} 302
}
http://schuage.com {
encode gzip
header {
Strict-Transport-Security "max-age=31536000;"
Access-Control-Allow-Origin "*"
}
reverse_proxy {
to http://localhost:3000
}
}
5. Links to relevant resources:
I have looked at the following resources:
but both of these posts use Docker while I am trying to server my Next.js app with Caddy manually on my AWS EC2 instance within the server.
NOTE: On my NGINX configuration
I can serve my Next.js app from the same Docker container just fine with nginx
, but when I do, I don’t NGINX serving my site with QUIC and HTTP/3 in my browser; only HTTP/2, so I want to switch to using Caddy since I can see that it auto-enables HTTP/3 by default with no manual configuration.
For reference, here’s my NGINX configuration that I use:
server {
root /var/www/html;
server_name schuage.com www.schuage.com;
http2 on; # HTTP/2 only
http3 on; # QUIC and HTTP/3 only
http3_hq on; # QUIC and HTTP/3 only
quic_retry on; # QUIC and HTTP/3 only
ssl_early_data on; # Enabling QUIC 0-RTT
listen [::]:443 quic reuseport default_server; # QUIC and HTTP/3 only
listen 443 quic reuseport default_server; # QUIC and HTTP/3 only
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/schuage.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/schuage.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_pass http://localhost:3000;
add_header Alt-svc 'h3=":443"; ma=3600, h3-29=":443"; ma=3600'; # QUIC and HTTP/3 only
add_header x-quic 'h3'; # QUIC and HTTP/3 only
add_header Cache-Control 'no-cache,no-store'; # QUIC and HTTP/3 only
add_header X-protocol $server_protocol always; # QUIC and HTTP/3 only
proxy_set_header Early-Data $ssl_early_data; # QUIC and HTTP/3 only
}
}
server {
if ($host = www.schuage.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = schuage.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80 default_server;
listen [::]:80 default_server;
server_name schuage.com www.schuage.com;
return 404; # managed by Certbot
}
NOTE: On Inbound connections for my AWS EC2 instance
I am not sure if it is necessary, but I went ahead and changed the Security Group for my EC2 instance by adding an inbound security rule to allow for inbound requests coming from UDP using IPv4.
The rule settings are shown below:
IP Type Protocol Port range Source
IPv4 Custom UDP UDP 443 0.0.0.0/0
NOTE: On using Dockerized Caddy server to serve my Next.js app
I haven’t tried this yet because I wanted to first try to get my Caddy server running without Docker, but if running a Docker image of a Caddy server is the only way to serve my Docker image of my Next.js app on my AWS EC2 instance, then I will try to do that instead.
For now, I am focusing on other feature integrations before attempting to dockerize a Caddy server to serve my Docker image of my Next.js app.
Any help is very appreciated!