Caddy + SSL + Grafana

<< Deploying Grafana in Docker

Caddy Server is a lightweight reverse proxy with built in Let’s Encrypt support. It also has an awesome community behind it! For this guide we will be using Caddy v1 as a docker container since v2 is still currently in development.

This page will be re-written soon for Caddy v2.

STOP!
FOR THIS TO WORK YOU MUST OWN A DOMAIN AND HAVE IT POINTING AT YOUR WAN IP VIA YOUR DNS PROVIDER! ALSO YOUR ISP (Internet Service Provider) CAN’T BE BLOCKING PORT 80 AND PORT 443 INBOUND!

You will also need a static WAN IP or your DNS service needs to support DynDNS updates. This is out of the scope for this guide!

Caddy V2 has been released! If you use my image you will need to update to the v2 tag. Please see the CaddyV2 section below for a Grafana reverse_proxy config using CaddyV2.

First thing we will need to do is create our directory for the Caddyfile and support files.

SSH into your machine and run the following to create the directory.

# BASH [Linux VM]
mkdir /opt/containers/caddy && mkdir /opt/containers/caddy/certs && touch /opt/containers/caddy/Caddyfile

Now we need to pull the caddy image.

# BASH [Linux VM]
docker pull alexandzors/caddy:latest

We will be using the image I maintain, which is based off of the abiosoft/caddy-docker image. My image includes the following plugins that may come in handy down the road for your lab:

git,cors,realip,expires,cache,geoip,nobots,reauth,webdav,cloudflare,googlecloud,login,ipfilter

Copy the Caddy compose file from gist:

# BASH [Linux VM]
sudo curl https://bin.alexsguardian.net/raw/caddy-compose -o /opt/containers/caddy/caddy-compose.yml

If you are not using Cloudflare you can edit the compose file and remove the two lines in the environment section.

# BASH [Linux VM]
nano /opt/containers/caddy/caddy-compose.yml

# Remove these two lines in the compose file:
- CLOUDFLARE_EMAIL=${CFEMAIL}
- CLOUDFLARE_API_KEY=${CFAPIKEY}

Save CTRL+X then Y.


Port Forwarding

Caddy needs both port 80 (HTTP) and port 443 (HTTPS) in order to work correctly. In order for your machine to get traffic in from your WAN you will need to port forward these two ports in your router’s firewall.

Every router is different so you will have to look at your routers documentation for how to port forward. Usually its in the router’s firewall settings! Here is what it looks like in my EdgeRouter Lite’s dashboard as an example:


Configuration

Once we are finished getting everything setup, we need configure Caddy before we deploy it.

# BASH [Linux VM]
nano /opt/containers/caddy/Caddyfile

For this guide we will only be exposing Grafana to WAN, however you can setup Influx to also receive http traffic from WAN if you want to ingest data from WAN endpoints.

Paste the following into your Caddyfile:

# Lab subdomain
your.domain.tld {
        gzip
        tls [email protected]
        proxy / http://grafana_grafana_1:3000 {
                transparent
                websocket
        }
}

You will need to change the your.domain.tld to be your domain and tls [email protected] to your email. If you are using a dns plugin you’ll need to open a bracket for tls.

Save and close the file CTRL+X then Y.


Deploying Caddy

IMPORTANT: I recommend using the staging environment for Let’s Encrypt to try your config before you deploy it live if this is your first time! This will help you avoid being rate limited if something in your environment is mis-configured.

To use the staging environment you can pass -ca https://acme-staging-v02.api.letsencrypt.org/directory run arg to the Caddy container. Edit the compose file and add the following line for the container:

command: --conf /etc/Caddyfile --log stdout --agree=true -ca  https://acme-staging-v02.api.letsencrypt.org/directory

Should look like this:

Deploy Caddy with your testing config:

# BASH [Linux VM]
docker-compose -f /opt/containers/caddy/caddy-compose.yml up -d

If successful you should see the test certificate get generated in the container’s logs. docker logs -f caddy_caddy_1.

Once satisfied with your config you can remove the command: line from your compose file and re-deploy Caddy.

# BASH [Linux VM]
docker-compose -f /opt/containers/caddy/caddy-compose.yml down

# BASH [Linux VM]
docker-compose -f /opt/containers/caddy/caddy-compose.yml up -d

After deploying Caddy you can view the logs to verify that it is running. docker logs -f caddy_caddy_1. If it successfully obtained the certificate you should see something similar in your log view.

Grafana + Caddy

Once Caddy is deployed and working we can try and connect to Grafana via the domain you specified. In my case it would be https://lab.alexsguardian.net.

If you are unable to connect to Grafana you may have to edit the grafana.ini file so that Grafana can accept the incoming connections from Caddy.

# BASH [Linux VM]
nano /opt/containers/grafana/grafana.ini

Change the following lines under the Server section:

;domain = localhost
domain = your.domain.tld

;root_url = %(protocol)s://%(domain)s:%(http_port)s/
root_url = https://%domains/

Save and close the file CTRL+X then Y and restart Grafana:

# BASH [Linux VM]
docker restart grafana-grafana-1

Caddy V2 [Caddy] Configuration

Caddy V2 or Caddy as its supposed to be called, annoying I know, changed a lot of the background stuff. However, its actually still very easy to configure Caddy to reverse proxy Grafana. See the below code example of what your Caddyfile will look like for CaddyV2.

{
    email [email protected]
#    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
    default_sni hostname
    admin localhost:2019
}
grafana.yourdomain.tld {
        import header # This imports a custom header snippet. See Caddy docs for importing!
        import tls # This imports a custom header snippet. See Caddy docs for importing!
        log {
            output file /var/log/caddy/subdomain.log { # I recommend changing this log name to something easy to identify.
                roll_size 50mb
                roll_keep 2
                roll_keep_for 24h
            }
        }
        route * {
            reverse_proxy 192.168.9.2:3000
        }
}