Caddy

Caddy

Basic install including Let's Encrypt and Cloudflare

docker-compose.yml

version: "3.7"

services:
  caddy:
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    cap_add:
      - NET_ADMIN
    ports:
      - "6443:443"
      - "6443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:Z
      - ./site:/srv:Z
      - ./data:/data:Z
      - ./config:/config:Z

Dockerfile

This will add the Cloudflare DNS module into the Caddy build. This module will allow Caddy to create the DNS records which lets Let's Encrypt issue the certificate.

FROM caddy:2-builder-alpine AS builder
RUN caddy-builder github.com/caddy-dns/cloudflare
FROM caddy:2
COPY --from=builder /usr/bin/caddy /usr/bin/caddy

Example site configuration

In your ./Caddyfile

https://site.mydomain.com {
    tls {
        dns cloudflare <DNS cloudflare token>
    }
    reverse_proxy internal_server.lan:3000
}

Make sure the internal server port is the same as the service you're wanting to expose to the internet.

Authentication with HTTP Basic Auth

If you want to use Basic Auth and have Bitwarden transparently log in, in the Caddyfile put the same username and password as will be used for the user login on the site:

https://securesite.mydomain.com {
    basic_auth {
        username password_hash
    }
    reverse_proxy internal_server.lan:3020
}

Then in Bitwarden, as long as one single password matches that site, it will transparently fill in the HTTP Basic Auth before taking you straight to the destination service's login screen.

Authenticating with mutual TLS

Generate your client certificate

This is a basic way to generate a certificate for a user. If it's only you using your own homelab, then you'll just need to make one certificate.

This certificate will last for ~10 years (although of course you can revoke it at any time by deleting it from Caddy's key store).

#!/bin/bash

mkdir -p certs

# Generate CA certificates
openssl genrsa -out certs/client-ca.key 4096
openssl req -new -x509 -nodes -days 3600 -key certs/client-ca.key -out certs/client-ca.crt

# Generate a certificate signing request
openssl req -newkey rsa:4096 -nodes -keyout certs/client.key -out certs/client.req

# Have the CA sign the certificate requests and output the certificates.
openssl x509 -req -in certs/client.req -days 3600 -CA certs/client-ca.crt -CAkey certs/client-ca.key -set_serial 01 -out certs/client.crt

echo
echo "Please enter a STRONG password. Many clients *require* a password for you to be able to import the certificate, and you want to protect it."
echo

# Convert the cerificate to PKCS12 format (for import into browser)
openssl pkcs12 -export -out certs/client.pfx -inkey certs/client.key -in certs/client.crt

# Clean up
rm certs/client.req

Configure Caddyfile

https://securesite.mydomain.com {
    tls {
        client_auth {
            mode require_and_verify
            trusted_ca_cert_file /data/client_certs/client.crt
        }
    }
    reverse_proxy internal_server.lan:3020
}
Share Note for Obsidian 🌓