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
  • 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