Reverse proxy between 2 caddy containers with https

1. The problem I’m having:

Hello. I am currently working on implementing the following setup:
1 container with production frontend and api service (call it caddy-server)
2. container with monitoring caddy (caddy-monitor)
The intended functionality is that if the production container is down or have some issues, a “site maintenance” page should be displayed to site visitors.

Configuration works if I send http requests from caddy-monitor to caddy-server
i.e.
reverse_proxy caddy-server:80 on caddy-monitor config
and http://mysitecom { on caddy-server config
But there are some problems with http transfer and i’ts required to use https.
When I’m trying to use https between these instances, caddy-monitor couldn’t reach caddy-server because of tls error. I am seeking advice or solutions to fix this issue.

P.S. forum doesn’t allow to post sites url, so I deleted ‘.’ in mysitecom

2. Error messages and/or full log output:

{"level":"info","ts":1705048592.899819,"logger":"http.handlers.reverse_proxy.health_checker.active","msg":"HTTP request failed","host":"caddy-server:80","error":"Get \"https://caddy-server/\": remote error: tls: internal error"}
{"level":"info","ts":1705048601.8962085,"logger":"http.handlers.reverse_proxy.health_checker.active","msg":"HTTP request failed","host":"caddy-server:80","error":"Get \"https://caddy-server/\": remote error: tls: internal error"}

3. Caddy version:

2.7.5

4. How I installed and ran Caddy:

a. System environment:

Docker

b. Command:

docker compose -f docker-compose-monitor.yml up -d
docker compose up -d

c. Service/unit/compose file:

For caddy-server:

version: '3'

services:

    caddy:
      image: caddy:latest
      container_name: caddy-server
      restart: unless-stopped
 
      volumes:
        - ./configs/Caddyfile:/etc/caddy/Caddyfile
        - ./www/api:/var/www/html/api
        - ./www/front:/var/www/html/front
        - ./data:/data
        - ./configs:/config
      extra_hosts:
        - host.docker.internal:host-gateway
      links:
        - php81
      networks:
        - my_default

networks:
  my_default:
    external: true

For caddy-monitor:

version: '3'

services:
  caddy-monitor:
    image: caddy:latest
    container_name: caddy-monitor
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./configs/Caddyfile-monitor:/etc/caddy/Caddyfile
      - ./www/maintenance:/var/www/html/maintenance
      - ./data:/data # папка с сертификатами
      - ./configs:/config
      - ./www/api:/var/www/html/api
    networks:
      - my_default

networks:
  my_default:
    external: true

d. My complete Caddy config:

For caddy-server:

https://mysitecom {
    root * /var/www/html/front/public
    try_files {path} /index.html
    file_server *
    encode gzip zstd
}

https://api.mysitecom {
    root * /var/www/html/api/public
    php_fastcgi php81:9000
    file_server *
    encode gzip zstd
}

For caddy-monitor:

mysitecom {
    reverse_proxy {
        to caddy-server:443
        health_uri /
        health_interval 10s
        health_timeout 2s
        health_status 2xx
    }
    handle_errors {
        root * /var/www/html/maintenance
        file_server
    }
}

api.mysitecom {
    reverse_proxy {
        to caddy-server:443
    }
    handle_errors {
        root * /var/www/html/maintenance
        file_server
    }
}

5. Links to relevant resources:

Both containers are running in the same network, right? If so, you should be proxying between them over HTTP, not HTTPS.

The problem is that if you serve HTTPS from your app container, then it needs to be able to issue TLS certs, but since you put your monitor in front of it, it won’t be able to do that because the monitor would intercept incoming ACME challenge requests.

Also, proxying over HTTPS in your LAN has no security benefit, what’s important is that the connection over the open internet is encrypted, but once it’s in your network the risk is gone. HTTPS also adds some latency due to the TLS handshake, so it performs slightly worse than plain HTTP.

Make sure to configure the trusted_proxies global options on your app container so that it trusts requests coming from your monitor’s IP (or just trusts all private IP ranges) such that the original client IP is correctly passed through to your app.

If I leave config like this:

    reverse_proxy {
        to caddy-server:80
        health_uri /
        health_interval 10s
        health_timeout 2s
        health_status 2xx
    }
    handle_errors {
        root * /var/www/html/maintenance
        file_server
    }
}

and

http://mysitecom {
    root * /var/www/html/front/public
    try_files {path} /index.html
    file_server *
    encode gzip zstd
}

Not all of the resources would be loaded on the website.
Is there any option to disable tls on the second container? And may be to leave only “sitecom” (without http(s)://) on the second container?
I’ll try to use trusted_proxies if it’s a solution, thanks

What do you mean by this? Please be specific. What behaviour are you seeing, exactly?

Yes, just prefix each site address with http:// to disable TLS.

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