Caddy tls error in docker

1. Caddy version (caddy version):

Caddy version: v2.3.0.

2. How I run Caddy:

Caddy is runned as docker container.

a. System environment:


b. Command:

wget https:caddy:8080

Wget command returns same error like my express server via proxy.

c. Service/unit/compose file:

      context: api/
      - php
      - pwa
      PWA_UPSTREAM: pwa:3000
      SERVER_NAME: ${SERVER_NAME:-localhost}
      SERVER_NAME_API: ${SERVER_NAME_API:-api.localhost, caddy:8080}
    restart: unless-stopped
      - php_socket:/var/run/php
      - caddy_data:/data
      - caddy_config:/config
      # HTTP
      - target: 80
        published: 80
        protocol: tcp
      # HTTPS
      - target: 443
        published: 443
        protocol: tcp
      # HTTP/3
      - target: 443
        published: 443
        protocol: udp
      # API
      - target: 8080
        published: 8080
        protocol: tcp

d. My complete Caddyfile or JSON config:

    # Debug
    # HTTP/3 support
    servers {
        protocol {

# Matches requests for HTML documents, for static files and for

    reverse_proxy http://{$PWA_UPSTREAM}

    route {
        root * /srv/api/public
        mercure {
            # Transport to use (default to Bolt)
            transport_url {$MERCURE_TRANSPORT_URL:bolt:///data/mercure.db}
            # Publisher JWT key
            publisher_jwt {env.MERCURE_PUBLISHER_JWT_KEY} {env.MERCURE_PUBLISHER_JWT_ALG}
            # Subscriber JWT key
            subscriber_jwt {env.MERCURE_SUBSCRIBER_JWT_KEY} {env.MERCURE_SUBSCRIBER_JWT_ALG}
            # Allow anonymous subscribers (double-check that it's what you want)
            # Enable the subscription API (double-check that it's what you want)
            # Extra directives

        # Add links to the API docs and to the Mercure Hub if not set explicitly (e.g. the PWA)
        header ?Link `</docs.jsonld>; rel="", </.well-known/mercure>; rel="mercure"`

        # Comment the following line if you don't want Next.js to catch requests for HTML documents.
        # In this case, they will be handled by the PHP app.
        # reverse_proxy @pwa http://{$PWA_UPSTREAM}

        php_fastcgi unix//var/run/php/php-fpm.sock
        encode zstd gzip

3. The problem I’m having:

I’m trying to proxy requests in node.js server. I’m using express server.

  proxy(process.env.REACT_APP_API_ENTRYPOINT || 'https://caddy:8080', {
    limit: '100mb',
    proxyReqOptDecorator(opts) {
      // Remove in production
      const cookies = parseCookies(opts);
      opts.rejectUnauthorized = false;
      opts.headers['x-forward-host'] = process.env.REACT_APP_BASE_URI || 'https://localhost';
      opts.headers.cookie = '';
      delete opts.headers.cookie;
      if (cookies.token && cookies.token.length > 0)
        opts.headers.Authorization = `Bearer ${cookies.token}`;
      return opts;
    proxyErrorHandler: function(err, res, next) {
      console.log([err, res]);

4. Error messages and/or full log output:

Error: write EPROTO 140150939962696:error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error:…/deps/openssl/openssl/ssl/record/rec_layer_s3.c:1544:SSL alert number 80

5. What I already tried:

I have access from my local machine via https://api.localhost and https://localhost.
I can’t use api.localhost insight my node container, so that must be part ot docker network. That’s why I’m using caddy:8080.

6. Links to relevant resources:

You’re missing the // there. That’s not a valid URL.

I don’t see a volume for /etc/caddy/Caddyfile here. Are you copying in your Caddyfile at build time instead?

Caddy will try to issue a certificate from Let’s Encrypt or ZeroSSL for any domain that doesn’t look like localhost or *.localhost or is an IP address. Since caddy is a docker service name and not a public hostname, that will fail to get a publicly trusted certificate. So you’ll need to specify tls internal in your site to tell Caddy to issue a certificate from its own internal CA instead.

Thank you @francislavoie.
Sorry I have misspelled wget command in my post. Caddy file is just copy in caddy image. But I use exactly this one.
This issue is on development server. SSL certificates are self signed and my requests are comply with it.
Command on local machine with success.

wget --no-check-certificate https://api.localhost

Command in Node container is:

wget --no-check-certificate https://caddy:8080

Error that I receive is:

Connecting to caddy:8080 (
ssl_client: caddy: handshake failed: error:14094438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error
wget: error getting response: Connection reset by peer

That error show me that hostname is successfully located ( is docker network)

Yes, like I said, this is because Caddy cannot issue a certificate for the hostname caddy. That’s not a real domain. Please check your caddy container logs.

I didn’t know about caddy certificate. But if I perform http request another error occurs

Client sent an HTTP request to an HTTPS server

The solution for me was to turn off ssl for caddy host. In compose file SERVER_NAME_API: ${SERVER_NAME_API:-api.localhost, caddy:8080} to SERVER_NAME_API: ${SERVER_NAME_API:-api.localhost, http://caddy:8080}. There is no need for security in local docker network requests. Thanks again @francislavoie .

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