One great feature of caddy-docker-proxy is that you can quickly define config rules with Docker Compose labels in each containers on the fly like Traefik, instead of at a centralized place. With this feature, we can define everything in compose files, and don't ever need to mess with a config file (Caddyfile or JSON).
Taking advantage of snippets, I created this docker-compose.yaml
example so that you can quickly define routing rules and add authetication like Authelia with just 3 lines of labels below each docker container you use.
With this example, should not ever need to manually edit Caddyfile config.
When you add a new container, you just need to do this:
networks:
caddy_net:
external: true
services:
snapdrop:
image: linuxserver/snapdrop:latest
container_name: snapdrop
networks:
- caddy_net
restart: always
#π Magic happening below
labels:
caddy: drop.example.com #π Subdomain using wildcard cert
caddy.reverse_proxy: "{{upstreams 80}}" #π Container port
caddy.import: auth #π One-line enable Authelia
Now with auto_https prefer_wildcard option
merged, we get a even better config structure if wanting to use wildcard SSL certs for HTTPS.
To use wildcard certs, need to build a custom Docker image of Caddy with Cloudflare module (if that is you DNS nameserver) to handle DNS challenge.
Put this Dockerfile in the same directory as the Docker Compose file below.
ARG CADDY_VERSION=2
FROM caddy:${CADDY_VERSION}-builder AS builder
# no need the "v2.9.0-beta.2" part after new version release
RUN xcaddy build v2.9.0-beta.2 \
--with github.com/lucaslorentz/caddy-docker-proxy/v2 \
--with github.com/caddy-dns/cloudflare
FROM caddy:${CADDY_VERSION}-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
CMD ["caddy", "docker-proxy"]
Besure to modify to your info where indicated. Some examples are provided at the end.
EMAIL=your_email@example.com #π Your email for SSL cert
CF_API_TOKEN=your_cloudflare_api_token #π Get your token from Cloudflare
AUTH_HOST_INTERNAL=authelia:9091 #π Authelia container name and port
AUTH_HOST_EXTERNAL=auth.example.com #π Public facing domain of Authelia
# docker-compose.yaml
networks:
caddy_net: #βΉοΈ Caddy ingress network
name: caddy_net
ipam:
driver: default
services:
caddy:
container_name: caddy
build: .
restart: always
environment:
CADDY_INGRESS_NETWORKS: caddy_net
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./caddy/data:/data/caddy #π where to save SSL certs
- ./caddy/config:/config/caddy #π where to save configs
networks:
- caddy_net
ports:
- 80:80
- 443:443
extra_hosts:
- host.docker.internal:host-gateway
# to be continued below...
Before using, we need to configure Caddy itself first. This can be done purely with compose labels. We group labels with _numbers
as yaml keys must be unique. You can read more about Labels to Caddyfile conversion here.
While we CAN put these labels directly under the main container above, it is better to use a separate, lightweight container. As commented by @coandco, if we change any labels under the main container, Caddy has to be restarted and thus interrupt existing connections.
Personally, I use the traefik/whoami
image, which can double as a troubleshooting tool.
# docker-compose.yaml continued
caddy-config:
container_name: caddy-config
image: traefik/whoami:latest
networks:
- caddy_net
restart: always
labels:
#############################################
# Settings and snippets to get things working
# You shouldn't need to modify this normally
# Custom settings and definitions are below
#############################################
#### Global Settings ####
caddy_0.email: "{env.EMAIL}"
caddy_0.auto_https: prefer_wildcard
#### Snippets ####
# Get wildcard certificate
caddy_1: (wildcard)
caddy_1.tls.dns: "cloudflare {env.CF_API_TOKEN}"
caddy_1.tls.resolvers: 1.1.1.1 1.0.0.1
caddy_1.handle.abort: ""
# Secure a site with Authelia
caddy_2: (auth)
caddy_2.forward_auth: "{$$AUTH_HOST_INTERNAL}"
caddy_2.forward_auth.uri: /api/verify?rd=https://{$$AUTH_HOST_EXTERNAL}
caddy_2.forward_auth.copy_headers : Remote-User Remote-Groups Remote-Name Remote-Email
# Skip TLS verify for backend with self-signed HTTPS
caddy_3: (https)
caddy_3.transport: http
caddy_3.transport.tls: ""
caddy_3.transport.tls_insecure_skip_verify: ""
###########################################
# Custom settings. Modify things below π:
# Make sure they have unique label numbers
###########################################
# Custom global settings, add/edit as needed
# caddy_0.log: default
# caddy_0.log.format: console
# Uncomment this during testing to avoid hitting rate limit.
# It will try to obtain SSL from Let's Encrypt's staging endpoint.
# acme_ca: "https://acme-staging-v02.api.letsencrypt.org/directory" # π Staging
## Setup wildcard sites
caddy_10: "*.example.com" #π Change to your domain
caddy_10.import: wildcard
# Add our first site, which this container itself
caddy_99: whoami.example.com #π Subdomain using wildcard cert
caddy_99.reverse_proxy: "{{upstreams 80}}" #π Container port
caddy_99.import: auth #π Enable protection by Authelia
# to be continued below...
If we have some non-docker sites that need to be reverse proxied, we can also add their configs here:
# docker-compose.yaml continued
# e.g.: Pi-Hole on another machine in the same LAN
caddy_100: pihole.example.com #π Subdomain using wildcard cert
caddy_100.reverse_proxy: 192.168.1.4:88 #π LAN IP and port
caddy_100.import: auth #π Enable protection by Authelia
# e.g. OpenMediaVault on the host machine, with self-signed https at port 4430
caddy_101: omv.example.com #π Subdomain using wildcard cert
caddy_101.reverse_proxy: host.docker.internal:4430 #π Port on host machine
caddy_101.reverse_proxy.import: https #π Allow self-signed cert between OMV and Caddy
caddy_101.import: auth #π Enable protection by Authelia
Make sure Authelia is in the same network with Caddy. Add two labels under your existing Authelia compose:
networks:
caddy_net:
external: true
# ... other networks used by authelia ...
services:
authelia:
container_name: authelia
hostname: authelia
image: authelia/authelia:latest
networks:
- caddy_net
- #... other networks ...
expose:
- 9091
# ... the rest of your regular ...
# ... authelia compose here ...
# ...
# Add this:
labels:
caddy: auth.example.com #π Public facing subdomain of Authelia
caddy.reverse_proxy: "{{upstreams 9091}}" #π Authelia container port
Three labels! Just the subdomain, port and if you want Authelia.
networks:
caddy_net:
external: true
snapdrop:
image: linuxserver/snapdrop:latest
container_name: snapdrop
networks:
- caddy_net
restart: always
labels:
caddy: drop.example.com #π Subdomain
caddy.reverse_proxy: "{{upstreams 80}}" #π Container port
caddy.import: auth #π Authelia
The docker version of Caddy needs its admin endpoint internally for reload, and does not allow you to modify or expose it outside the container.
If you need it, such as for the Caddy widget of Homepage dashboard, you can expose this portion with the following labels for Caddy:
# docker-compose.yaml
# under caddy-config container
caddy_20: :2020
caddy_20.handle: /reverse_proxy/upstreams
caddy_20.handle.reverse_proxy: localhost:2019
caddy_20.handle.reverse_proxy.header_up: Host localhost:2019
And for your Homepage widget: (make sure they are on the same network)
# services.yaml
...
widget:
type: caddy
url: http://caddy:2020
More to come...
Please leave a β if this helps you!
What specific features are you using 2.9.0-beta2 for? Why have that over mainline 2.8.4?