Skip to content

caddy handout

installation

services:
    caddy:
        image: caddy:2.7.6
        container_name: caddy
        restart: unless-stopped
        labels:
            - "com.centurylinklabs.watchtower.enable=true"
        networks:
            - caddynet
        ports:
            - "80:80"
            - "443:443"
            - "443:443/udp" 
        volumes:
            - ./caddy/Caddyfile:/etc/caddy/Caddyfile
            - ./caddy/site:/srv # static files
            - ./wordpress:/var/www/html # for exec php files
            - caddy_data:/data
            - caddy_config:/config
        extra_hosts:
            - "host.docker.internal:host-gateway"
<DOMAIN.TLD> {
    file_server browse
}

<www.DOMAIN.TLD> {
    redir https://<DOMAIN.TLD>{uri}
}

<SUBDOMAIN.DOMAIN.TLD>  {
    reverse_proxy <CONTAINER:PORT>
}

<SUBDOMAIN.DOMAIN.TLD> {
    forward_auth <CONTAINER:PORT> {
        uri /api/verify?rd=https://<SUBDOMAIN.DOMAIN.TLD>
        copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    }
    reverse_proxy <CONTAINER:PORT>
}

<SUBDOMAIN.DOMAIN.TLD> {
    root * /var/www/html
    encode gzip
    php_fastcgi <CONTAINER.PORT>
    file_server
    log
}

<SUBDOMAIN.DOMAIN.TLD> {
    reverse_proxy <CONTAINER:PORT>
    basicauth {
        <USER> <HASHED PASSWORD>
    }
}

reloading caddyfile after change

docker compose exec -w /etc/caddy caddy caddy reload

how to mTLS

<domain.tld> {
    reverse_proxy <service>:<port>
    tls {
        client_auth {
            mode require_and_verify
            trust_pool file {
                pem_file /data/caddy/certs/mtls/ca.crt
            }
        }
    }
}

Note

trusted_ca_cert_file is deprecated with v2.8. use trust_pool instead

troubleshoot

check if port is accessible

docker exec -it caddy /bin/sh
curl -v <CONTAINER:PORT> OR curl -vk <CONTAINER:PORT>

if curl is not installed

apk add curl 

errorcodes

http status code cheatsheet
| status  | who messed up | desc              |
| ------- | ------------- | ----------------- |
| 1**     | hold on       | informational     |
| 2**     | here you go   | success           |
| 3**     | go away       | redirection       |
| 4**     | you messed up | client error      |
| 5**     | i messed up   | server error      |
logger=http.log.error msg=dial tcp IP:PORT: connect: connection refused ... status=502

trying access wrong port or caddy and the other container is not in the same network