Caddy
Caddy Proxy with DNS-01 certs
caddy/Dockerfile
# the different stages of this Dockerfile are meant to be built into separate images # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage # https://docs.docker.com/compose/compose-file/#target # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact ARG CADDY_VERSION=2 # ------------------------------------- # Caddy Build FROM caddy:${CADDY_VERSION}-builder-alpine AS caddy_builder RUN xcaddy build \ --with github.com/caddy-dns/route53 # --with github.com/greenpau/caddy-security \ # --with github.com/greenpau/caddy-trace # ------------------------------------- # Caddy Run FROM caddy:${CADDY_VERSION}-alpine COPY --from=caddy_builder /usr/bin/caddy /usr/bin/caddy # COPY docker/caddy/Caddyfile /etc/caddy/Caddyfile
caddy/Caddyfile
# The Caddyfile is an easy way to configure your Caddy web server. # # Unless the file starts with a global options block, the first # uncommented line is always the address of your site. # # To use your own domain name (with automatic HTTPS), first make # sure your domain's A/AAAA DNS records are properly pointed to # this machine's public IP, then replace the line below with your { admin off debug log { output stdout format json } } (theheaders) { header_up X-Forwarded-Ssl on header_up Host {http.request.host} header_up X-Real-IP {http.request.remote} header_up X-Forwarded-Host {http.request.host} header_up X-Forwarded-Port {http.request.port} header_up X-Url-Scheme {http.request.scheme} } {$THE_SERVER_NAME} { tls { dns route53 { max_retries 10 } } encode zstd gzip root * /usr/share/caddy file_server } grafana.{$THE_SERVER_NAME} { tls { dns route53 { max_retries 10 } } encode zstd gzip reverse_proxy grafana:3000 { import theheaders } } prometheus.{$THE_SERVER_NAME} { tls { dns route53 { max_retries 10 } } encode zstd gzip reverse_proxy prometheus:9090 { import theheaders } } alerts.{$THE_SERVER_NAME} { tls { dns route53 { max_retries 10 } } encode zstd gzip reverse_proxy alertmanager:9093 { import theheaders } } up.{$THE_SERVER_NAME} { tls { dns route53 { max_retries 10 } } encode zstd gzip reverse_proxy up:3001 { import theheaders } } # Refer to the Caddy docs for more information: # https://caddyserver.com/docs/caddyfile
caddy/static/index.html
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Jump Page</title> <meta name="description" content="Desktop App"> <meta name="author" content="Myron Overton"> </head> <body> <h1>Monitoring</h1> <ul> <li><a href="https://up.mon.int.x.com/">Uptime Kuma</a></li> <li><a href="https://grafana.mon.int.x.com/">Grafana</a></li> <li><a href="https://prometheus.mon.int.x.com/">Prometheus</a></li> <li><a href="https://alerts.mon.int.x.com/">Alerts</a></li> </ul> <hr> <h2><a href="https://nmpf.atlassian.net/wiki/spaces/NF/pages/154x5/Server+List">Full Server List</a></h2> </body> </html>
docker-compose.yml
version: '3' services: caddy: build: context: caddy dockerfile: ./Dockerfile image: caddy-secure:1.0.0 container_name: caddy_local env_file: - .env environment: - AWS_REGION=us-west-1 - AWS_ACCESS_KEY_ID=${DNS_AWS_ACCESS_KEY_ID:-} - AWS_SECRET_ACCESS_KEY=${DNS_AWS_SECRET_ACCESS_KEY:-} - THE_SERVER_NAME=${THE_SERVER_NAME:-} hostname: caddy ports: - 0.0.0.0:80:80 - 0.0.0.0:443:443 # - 0.0.0.0:2019:2019 volumes: - ./caddy/Caddyfile-local:/etc/caddy/Caddyfile - ./caddy/static:/usr/share/caddy - ./data/caddy:/data/caddy restart: unless-stopped grafana: container_name: grafana hostname: grafana image: grafana/grafana:9.3.2 restart: unless-stopped # networks: # - default # - loki environment: - GF_ROOT_URL=https://grafana.${THE_SERVER_NAME} - GF_INSTALL_PLUGINS=grafana-piechart-panel,grafana-clock-panel,briangann-gauge-panel,natel-plotly-panel,grafana-simple-json-datasource volumes: - ./grafana/grafana.ini:/etc/grafana/grafana.ini - data-grafana:/var/lib/grafana up: image: louislam/uptime-kuma:1.23.15-alpine volumes: - ./data/uptime:/app/data restart: unless-stopped # ------------------------------------- volumes: data-grafana: data-caddy: # -------------------------------------
DNS Challenge
Dockerfile example
# the different stages of this Dockerfile are meant to be built into separate images # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage # https://docs.docker.com/compose/compose-file/#target # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact ARG CADDY_VERSION=2 FROM caddy:${CADDY_VERSION}-builder-alpine AS caddy_builder RUN xcaddy build \ --with github.com/caddy-dns/route53 # --with github.com/greenpau/caddy-security \ # --with github.com/greenpau/caddy-trace FROM caddy:${CADDY_VERSION}-alpine COPY --from=caddy_builder /usr/bin/caddy /usr/bin/caddy
Enable compression in Caddy
- enable br?
encode zstd gzip caddy reload --config /etc/caddy/Caddyfile dc run --rm --service-ports caddy sh caddy run --config /etc/caddy/Caddyfile --adapter caddyfile
Auth
https://github.com/greenpau/caddy-security - Auth Portal and Authorize Plugins for Caddy
Running non-root
Kubernetes
- https://github.com/caddyserver/ingress - Kubernetes Ingress Controller for Caddy
Examples
Replacing nginx with caddy
omg.dje.li { root /path/to/caddy/omg.dje.li log /path/to/caddy/logs/omg.dje.li-access.log { rotate { age 7 # Keep log files for 14 days keep 10 # Keep at most 10 log files } } gzip header / Strict-Transport-Security "max-age=31536000" tls { dns route53 } git { repo git@<internal.gitlab.host>:<username>/<repo>.git key /path/to/caddy/.ssh/id_rsa then git submodule update --init then hugo --destination=/path/to/caddy/omg.dje.li --baseURL https://omg.dje.li hook /hidden_webhook_location secret-password-which-is-not-this } }
Check token/cookie
my.webservice { tls /etc/letsencrypt/my.webservice.fullchain /etc/letsencrypt/my.webservice.key @headerfilter { not header Cookie *mytoken=somevalue* not query mytoken=somevalue } respond @headerfilter 403 reverse_proxy my.webservice:8080 { header_down +Set-Cookie "mytoken=somevalue; Path=/" } }
Whoami Service
whoami: image: containous/whoami networks: - caddy labels: caddy: whoami.example.com caddy.reverse_proxy: "{{upstreams 80}}"
Reverse Proxies
# The Caddyfile is an easy way to configure your Caddy web server. # # Unless the file starts with a global options block, the first # uncommented line is always the address of your site. # # To use your own domain name (with automatic HTTPS), first make # sure your domain's A/AAAA DNS records are properly pointed to # this machine's public IP, then replace the line below with your { debug log { output stdout format json } } # header_up X-Forwarded-For {http.request.remote} (theheaders) { header_up X-Forwarded-Ssl on header_up Host {http.request.host} header_up X-Real-IP {http.request.remote} header_up X-Forwarded-Port {http.request.port} header_up X-Forwarded-Proto {http.request.scheme} header_up X-Url-Scheme {http.request.scheme} header_up X-Forwarded-Host {http.request.host} } host.domain.com { encode zstd gzip handle_path /path_to_strip/* { reverse_proxy https://172.x.x.x { header_up Host "subhost.n.com" header_up X-Forwarded-Host "subhost.n.com" transport http { tls_server_name "subhost.n.com" } } } handle { reverse_proxy https://apache:443 { import theheaders transport http { tls_server_name "host.domain.com" } } } } # Refer to the Caddy docs for more information: # https://caddyserver.com/docs/caddyfile
Monitor
- https://github.com/alexandre-daubois/ember - Real-time terminal dashboard for Caddy servers