Caddy - zbrewer/homelab GitHub Wiki

Installation

Follow the install instructions on the Caddy website. The static binary method using the Cloudflare binary will be needed if a DNS ACME challenge with Cloudflare will be needed. The specific instructions for manual installation include steps to set up Caddy as a systemd service so it starts at boot.

Building with Xcaddy

Recently, the download for the static binary with the Cloudflare module hasn't been working. This affects not only fresh installs but also upgrades using the caddy upgrade command. Fortunately, the Caddy binary can be easily built using the xcaddy tool instead.

Do this by installing the golang package (apt install golang on Debian) and then following the xcaddy install instructions on Github.

Note, however, that if you are using the Cloudsmith repo instructions to install xcaddy you end up creating a .list file defining the repository. This is fine on Ubuntu and Debian versions before 13 but Debian 13 and later use the deb822 format (.sources) instead. The easiest way to make sure the new sources format is used (if the instructions have not been updated) is to run apt modernize-sources after /etc/apt/sources.list.d/caddy-xcaddy.list is created. This will create /etc/apt/sources.list.d/caddy-xcaddy.sources and move /etc/apt/sources.list.d/caddy-xcaddy.list to /etc/apt/sources.list.d/caddy-xcaddy.list.bak (which can be deleted). Now you can run apt update and apt install xcaddy as per the instructions.

Once xcaddy has been installed, create a new directory for building Caddy (such as caddy-build) and cd to that directory. Now run the following command to build Caddy with the Cloudflare module:

xcaddy build --with github.com/caddy-dns/cloudflare

The resulting caddy binary can be checked with ./caddy version and ./caddy list-modules before being copied to /usr/bin/caddy (per the normal install instructions).

Configuration

Changes made to the Caddyfile can be applied by running systemctl reload caddy. Cloudflare configuration instructions can be found on GitHub and general documentation can be found on the Caddy website. My specific config can be found here but the API key placeholder must be replaced by a valid Cloudflare API key before use.

Update

Run caddy upgrade to update. Is building with xcaddy, run xcaddy build --with github.com/caddy-dns/cloudflare to build a new version and replace the binary at /usr/bin/caddy with the newly built version. Run systemctl restart caddy to restart caddy using the new version.

Short Links

Short links let you type things like truenas/ in your browser URL bar in order to bring up your TrueNAS web interface.

Under the hood, this is http://truenas and it needs to be able to resolve to a host through DNS. Because it isn't a FQDN (there is no domain part) this can't be done with a simple DNS override. Instead, one of a few different options has to be used. This could be a browser plugin, editing the hosts file of your computer, etc. but I chose to do this by specifying a DNS search suffix. This is a DHCP setting that tells clients on the network to try certain suffixes when making DNS queries if the DNS query could not initially be resolved. In other words, the client will make a DNS query for truenas. When that can't be resolved, it will try truenas.brew.foo, assuming that brew.foo is configured as a search suffix. You can create a DNS A entry for truenas.brew.foo so this will now resolve to the IP address it is supposed to.

OPNsense, which is what I use as my primary firewall and router, requires that you specify a domain name that is used for your network. This is then used as the primary DNS search suffix advertised by your DHCP servers (unless you specifically override this). This is what often lets you use hostname in the URL bar to reach other local hosts. In my case, this is a different domain than the one I use for my reverse proxy/internal services in order to avoid name collisions. As a result, I need to be able to add to the list of DNS search suffixes advertised to clients. This can be done in your DHCP server by adding your desired domain to the Domain search list (or a similarly named setting) in your DHCP config. Make sure that your clients are using DHCP (potentially with a reservation instead of a static IP) and re-connect them to make sure they receive this setting correctly. Once they do (and you have an appropriately configured A record) you can make sure the name is correctly resolved by using nslookup from the command line. You can also use the chrome://net-internals/#dns page in Chrome (use that as your URL) to check DNS resolution within the browser.

Note that some clients (such as Android) do not respect DNS search suffixes so you may need a workaround (like using a VPN) to support short links.

If you would like short links to work over a Wireguard tunnel (a potential solution for short links on Android), you need to specify the search suffix as part of the Wireguard config. This is done as a comma separated list after the DNS server address as part of the DNS parameter. In other words, this might look like:

DNS = 10.0.10.10, brew.foo, another-domain.example

Once the short links are resolving to the correct host, make sure that your firewall is configured to allow HTTP (not just HTTPS) traffic to your Caddy instance. This is important because initial requests to Caddy will take the form http://truenas and therefore won't ever make it to Caddy if HTTP is not allowed.

At this point, you should be able to use the short link to hit Caddy but Caddy won't know what to do with it since the host is just truenas (instead of truenas.brew.foo). To address this, a host matcher needs to be added for the host truenas that redirects to truenas.brew.foo. This matcher should also match on HTTP (rather than trying to auto-redirect to HTTPS, the default Caddy behavior). See this forum thread for this solution. This looks like:

http://truenas {
   redir https://truenas.brew.foo
}

The {host} placeholder can also be used in the redirect statement and will be replaced by the hostname that matched. This allows you to handle multiple short links more compactly like in the following snippet:

http://truenas,
http://guacamole {
   redir https://{host}.brew.foo
}

Finally, if you want the path to be maintained, you can use the {uri} placeholder making this look like:

http://truenas,
http://guacamole {
   redir https://{host}.brew.foo{uri}
}

This will ensure that things like truenas/ui/dashboard will redirect to http://truenas.brew.foo/ui/dashboard. This is particularly important when using short links with a URL shortener (a.k.a "go links" so that go/foo can redirect to a preconfigured URL).

See my Caddyfile for an example of how I have this setup.