I’ve done this a couple ways. Currently I’m doing it all through the docker-compose inside the wappler target, but previously I was building Caddy outside of Docker. I did so for one main benefit, Caddy would stay operational during a deploy so I could display a custom maintenance page. I don’t remember why I moved to moving it inside of the wappler target, but I need to get back to my original method as the maintenance page is quite nice to have.
My current setup is as follows. I should note that there are some redundancies in this setup; nothing that causes any problems, just haven’t tidied things up from when I was learning.
Dockerfile for caddy. This actually has 2 plugins; The first is to enable the use of labels within docker-compose, and the second allows for wildcard domains from digital ocean (there are other plugins for other dns providers.)
ARG CADDY_VERSION=2.6.4
FROM caddy:${CADDY_VERSION}-builder AS builder
RUN xcaddy build \
--with github.com/lucaslorentz/caddy-docker-proxy/v2 \
--with github.com/caddy-dns/digitalocean
FROM caddy:${CADDY_VERSION}-alpine
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
CMD ["caddy", "docker-proxy"]
The target docker-compose has a caddy service added:
caddy:
build:
context: ./caddy-build
dockerfile: Dockerfile
ports:
- 80:80
- 443:443
environment:
- CADDY_INGRESS_NETWORKS=caddy
networks:
- caddy
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- caddy_data:/data
restart: 'unless-stopped'
and then the web service in docker-compose uses labels to configure Caddy.
There are 3 request matchers that all point to the upstream port of 3000 (the node app). This is where the redundancy becomes clear as https://
will trump the wild card domain.
The https://
matcher allows literally any domain to connect and get a certificate, so it has an “ask” process which authorizes the use or not. In my case if the domain presented is properly activated in the app, then when let it through, otherwise, the request gets blocked.
labels:
caddy.email: "ken@uniqueideas.com"
caddy.on_demand_tls.ask: 'https://mealproapp.io/api/1/4/caddy/on_demand_tls_ask'
caddy.on_demand_tls.interval: '2m'
caddy.on_demand_tls.burst: '5'
caddy_0: 'https://'
caddy_0.tls.on_demand:
caddy_0.reverse_proxy: '{{upstreams 3000}}'
caddy_1: 'mealproapp.io'
caddy_1.reverse_proxy: '{{upstreams 3000}}'
caddy_2: '*.mealproapp.io'
caddy_2.reverse_proxy: '{{upstreams 3000}}'
caddy_2.tls.dns: 'digitalocean dop_v1_e39002REDACTED75ef8575a79c91f7f8c1'
Make sure to setup volumes and networks in the compose file as well to bring it all together.
networks:
...
caddy:
external: true
volumes:
...
caddy_data: {}