Tricked.dev

My perfect caddy setup

So i wanted to setup serverside logging for my selfhosted applications to get some insights into what is used the most and how much bandwidth is being spent etc, i quickly found that goaccess is the best tool to get these insights.

I found the example from hectorm to be the main way to get started but it was missing some things, it didn’t log the hostname used and didn’t work with proxies like Cloudflare it was also quite boilerplate full to add more domains.

So i modified the config to add these features

{
   admin off
   auto_https disable_redirects

   log all {
      include http.log.access.all
      output file /var/log/caddy/access.log
      format transform `{request>host}:443 {:request>remote_ip} - {request>user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` {
        time_format "02/Jan/2006:15:04:05 -0700"
      }
  }
}


domain.com {
  log all
  reverse_proxy :3001
}
dash.domain.com {
  log all
  reverse_proxy :3001
}

This is already much better but i needed to get the real ip in my logs so i didn’t just see Cloudflare ips, this can be done in 2 ways:

  1. Manually read the headers for the x-forwarded-for header {request>headers>X-Forwarded-For>[0]:request>headers>Cf-Connecting-Ip>[0]:request>remote_ip}
  2. Add cloudflare to trusted proxies theres a module for that https://github.com/WeidiDeng/caddy-cloudflare-ip then just add the cloudflare ip to trusted proxies

But if you are like me and use cloudflare tunnel (cloudflared) you have to configure it to use using the trusted_proxies static private_ranges option https://caddyserver.com/docs/caddyfile/options#trusted-proxies.

Although i couldn’t get that method to work with the logger for some reason im guessing its cause of the usage of request>remote_ip instead of client_ip but i haven’t tried using client_ip yet.

After that i also wanted to get ssl certs for my domains using a letsencrypt and the cloudflare api. I did this by using https://github.com/caddy-dns/cloudflare and updated my config to use the api key

{
   log all { ... old stuff}

   acme_dns cloudflare <api key>
}

Now the ssl certs just work out of the box!, i can use caddy for internal and external use on the same server.

As a added bonus i configured Cloudflareds fallback to be localhost:80 and prefixed all my externals domains with http:// and disabled https redirects and cloudflared worked too now i just need to add a dns record pointing to the tunnel and update my caddyfile to add a new service.

My final config:

{
   admin off
   auto_https disable_redirects

   log all {
      include http.log.access.all
      output file /var/log/caddy/access.log
      format transform `{request>host}:443 {request>headers>X-Forwarded-For>[0]:request>headers>Cf-Connecting-Ip>[0]:request>remote_ip} - {request>user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` {
        time_format "02/Jan/2006:15:04:05 -0700"
      }
         }

   acme_dns cloudflare <api key>

   servers {
        trusted_proxies cloudflare
   }

}

example.domain.com {
  log all
  reverse_proxy :3001
}

dash.domain.com {
  log all
  reverse_proxy :3000
}


goaccess.domain.com {
  log all
  root * /var/www/goaccess/
  file_server * browse

  @websockets {
     header Connection *Upgrade*
     header Upgrade websocket
  }
  reverse_proxy @websockets :7890
}

:80, :443 {
  respond "Funny 404"
}

final docker-compose file

version: "3"
services:
  caddy:
    image: caddycloudflare
    build: .
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - ./logs:/var/log/caddy/
      - www:/var/www/goaccess/
    restart: unless-stopped
    network_mode: "host"

  goaccess:
    image: "docker.io/hectorm/goaccess:latest"
    restart: "unless-stopped"
    volumes:
      - "/etc/goaccess/goaccess.conf:/etc/goaccess/goaccess.conf:ro"
      - "www:/var/www/goaccess/"
      - "./logs:/var/log/caddy/:ro"
    ports:
      - 7890:443
    depends_on:
      - "caddy"
volumes:
  caddy_data:
  www:

I also made my own caddy Dockerfile to use with it

FROM caddy:builder AS builder

RUN caddy-builder \
    github.com/caddy-dns/cloudflare \
    github.com/WeidiDeng/caddy-cloudflare-ip \
    github.com/greenpau/caddy-security \
    github.com/caddyserver/transform-encoder
FROM caddy:latest

COPY --from=builder /usr/bin/caddy /usr/bin/caddy

As you might see i changed the port from goaccess to 443 this is cause the port is hardcoded based on your config. Here is my final goaccess config too

cat /etc/goaccess/goaccess.conf
addr 0.0.0.0
port 443
daemonize false
real-time-html true
time-format %H:%M:%S
date-format %d/%b/%Y
log-format VCOMBINED
log-file /var/log/caddy/access.log
output /var/www/goaccess/index.html

I put my config in /etc/goaccess/goaccess.conf cause it was easier for testing but feel free to keep it as in the hectorm’s example

If you liked this article consider supporting my work!
View on Github