Can't setup https with IP only and Docker

1. The problem I’m having:

Can’t setup https with IP only and Docker. It’s in internal home lab with no domain - so I hoped for self signed certifcate. Did I assume wrong that Caddy should generate one?

If I enter the shell of Caddy container I can access the site with curl semaphore:3000 - so it’s clear that container with semaphore works… but I must have messed reverse proxy part.

2. Error messages and/or full log output:

curl https://192.168.1.191
curl: (35) error:0A000438:SSL routines::tlsv1 alert internal error

and result of docker container logs caddy:

{"level":"info","ts":1732546634.4190912,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1732546634.4195745,"msg":"adapted config to JSON","adapter":"caddyfile"}
{"level":"info","ts":1732546634.4201424,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//localhost:2019","//[::1]:2019","//127.0.0.1:2019"]}
{"level":"info","ts":1732546634.4202983,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"warn","ts":1732546634.4203715,"logger":"pki.ca.local","msg":"installing root certificate (you might be prompted for password)","path":"storage:pki/authorities/local/root.crt"}
{"level":"info","ts":1732546634.4204824,"msg":"warning: \"certutil\" is not available, install \"certutil\" with \"apt install libnss3-tools\" or \"yum install nss-tools\" and try again"}
{"level":"info","ts":1732546634.4204848,"msg":"define JAVA_HOME environment variable to use the Java trust"}
{"level":"info","ts":1732546634.4216564,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000137400"}
{"level":"info","ts":1732546634.433842,"msg":"certificate installed properly in linux trusts"}
{"level":"info","ts":1732546634.4341884,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1732546634.4342983,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"info","ts":1732546634.4343116,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1732546634.4343133,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["192.168.1.191"]}
{"level":"warn","ts":1732546634.4344747,"logger":"tls","msg":"stapling OCSP","error":"no OCSP stapling for [192.168.1.191]: no OCSP server specified in certificate","identifiers":["192.168.1.191"]}
{"level":"info","ts":1732546634.4347458,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1732546634.4347525,"msg":"serving initial configuration"}
{"level":"info","ts":1732546634.436279,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"504f267a-7258-45bd-96cf-c59b0d7f67f2","try_again":1732633034.4362779,"try_again_in":86399.99999985}
{"level":"info","ts":1732546634.4363043,"logger":"tls","msg":"finished cleaning storage units"}

When entered shell of Caddy container I did some testing and I got:

curl -v https://localhost/acme/local/directory
* Host localhost:443 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
*   Trying [::1]:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS alert, internal error (592):
* TLS connect error: error:0A000438:SSL routines::tlsv1 alert internal error
* closing connection #0
curl: (35) TLS connect error: error:0A000438:SSL routines::tlsv1 alert internal error

3. Caddy version:

2.8.4

4. How I installed and ran Caddy:

Docker, with compose :

services:
  caddy:
    image: caddy:2.8.4
    restart: unless-stopped
    container_name: caddy
    cap_add:
      - NET_ADMIN
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - /home/uslugi/Caddyfile:/etc/caddy/Caddyfile:z
      - /home/uslugi/site:/srv:z
      - caddy_data:/data:z
      - caddy_config:/config:z
    networks:
      - caddynet

  mysql:
    restart: unless-stopped
    image: mysql:8.0
    hostname: mysql
    # I've removed the variables etc - they are not important in this case
    networks:
      - dbnet

  semaphore:
    restart: unless-stopped
    image: semaphoreui/semaphore:latest
    container_name: semaphore
    hostname: sempahore
    # I've removed env etc - do not matter
    depends_on:
      - mysql 
    networks:
      - caddynet
      - dbnet

volumes:
  semaphore-mysql: 
  caddy_data:
  caddy_config:

networks:
  dbnet:
    name: dbnet
    internal: true
  caddynet:
    name: caddynet
    driver: bridge

d. My complete Caddy config:

{
	default_sni 192.168.1.192
}

192.168.1.191 {
	tls internal
	reverse_proxy semaphore:3000
	file_server
}

Any suggestions howto make it work in home lab scenario?

These IPs do not match. So if you default SNI to .192 but Caddy only has a cert for .191, it won’t have one for your request.

If Docker has the userland TCP proxy enabled, then Caddy will not see the original remote IP address on the connection, so default_sni becomes necessary to server any valid cert.

I strongly recommend using a domain (like a free one), you get around this whole fundamental SNI issue.

Having both reverse_proxy and file_server without a matcher to separate them doesn’t make sense. Those are terminal handlers, so the first one in the directive order will run and shadow the other one making it useless.

1 Like

thank you, you’re a star!

That was it. As I’ve spent quite a bit of time digging through docs howto set it up, reading about SNI … and when it didn’t work I’ve been pretty sure I’ve messed it up there, overlooked a typo :rofl:.

As for domain - I get it, it would be nice. But this is in isolated vlan, where I don’t have access to outside world. I’ll learn a bit howto set up certificate in home lab network in due time.

Thx for pointing out the dangling file_server - it is remnant of the time where I’ve tested whether serving static sites work.

You can run a DNS server in your local network, and use that domain with Caddy. It doesn’t need to be a real domain, it can be like foo.internal. Configure your network to use that DNS server (on your router) instead of your ISP’s DNS. Then use tls internal in your Caddy sites to tell Caddy to issue the cert locally.

1 Like