Probably can't retrieve certificate due to rootless docker?

1. The problem I’m having:

I’ve got a Ubuntu VPS 24.04 LTS with one specific (non sudo) docker user.
Trying to run n8n + Caddy.
Seems like, both are starting, I could access n8n without SSL if my setup would permit it
But via SSL Caddy seems to have an issue with the non root user not being able to use the port 80 for the lets encrypt challenge?

2. Error messages and/or full log output:

docker logs docker_n8n_caddy-caddy-1 --follow
{"level":"info","ts":1741850418.0009544,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1741850418.0158513,"msg":"adapted config to JSON","adapter":"caddyfile"}
{"level":"warn","ts":1741850418.015906,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1741850418.0263596,"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":1741850418.0301542,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc000423680"}
{"level":"info","ts":1741850418.0303123,"logger":"http.auto_https","msg":"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}
{"level":"info","ts":1741850418.0303435,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1741850418.0398107,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1741850418.0411382,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 7168 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
{"level":"info","ts":1741850418.0488267,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"warn","ts":1741850418.0497804,"logger":"http","msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":80"}
{"level":"warn","ts":1741850418.049808,"logger":"http","msg":"HTTP/3 skipped because it requires TLS","network":"tcp","addr":":80"}
{"level":"info","ts":1741850418.0498164,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1741850418.0498245,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["sub.domain.de"]}
{"level":"info","ts":1741850418.0598736,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1741850418.0599236,"msg":"serving initial configuration"}
{"level":"info","ts":1741850418.0654612,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"238e316c-d863-450a-8064-0ed84fc8e2bf","try_again":1741936818.0654566,"try_again_in":86399.999998858}
{"level":"info","ts":1741850418.0656776,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1741850418.7169225,"msg":"got renewal info","names":["sub.domain.de"],"window_start":1746911385,"window_end":1747084185,"selected_time":1747048213,"recheck_after":1741872018.7169046,"explanation_url":""}
{"level":"info","ts":1741850418.727867,"logger":"tls","msg":"updated ACME renewal information","identifiers":["sub.domain.de"],"cert_hash":"91b60886f8b53b318e31935cfec842dd9a95f2426266398e5d6cd005b1ddb4da","ari_unique_id":"nytfzzwhT50Et-0rLMTGcIvS1w0.A6REcTqKutehTZPTM9FDyeD0","cert_expiry":1749588614,"selected_time":1746917787,"next_update":1741872018.7169046,"explanation_url":""}
{"level":"info","ts":1741850650.3075113,"msg":"shutting down apps, then terminating","signal":"SIGTERM"}
{"level":"warn","ts":1741850650.3077278,"msg":"exiting; byeee!! 👋","signal":"SIGTERM"}
{"level":"info","ts":1741850650.3077726,"logger":"http","msg":"servers shutting down with eternal grace period"}
{"level":"info","ts":1741850650.3096147,"logger":"admin","msg":"stopped previous server","address":"localhost:2019"}
{"level":"info","ts":1741850650.3096504,"msg":"shutdown complete","signal":"SIGTERM","exit_code":0}
{"level":"info","ts":1741890386.2823944,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1741890386.2913382,"msg":"adapted config to JSON","adapter":"caddyfile"}
{"level":"warn","ts":1741890386.2913914,"msg":"Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies","adapter":"caddyfile","file":"/etc/caddy/Caddyfile","line":2}
{"level":"info","ts":1741890386.3036993,"logger":"admin","msg":"admin endpoint started","address":"localhost:2019","enforce_origin":false,"origins":["//[::1]:2019","//127.0.0.1:2019","//localhost:2019"]}
{"level":"info","ts":1741890386.3052886,"logger":"http.auto_https","msg":"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}
{"level":"info","ts":1741890386.30532,"logger":"http.auto_https","msg":"enabling automatic HTTP->HTTPS redirects","server_name":"srv0"}
{"level":"info","ts":1741890386.3062701,"logger":"tls.cache.maintenance","msg":"started background certificate maintenance","cache":"0xc00053a300"}
{"level":"info","ts":1741890386.3130255,"logger":"http","msg":"enabling HTTP/3 listener","addr":":443"}
{"level":"info","ts":1741890386.313803,"msg":"failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 7168 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details."}
{"level":"info","ts":1741890386.3180363,"logger":"http.log","msg":"server running","name":"srv0","protocols":["h1","h2","h3"]}
{"level":"warn","ts":1741890386.3184295,"logger":"http","msg":"HTTP/2 skipped because it requires TLS","network":"tcp","addr":":80"}
{"level":"warn","ts":1741890386.3184404,"logger":"http","msg":"HTTP/3 skipped because it requires TLS","network":"tcp","addr":":80"}
{"level":"info","ts":1741890386.3184445,"logger":"http.log","msg":"server running","name":"remaining_auto_https_redirects","protocols":["h1","h2","h3"]}
{"level":"info","ts":1741890386.3184495,"logger":"http","msg":"enabling automatic TLS certificate management","domains":["sub.domain.de"]}
{"level":"info","ts":1741890386.3258567,"msg":"autosaved config (load with --resume flag)","file":"/config/caddy/autosave.json"}
{"level":"info","ts":1741890386.3259673,"msg":"serving initial configuration"}
{"level":"info","ts":1741890386.3278253,"logger":"tls","msg":"storage cleaning happened too recently; skipping for now","storage":"FileStorage:/data/caddy","instance":"238e316c-d863-450a-8064-0ed84fc8e2bf","try_again":1741976786.3278193,"try_again_in":86399.999999109}
{"level":"info","ts":1741890386.3282108,"logger":"tls","msg":"finished cleaning storage units"}
{"level":"info","ts":1741890387.8875897,"msg":"got renewal info","names":["sub.domain.de"],"window_start":1746911385,"window_end":1747084185,"selected_time":1747048699,"recheck_after":1741911987.8875663,"explanation_url":""}
{"level":"info","ts":1741890387.8961806,"logger":"tls","msg":"updated ACME renewal information","identifiers":["sub.domain.de"],"cert_hash":"91b60886f8b53b318e31935cfec842dd9a95f2426266398e5d6cd005b1ddb4da","ari_unique_id":"nytfzzwhT50Et-0rLMTGcIvS1w0.A6REcTqKutehTZPTM9FDyeD0","cert_expiry":1749588614,"selected_time":1746917787,"next_update":1741911987.8875663,"explanation_url":""}

On the browser I get this:
In Chrome ERR_CONNECTION_REFUSED
In Firefox: Error code: PR_END_OF_FILE_ERROR

I’ve tried:
http://sub.domain.de
https://sub.domain.de
https://sub.domain.de:443
https://sub.domain.de:8443

3. Caddy version:

Maybe v2.9.1?

4. How I installed and ran Caddy:

My docker compose yml looks simple enough:

services:
  caddy:
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:8080"
      - "443:8443"
    volumes:
      - ./caddy_storage:/data
      - ${DATA_FOLDER}/caddy_config:/config
      - ${DATA_FOLDER}/caddy_config/Caddyfile:/etc/caddy/Caddyfile

  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: always
    ports:
      - 5678:5678
    environment:
      - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
      - N8N_PORT=5678
      - N8N_PROTOCOL=https
      - NODE_ENV=production
      - WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
      - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
      # Enable authentication
      - N8N_BASIC_AUTH_ACTIVE=true
      - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
      - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
      # Secure credentials with encryption
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      # Disable the public API https://docs.n8n.io/hosting/securing/disable-public-api/
      - N8N_PUBLIC_API_DISABLED=true
      - N8N_PUBLIC_API_SWAGGERUI_DISABLED=true
      # Disable data collection https://docs.n8n.io/hosting/securing/telemetry-opt-out/#collected-data
      - N8N_DIAGNOSTICS_ENABLED=false
      - N8N_VERSION_NOTIFICATIONS_ENABLED=false
      - N8N_TEMPLATES_ENABLED=false
    volumes:
      - n8n_storage:/home/node/.n8n
      - ${DATA_FOLDER}/local_files:/files

a. System environment:

Ubuntu 24.04 LTS
Docker (rootless)

b. Command:

 docker compose up -d

c. Service/unit/compose file:

See above

d. My complete Caddy config:

sub.domain.de {
    reverse_proxy n8n:5678 {
      flush_interval -1
    }


    tls {
        issuer acme {
            alt_http_port 8080
            alt_tlsalpn_port 8443
        }
    }
}

5. Links to relevant resources:

I’m not very technical when it comes to docker / sys admin / reverse proxy.
I’ve seen that there is a DNS challenge alternative. If anyhow possible, I’d like to use a simple approach.
I was hoping that the issuer acme in the config would already solve this issue?

Why do you need to bind port 80 on the host machine to port 8080 in the container? I’m not sure if you mean to do it this way due to a misunderstanding or something. Anyway, if Caddy is obtaining the certificate through port 8080 in the container as you’ve configured with your Caddyfile, your configuration means Caddy still doesn’t know that it’s supposed to listen on port 8443 in the container for serving HTTPS instead of 443. You would need to modify the http_port and https_port global option.

{
    http_port 8080
    https_port 8443
}

sub.domain.de {
    reverse_proxy n8n:5678 {
      flush_interval -1
    }


    tls {
        issuer acme {
            alt_http_port 8080
            alt_tlsalpn_port 8443
        }
    }
}

It finally worked, thank you very much.

1 Like