HTTPS for Homelab

When I wanted to install bitwarden_rs (now vaultwarden), i read their wiki and got struck with an idea to setup my homelab apps behind https.

Then the hunt for reverse proxies started and i settled down with caddy after trying out nginx and traefik (both are good, but not suitable for my usecase). Caddy is a simple configurable reverse proxy and webserver. I use it as reverse proxy and HTTPS provider for all my homelab apps. I have found the configuration is much easier compared to other reverse proxies out there.

Caddy will serve all content using HTTPS by default with its self signed SSL certificates. But i have found that all browsers do not play well and throw a warning. To make the browsers trust the self-signed SSL, you need to add the root certificate to the respective OS and browser cert store. It is very difficult to do it manually, especially for mobile devices. So I use letsencrypt wilcard certificate from my unused domain for homelab.

Letsencrypt will issue a free ssl certificate which is trusted by all browsers. You have to prove the domain ownership to letsencrypt, that’s where http and DNS challenge comes into play. Read more about it here.

By default the caddy binary does not have cloudflare-dns plugin for acme DNS challenge. This is important because all my homelab services are not exposed to internet and there is no way http challenge will work.

xcaddy is tool for compiling and installing caddy from source. (please note that this tool is still under development, but i have found it to be working without any issue)

Please note that to proceed you should have a VM or Container for playing around. I have a dedicated ubuntu container running for reverse proxy.

Downoad and Install Go

Go language is needed for compiling and installing caddy.

## download go https://golang.org/doc/install
wget https://golang.org/dl/go1.16.3.linux-amd64.tar.gz

## extract
sudo tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz

## add PATH env variable 
export PATH=$PATH:/usr/local/go/bin

## reboot check if go is installed
go version

Version is 1.16.3 as of writing this, so please change accordingly.

Download and install xcaddy

Proceed to latest xcaddy releases page and download the *.deb package. Version is 0.1.9 as of writing this, so please change accordingly.

wget https://github.com/caddyserver/xcaddy/releases/download/v0.1.9/xcaddy_0.1.9_linux_arm64.deb

sudo dpkg -i xcaddy_0.1.9_linux_arm64.deb

Other install methods are also listed in the github page.

Build Caddy with optional plugins

We have downloaded pre-requesites and now we will build caddy with cloudflare-dns plugin. I have added webdav just for this tutorial purpose, feel free to delete it if you are not using it. There are many other plugins, please search and feel free to include the ones you like.

xcaddy build \
    --with github.com/caddy-dns/cloudflare
    --with github.com/mholt/caddy-webdav

The above command will download the caddy source and compile and create a caddy binary in the folder where you run the command.

Starting caddy service

The compiled binary file needs to be moved to correct location and a service files needs to be created.

Create a file /etc/systemd/system/caddy.service with the following contents.

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
User=caddy
Group=caddy
ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

Be sure to chmod 644 the above file. create a user and group named caddy

sudo chmod 644 /etc/systemd/system/caddy.service

sudo groupadd --system caddy
sudo useradd --system --gid caddy caddy

Move the compiled binary to /usr/local/bin/caddy

sudo chown root:root /usr/local/bin/caddy
sudo chmod 755 /usr/local/bin/caddy

Caddyfile

Create a Caddyfile in /etc/caddy/Caddyfile. The following is an example configuration, and complete options and configuration can be checked in official docs.

*.homelab.tld {

  tls YOUR_EMAIL
  tls {
     dns cloudflare API_KEY
  }

  @app1 host app1.homelab.tld
  @app2 host app2.homelab.tld
   
  handle @app1 {
     reverse_proxy 192.168.1.10:4000
  }
   
  handle @app2 {
     reverse_proxy 192.168.1.11:3000
  }
  
  log {
     output file /var/log/caddy/access.log {
        roll_size 10mb
        roll_keep 5
        roll_keep_for 24h
     }
  }
}

The above example assumes homelab.tld domain DNS records are managed by cloudflare. When starting caddy it does ACME DNS challenge using the cloudflare DNS plugin to verify the domain ownership and then gets a wildcard SSL certificate from letsencrypt automatically.

Reference

  1. https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148
  2. https://www.digitalocean.com/community/tutorials/how-to-host-a-website-with-caddy-on-ubuntu-18-04
  3. https://www.linode.com/docs/guides/compile-caddy-from-source/
  4. https://caddyserver.com/docs/caddyfile/directives/tls

For more adventure, try your own CA.

https://smallstep.com/blog/build-a-tiny-ca-with-raspberry-pi-yubikey/