lucaslorentz / caddy-docker-proxy

Caddy as a reverse proxy for Docker
MIT License
2.86k stars 168 forks source link

Usage example results in TLSv1 internal error #645

Closed edelmanjm closed 2 months ago

edelmanjm commented 2 months ago

Hi all, new to Caddy so I'm sure this is something really stupid. I'm trying to follow the most basic example provided in the README, but I can't even get that to work.

Here's the output I'm seeing:

❯ cd caddy
❯ docker-compose up -d
Starting caddy_caddy_1 ... done
❯ cd ../whoami
❯ docker-compose up -d
Creating whoami_whoami_1 ... done
❯ curl -L whoami.example.com
curl: (6) Could not resolve host: whoami.example.com
❯ curl -L localhost:80
curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error
❯ curl -Lvv localhost:80
*   Trying 127.0.0.1:80...
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 308 Permanent Redirect
< Connection: close
< Location: https://localhost/
< Server: Caddy
< Date: Mon, 22 Jul 2024 23:27:41 GMT
< Content-Length: 0
< 
* Closing connection 0
* Clear auth, redirects to port from 80 to 443
* Issue another request to this URL: 'https://localhost/'
*   Trying 127.0.0.1:443...
* Connected to localhost (127.0.0.1) port 443 (#1)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Unknown (21):
* TLSv1.3 (IN), TLS alert, internal error (592):
* error:0A000438:SSL routines::tlsv1 alert internal error
* Closing connection 1
curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error

Both my docker-compose.yml files are exactly as provided in the README. What am I doing wrong?

francislavoie commented 2 months ago

If you use localhost as your hostname, then Caddy will be issuing a cert with its internal CA. No clients will trust that CA by default (because it didn't exist before you started Caddy) so you need to establish trust by installing Caddy's root CA cert on your host machine. See https://caddyserver.com/docs/running#local-https-with-docker for instructions.

If you used a real public domain, then Caddy would have issued the cert from Let's Encrypt, which is publicly trusted (their root CA cert is in your system's trust store) so you wouldn't have a problem.

edelmanjm commented 2 months ago

Okay, thanks. Since I'm using the whoami.example.com domain, as specified in the README, what entries do I need to add to my DNS server? I tried adding a DNS A Record mapping whoami.example.com to my internal IP address, but that still results in an SSL error.

❯ curl -L whoami.example.com
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
❯ host whoami.example.com
whoami.example.com has address 192.168.1.221
francislavoie commented 2 months ago

whoami.example.com is not a real domain, you can't use that. It's exactly as it says, an example. You need to substitute it with your own real domain.

edelmanjm commented 2 months ago

Ah okay thanks, my bad 🤦. Do I need to specify ACME credentials so Caddy can pull the certs from a CA? Will those certs work with internal IP addresses? Sorry for the dumb questions, still somewhat new to DNS.

francislavoie commented 2 months ago

Do I need to specify ACME credentials

You don't need any credentials, Let's Encrypt is free to use. Caddy automates the setup for you. Specifying an email address in your config is recommended, though (with the email global option).

Will those certs work with internal IP addresses?

Not unless you use the ACME DNS challenge which requires building with a plugin for your DNS provider. You can use Caddy's internal CA to issue IP certs, but you need to set up trust like I mentioned earlier.

edelmanjm commented 2 months ago

Gotcha, thanks. I port-forwarded Caddy to my WAN, and that works as expect. That said, that's unfortunately not really my use case. Is there a way to either:

  1. Use a self-signed certificate that won't be completely rejected by every browser/OS out there, without manually installing Caddy's internal CA on every machine I want to use? This is really just for use on my own internal network, and I'm happy to click past the security warnings thrown up by my browser, but if the page just won't load at all that's not so good.
  2. Pull a prebuilt version of Caddy + my DNS provider and use it with Docker/caddy-docker-proxy, or run xcaddy build and use it with Docker/caddy-docker-proxy, per these instructions?

Thanks again for your help, sorry for the dumb questions.

francislavoie commented 2 months ago

Use a self-signed certificate that won't be completely rejected by every browser/OS out there, without manually installing Caddy's internal CA on every machine I want to use?

No, because Caddy's certs will have a short lifetime so you'd have to click past browser prompts quite frequently because the cert would expire and get refreshed. Installing the root CA cert is the way to go.

Pull a prebuilt version of Caddy + my DNS provider and use it with Docker/caddy-docker-proxy, or run xcaddy build and use it with Docker/caddy-docker-proxy

Build from a Dockerfile:

https://github.com/lucaslorentz/caddy-docker-proxy?tab=readme-ov-file#custom-images