Skip to content

Instantly share code, notes, and snippets.

@shawngmc
Last active March 7, 2024 02:53
Show Gist options
  • Save shawngmc/b5bb315f07a9fbedb499d0730bd98a5c to your computer and use it in GitHub Desktop.
Save shawngmc/b5bb315f07a9fbedb499d0730bd98a5c to your computer and use it in GitHub Desktop.
Caddy Example Files
[default]
aws_access_key_id=XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
aws_region=us-east-1
import sites/*.caddy
version: "3"
services:
caddy2:
build:
context: .
container_name: caddy2
volumes:
- './data/:/data'
- './config/:/config'
- './Caddyfile:/etc/caddy/Caddyfile'
- './sites/:/etc/caddy/sites/'
- './logs/:/logs/'
- './config/.aws-creds:/root/.aws/credentials'
ports:
- '55080:80'
- '55443:443'
restart: always
# Use the latest 2.x builder
FROM caddy:2-builder AS builder
# Build with plugins
# github.com/hairyhenderson/caddy-teapot-module - 418 I'm a Teapot/Lights-on test
# github.com/caddy-dns/route53 - Update R53 DNS records for Let's Encrypt Challenge
# TODO github.com/porech/caddy-maxmind-geolocation - Support limiting origin IP addresses to US
RUN xcaddy build \
--with github.com/caddy-dns/route53 \
--with github.com/hairyhenderson/caddy-teapot-module
# --with github.com/porech/caddy-maxmind-geolocation
# Overlay on the latest 2.x base image
FROM caddy:2
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
jellyfin.MYDOMAIN.com {
reverse_proxy * {
to 192.168.1.XXX:8096
header_down Set-Cookie ^.*$ "$0; Secure"
}
log {
output file /logs/jellyfin.json
}
tls {
dns route53 {
max_retries 10
}
}
encode {
zstd
}
header {
# disable FLoC tracking
Permissions-Policy interest-cohort=()
# enable HSTS
Strict-Transport-Security max-age=31536000;
# disable clients from sniffing the media type
?X-Content-Type-Options nosniff
# clickjacking protection
?X-Frame-Options DENY
# keep referrer data off of HTTP connections
?Referrer-Policy no-referrer-when-downgrade
}
}

A reverse proxy provides multiple benefits:

  • A reverse proxy can easily allow multiple services to be hosted by one IP address. When an HTTP request comes in, a reverse proxy can follow rules to determine what to do with the request (silently pass the request to another port on the same machine OR another machine, return an error, or even serve static content directly).
  • A reverse proxy can act as a single point of HTTPS (TLS) termination. Rather than set up HTTPS on every service you set up, you can make it so that they are only accessible through the reverse proxy, and the reverse proxy handles the cert (typically a wildcard, often from LetsEncrypt).
  • A reverse proxy can apply security settings - like HSTS, Clickjacking Protection headers, etc. - through all services that come through it.
  • A reverse proxy reduces the public footprint by making only one port externally accessible. You can quickly disable the proxy (or traffic forwarding to it) in case of an emergency.
  • A reverse proxy can enforce some simple authentication. For example, if you have a completely unprotected HTTP app, a proxy can provide basic HTTP authentication protection.

Personally, I use Caddy v2 for my homelab. I don't think it's perfect, but until I go full Kubernetes, it's pretty close. The Caddyfile format is simple (but not really machine editable). It makes HTTPS via LetsEncrypt very easy. I don't have a guide that I can easily link - maybe I should write one some day - but I can give you a quick example of my setup. Also, their getting started guide is a decent starting point.

I deploy Caddy as a docker container using docker-compose (see docker-compose.yml).

The volumes will need to be setup (data, config and logs are folders; the rest are specific files). Also, I port forward my router's 443 to 55443 (and 80 to 55080) since this machine is running another tool that needs 443. (GENERALLY, using multiple services on one machine, I find it useful to NOT use low numbered/defined ports unless there's a good reason). It's using a Dockerfileto build caddy with a couple plugins. This is their recommended Docker deploy method if using plugins.

I use Route53 DNS for a wildcard Let's Encrypt certificate. I have a regular DNS entry to forward to my local DNS, and an external tool that handles that. Caddy, however, gets a copy of the .aws-creds (see GH Gist).

Then, my basic Caddyfile is just in charge of telling it to look for more Caddyfiles.

Finally, each tool has a Caddyfile in the sites folder. For example, Jellyfin in jellyfin-example.caddy.

That Caddyfile applies a bunch of protection headers. I do this at the per-tool level since some headers may break some tools.

Finally, I deploy it with: sudo docker-compose up -d

Then, I update it with:

sudo docker-compose build
sudo docker-compose up -d

I can shut it down with:

sudo docker-compose down

If I just want to reload new sites, Caddy can do that without a full restart that breaks connections:

docker exec -it caddy2 caddy reload --config /etc/caddy/Caddyfile --adapter caddyfile

Note that this is a bit sloppy, since it relies on the container name; I should redo it to use the docker-compose config.

There's half-a-tutorial. :) I can answer questions if you'd like, but Nginx, Traefik, and Apache are all popular as reverse proxies as well.

@delanym
Copy link

delanym commented Mar 4, 2022

where's your teapot?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment