Localhost ssl in docker (podman) container

1. Caddy version:

caddy version (in the container); unknown
apk info caddy (in the container): caddy-2.6.2-r2
Caddy runing in podman (docker) container based on alpine:latest

2. How I installed, and run Caddy:

Runs in podman (docker) container like this:
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

a. System environment:

alpine:latest, podman (docker)

b. Command:

podman run -it -p 12345:80 -p 12346:443 website_testing:latest 

c. Service/unit/compose file:

FROM alpine:latest

ARG WEBBUILDTYPE=production
# or testing

RUN apk add --no-cache ca-certificates caddy nss-tools

COPY src /www/prod
COPY server/caddy/Caddyfile_production etc/caddy/Caddyfile_production
COPY server/caddy/Caddyfile_testing etc/caddy/Caddyfile_testing

RUN mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bkp.dist
RUN if test "$WEBBUILDTYPE" = 'production'; then ln -s /etc/caddy/Caddyfile_production /etc/caddy/Caddyfile ; else ln -s /etc/caddy/Caddyfile_testing /etc/caddy/Caddyfile ; fi

ENV XDG_DATA_HOME /data

CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"]

we are talking about the WEBBUILDTYPE=testing here.

d. My complete Caddy config:

localhost 127.0.0.1 {
	redir /staging /staging/
	route /staging/* {
		uri strip_prefix /staging
		basicauth {
			staging_user CREDENTIALS_REDACTED
		}
		file_server {
			root /www/staging
		}
	}
	file_server * {
		root /www/prod
	}
}

3. The problem I’m having:

When I visit the page (127.0.0.1:12346) on my computer (which is running the container with caddy) I get this:

  • chrome:
This site can’t provide a secure connection
127.0.0.1 sent an invalid response.
ERR_SSL_PROTOCOL_ERROR
  • firefox:
Secure Connection Failed
An error occurred during a connection to 127.0.0.1:12346. Peer reports it experienced an internal error.
Error code: SSL_ERROR_INTERNAL_ERROR_ALERT
  • curl
curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error
  • wget https://127.0.0.1:12346 --no-check-certificate
--2023-02-04 10:58:50--  https://127.0.0.1:12346/
Connecting to 127.0.0.1:12346... connected.
GnuTLS: A TLS fatal alert has been received.
GnuTLS: received alert [80]: Internal error
Unable to establish SSL connection.

4. Error messages and/or full log output:

2023/02/04 04:16:13.076 INFO    using provided configuration    {"config_file": "/etc/caddy/Caddyfile", "config_adapter": "caddyfile"}
2023/02/04 04:16:13.078 INFO    admin   admin endpoint started  {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2023/02/04 04:16:13.079 INFO    http    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}
2023/02/04 04:16:13.079 INFO    http    enabling automatic HTTP->HTTPS redirects        {"server_name": "srv0"}
2023/02/04 04:16:13.079 INFO    tls.cache.maintenance   started background certificate maintenance      {"cache": "0xc000760850"}
2023/02/04 04:16:13.080 INFO    tls     cleaning storage unit   {"description": "FileStorage:/data/caddy"}
2023/02/04 04:16:13.080 INFO    tls     finished cleaning storage units
2023/02/04 04:16:13.093 WARN    pki.ca.local    installing root certificate (you might be prompted for password)        {"path": "storage:pki/authorities/local/root.crt"}
2023/02/04 04:16:13.094 INFO    not NSS security databases found
2023/02/04 04:16:13.094 INFO    define JAVA_HOME environment variable to use the Java trust
2023/02/04 04:16:13.143 INFO    certificate installed properly in linux trusts
2023/02/04 04:16:13.143 INFO    http    enabling HTTP/3 listener        {"addr": ":443"}
2023/02/04 04:16:13.143 INFO    failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 2048 kiB, got: 416 kiB). See https://github.com/lucas-clemente/quic-go/wiki/UDP-Receive-Buffer-Size for details.
2023/02/04 04:16:13.144 INFO    http.log        server running  {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2023/02/04 04:16:13.144 INFO    http.log        server running  {"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2023/02/04 04:16:13.144 INFO    http    enabling automatic TLS certificate management   {"domains": ["localhost", "127.0.0.1"]}
2023/02/04 04:16:13.144 INFO    autosaved config (load with --resume flag)      {"file": "/root/.config/caddy/autosave.json"}
2023/02/04 04:16:13.144 INFO    serving initial configuration
2023/02/04 04:16:13.144 INFO    tls.obtain      acquiring lock  {"identifier": "127.0.0.1"}
2023/02/04 04:16:13.144 INFO    tls.obtain      acquiring lock  {"identifier": "localhost"}
2023/02/04 04:16:13.145 INFO    tls.obtain      lock acquired   {"identifier": "localhost"}
2023/02/04 04:16:13.145 INFO    tls.obtain      lock acquired   {"identifier": "127.0.0.1"}
2023/02/04 04:16:13.146 INFO    tls.obtain      obtaining certificate   {"identifier": "localhost"}
2023/02/04 04:16:13.146 INFO    tls.obtain      obtaining certificate   {"identifier": "127.0.0.1"}
2023/02/04 04:16:13.148 INFO    tls.obtain      certificate obtained successfully       {"identifier": "127.0.0.1"}
2023/02/04 04:16:13.148 INFO    tls.obtain      certificate obtained successfully       {"identifier": "localhost"}
2023/02/04 04:16:13.148 INFO    tls.obtain      releasing lock  {"identifier": "127.0.0.1"}
2023/02/04 04:16:13.148 INFO    tls.obtain      releasing lock  {"identifier": "localhost"}
2023/02/04 04:16:13.148 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [127.0.0.1]: no OCSP server specified in certificate", "identifiers": ["127.0.0.1"]}
2023/02/04 04:16:13.148 WARN    tls     stapling OCSP   {"error": "no OCSP stapling for [localhost]: no OCSP server specified in certificate", "identifiers": ["localhost"]}

5. What I already tried:

  • On production I run same thing but I replace the localhost 127.0.0.1 { in caddy file with actual domains (this is how it runs on pruduction server) it gets certificates from lets encrypt and works properly (I of course persist /data folder of container on production, on testing I do not)

  • The localhost 127.0.0.1 { version that I use here doesn’t work for me. It is meant to be used locally during the development of the website. I expect it to generate self signed certificates on each start of container and then I was hoping I can click sth. like ignore self signed cert in the browser to continue. Instead I get cryptic error decribed in section 3 and I am not able to visit the website.

  • I tried to add:

{
	http_port 12345
	https_port 12346
}

at the beginning of Caddyfile and then run it like podman run -it -p 12345:12345 -p 12346:12346 website:latest thinking maybe internal/exposed ports number difference matters. It seems it doesn’t.

  • I tried to add:
	tls internal {
		on_demand
	}

same result except now I had to add nss-tools package into the container for caddy to run

  • tried to also forward 443/UDP by podman run -it -p 12345:80 -p 12346:443 -p 12346:443/udp website_testing:latest without any difference in results

  • curl http://127.0.0.1:12346 (calling https port with http) results in Client sent an HTTP request to an HTTPS server. reply from the server indicating that port forwarding etc. is working properly (there is connection to caddy server).

  • lot of google but seem to be running in circles or misunderstanding something here

6. Links to relevant resources:

Why not use the official Caddy Docker image instead? See Docker

Caddy generates its own certificate authority that it uses to issue certificates for local use. You need to install that CA’s root certificate to your system’s trust store. You can get it from Caddy’s storage location, i.e. /data/caddy/pki/authorities/local/root.crt

Caddy tries to automate installing the root CA cert, but it can’t do it from inside a container, because it’s obviously isolated from the host machine.

Well it is pretty much the same thing except it downloads caddy from "https://github.com/caddyserver/caddy/releases/download/v{{ .config.caddy_version }}/caddy_{{ .config.caddy_version }}_linux_${binArch}.tar.gz" instead of using package that alpine has already. I want to be able to customize it in the future easily as I will be adding lot of stuff.
Anyway it works flawlessly on production.

What I kind of expected is similar to what I am used to from other servers. In that case I generate the self signed certificate myself and configure the server to use it. Then browser displays warning about this but you are able to ignore it and continue to the site.

Is this not possible anymore? Getting that root certificate is the only way?

I tried curl --insecure -I https://127.0.0.1:12346 and wget https://127.0.0.1:12346 --no-check-certificate which should disable certificate checking… but still it doesn’t work

Tried to add tls /cert.pem /key.pem and use manually generated self signed cert as I would do with other SW and it loads those certificates successfully. Yet the error is the same when I visit the site.

It is possible, but the leaf certificates are very short-lived, so you’d have to do that ignoring the warning faff continuously.

Adding the root cert to your trust store is a one-time thing and will make it work for as long as you don’t wipe out Caddy’s storage.

This is a more secure approach than an actual self-signed cert (which is a private key that attests its own private key) because there’s no chain of trust and it’s not as representative of how things would run in “the real world”. Having a proper CA with a root → intermediate → leaf chain is more correct.

What do you mean by “doesn’t work”?

Turn on the debug global option in Caddy, it should show information about the handshake.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.