Files
serverAppConfigs/dankclaw/Caddyfile
T

236 lines
6.6 KiB
Caddyfile

# Homelab Caddyfile — the single Caddy for both hosts.
#
# Caddy runs as a container on dankclaw (192.168.0.143, this repo's
# compose.yaml service 'caddy') and fronts every service on both hosts:
# - dankclaw services: by container name (compose network) or by the
# published LAN port (quadlet services on isolated networks)
# - dankserver services (192.168.0.235): by published LAN port
#
# Naming: flat franksdank.cloud scheme (see docs/Infrastructure/LAN-DNS.md).
# DNS for these names is served by the Pi-hole quadlet on this host
# (dankclaw/pihole/addn-hosts — every name resolves to 192.168.0.143)
# and handed to LAN clients by the SURFboard G36 router.
#
# The basicauth hash below is a placeholder. deploy.sh renders the real
# hash (CADDY_BASICAUTH_HASH from the host .env, git-ignored) into
# /home/dank/Containers/caddy/Caddyfile, which the container mounts.
#
# TLS: real Let's Encrypt certs. Site addresses carry no http:// prefix,
# so Caddy serves HTTPS (and auto-redirects HTTP). Certs are wildcard
# (dns-01) via the global acme_dns block below, using the Porkbun module
# built into the franksdank/caddy-porkbun image (caddy/Containerfile).
# That needs no inbound ports and works from the LAN, where dnsmasq
# resolves these names to 192.168.0.143.
{
# Admin stays ON: it binds to 127.0.0.1:2019 inside the container and the
# port is not published, so nothing outside the container can reach it.
# It powers the config file watcher, so a rendered Caddyfile change
# hot-reloads without a container restart. 'admin off' once left a broken
# basicauth hash sitting on disk unapplied for hours (2026-08-22).
email admin@franksdank.cloud
# Solve ACME challenges for every site via Porkbun DNS (no port 80/443
# reachability needed). Credentials come from the container environment
# (compose.yaml, from the host .env — never committed).
acme_dns porkbun {
api_key {env.PORKBUN_API_KEY}
api_secret_key {env.PORKBUN_API_SECRET_KEY}
}
}
# --- Bare-IP access (health checks, convenience) ---
:80 {
redir https://dankclaw.franksdank.cloud/ 302
}
# --- Homepage (password protected) ---
dankclaw.franksdank.cloud {
root * /srv/homepage
# Operator-only admin page (Q19). Auth is checked on the original path,
# before any rewrite, so the path matcher is reliable. Caddy sorts a
# top-level 'rewrite' before 'basicauth'; that would change the path and
# break the path-based auth matchers. 'handle' preserves order.
handle /admin* {
basicauth {
frank REPLACE_WITH_ADMIN_HASH
}
try_files /admin.html
file_server
}
# Shared data + assets: the family OR the operator, so both pages can load
# them (the browser reuses the page's credential for these fetches). A
# 'handle' inline matcher is a single token, so the multi-path match is a
# named matcher.
@data path /services.json /status.json /app.js /style.css /deployed.js
handle @data {
basicauth {
dankuser REPLACE_WITH_HOMEPAGE_HASH
frank REPLACE_WITH_ADMIN_HASH
}
file_server
}
# Everything else (the user page): the homepage login (dankuser).
handle {
basicauth {
dankuser REPLACE_WITH_HOMEPAGE_HASH
}
try_files /index.html
file_server
}
}
# --- Legacy name: the media host has no Caddy of its own anymore ---
dankserver.franksdank.cloud {
redir https://dankclaw.franksdank.cloud/ 302
}
# ═══════════════════════════════════════════════════════════════
# Services on this host (dankclaw, 192.168.0.143)
# ═══════════════════════════════════════════════════════════════
# --- SearXNG (quadlet; behind the Gluetun tunnel, published 8081) ---
search.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy 192.168.0.143:8081
}
# --- ComfyUI ---
comfyui.franksdank.cloud {
reverse_proxy comfyui:8188
}
# --- OpenWebUI (quadlet on slirp4netns; published 3005) ---
chat.franksdank.cloud {
reverse_proxy 192.168.0.143:3005
}
# --- Hermes ---
hermes.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy hermes:8090
}
# --- Gitea (quadlet; published 3000) ---
gitea.franksdank.cloud {
reverse_proxy 192.168.0.143:3000
}
# --- Grafana ---
grafana.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy grafana:3000
}
# --- Prometheus ---
prometheus.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy prometheus:9090
}
# --- Loki ---
loki.franksdank.cloud {
reverse_proxy loki:3100
}
# --- Pi-hole (quadlet on slirp4netns; published 8083) ---
pihole.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy 192.168.0.143:8083
}
# ═══════════════════════════════════════════════════════════════
# Services on dankserver (192.168.0.235) — published LAN ports
# ═══════════════════════════════════════════════════════════════
# --- Plex (existing, kept) ---
# http:// on purpose: franksdank.casa is not hosted in the same Porkbun
# account as franksdank.cloud, so the DNS-01 provider cannot issue a
# Let's Encrypt cert for it. It stays plain-HTTP legacy; the canonical
# name is plex.franksdank.cloud (HTTPS, below).
http://plex.franksdank.casa {
reverse_proxy 192.168.0.235:32400
}
plex.franksdank.cloud {
reverse_proxy 192.168.0.235:32400
}
# --- Calibre-Web ---
books.franksdank.cloud {
reverse_proxy 192.168.0.235:8083
}
# --- RomM ---
romm.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy 192.168.0.235:8085
}
# --- Copyparty ---
files.franksdank.cloud {
basicauth {
dankuser REPLACE_WITH_HASH
}
reverse_proxy 192.168.0.235:3923
}
# --- Jellyfin ---
jellyfin.franksdank.cloud {
reverse_proxy 192.168.0.235:8096 {
transport http {
versions h2c 1.1
}
}
}
# --- *arr Stack ---
radarr.franksdank.cloud {
reverse_proxy 192.168.0.235:7878
}
sonarr.franksdank.cloud {
reverse_proxy 192.168.0.235:8989
}
lidarr.franksdank.cloud {
reverse_proxy 192.168.0.235:8686
}
readarr.franksdank.cloud {
reverse_proxy 192.168.0.235:8787
}
prowlarr.franksdank.cloud {
reverse_proxy 192.168.0.235:9696
}
qbittorrent.franksdank.cloud {
reverse_proxy 192.168.0.235:8080
}
# --- Optional: Jackett ---
# jackett.franksdank.cloud {
# reverse_proxy 192.168.0.235:9117
# }
# --- Optional: Whisparr ---
# whisparr.franksdank.cloud {
# reverse_proxy 192.168.0.235:6969
# }