nix-config/hosts/heather/caddy.nix

172 lines
6.1 KiB
Nix
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# heather — Caddy как единый edge (TLS termination, reverse proxy).
#
# Заменяет Traefik (k3s built-in, отключён) и старые Caddy на iscg-dev/jul11.
# Паттерн как на iscg-dev: system Caddy, конфиг декларативно в nix.
#
# Caddy терминирует TLS на :80/:443 и роутит по Host на:
# - host-сервисы (syncthing GUI на localhost:8384) — напрямую
# - docker-контейнеры (forgejo на localhost:3030 и т.д.) — проброшенные порты
#
# ACME: пока staging (чтобы не забанили Let's Encrypt пока DNS не переведён на
# heather). Когда A-записи iscg.dev → 51.250.45.111 — переключим на production
# (убрать acme_ca, Caddy использует production LE по умолчанию).
{ config, pkgs, lib, ... }:
let
# caddy/basic-auth под паролем. hash сгенерить:
# caddy hash-password --plaintext '<password>'
# (на heather: nix-shell -p caddy --run 'caddy hash-password ...')
# Защищает syncthing GUI снаружи (GUI слушает только 127.0.0.1:8384,
# Caddy проксирует sync.iscg.dev + basicauth).
syncBasicAuth = ''
basicauth {
mikl $2a$14$ozHN9/aa4VhPX43NN8MKdODKvOoJ5MBpOUFhzkxwvb58ZI5b6eqEK
}
'';
in {
services.caddy = {
enable = true;
# DNS переведён на heather (2026-07-12). Production ACME.
# Если нужен staging обратно: раскомментировать acmeCA ниже.
# acmeCA = "https://acme-staging-v02.api.letsencrypt.org/directory";
email = "mikl@iscg.dev";
virtualHosts = {
# --- Syncthing GUI (host-сервис) ---
# header_up Host 127.0.0.1:8384 — обходим syncthing host-check (DNS
# rebinding protection): syncthing сравнивает Host header с адресом
# прослушивания (127.0.0.1:8384) и отдаёт 403 "Host check error" для
# внешних доменов. Подменяем Host на бэкенде.
"sync.iscg.dev".extraConfig = syncBasicAuth + ''
reverse_proxy 127.0.0.1:8384 {
header_up Host 127.0.0.1:8384
}
'';
# --- Контейнеры (arion, см. arion-compose.nix) ---
# Forgejo
"git.iscg.dev".extraConfig = ''
handle /robots.txt {
header Content-Type text/plain
respond "User-agent: *
Allow: /" 200
}
reverse_proxy 127.0.0.1:3030
'';
# Matrix tuwunel (homeserver)
"iscg.dev".extraConfig = ''
# Static file sharing (https://iscg.dev/files/<name>).
# handle_path stripает /files/ prefix → file_server ищет в root.
# Не конфликтует с matrix (использует /_matrix/*, /.well-known/matrix).
handle_path /files/* {
root * /var/www/files
file_server
}
reverse_proxy 127.0.0.1:8008
encode zstd gzip
'';
# Matrix federation
"iscg.dev:8448".extraConfig = ''
reverse_proxy 127.0.0.1:8008
'';
# tuwunel-admin
"admin.iscg.dev".extraConfig = ''
reverse_proxy 127.0.0.1:8009
'';
# Cinny (matrix web client)
"chat.iscg.dev".extraConfig = ''
reverse_proxy 127.0.0.1:8080
encode zstd gzip
'';
# Jitsi Meet (Caddy v2 auto-handles WebSocket upgrade)
# Docs: https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker#running-behind-a-reverse-proxy
"jitsi.iscg.dev".extraConfig = ''
reverse_proxy 127.0.0.1:8000
'';
# Teable
"teable.iscg.dev".extraConfig = ''
reverse_proxy 127.0.0.1:2345
'';
# Silverbullet
"note.iscg.dev".extraConfig = ''
reverse_proxy 127.0.0.1:3001
'';
# Homepage (dashboard со всеми сервисами heather)
"home.iscg.dev".extraConfig = ''
reverse_proxy 127.0.0.1:3002
'';
# Public OAuth consent pages for the personal gcalcli application.
"gcalcli.iscg.dev".extraConfig = ''
root * /etc/gcalcli-site
try_files {path} {path}.html
file_server
encode zstd gzip
'';
# Retired control plane: keep TLS but never proxy to a daemon.
"paseo.iscg.dev".extraConfig = ''
header Cache-Control "no-store"
respond "Paseo has been retired" 410
'';
# Disabled pending isolation from the administrative account.
"jupyter.iscg.dev".extraConfig = ''
header Cache-Control "no-store"
respond "Jupyter is temporarily disabled" 503
'';
# Nick timer prototype. Public timer pages; creation has no auth for now.
"timer.michaotic.space".extraConfig = ''
reverse_proxy 127.0.0.1:8787
'';
# File explorer (directory listing) для раздачи файлов через браузер.
# browse включает Caddy's built-in directory listing. Корень /var/www/pub.
# Без auth — класть только публичные файлы.
"files.iscg.dev".extraConfig = ''
# Retired preview: landing and API live only on help2travel.ru.
@help2travel_preview path /help2travel /help2travel/*
handle @help2travel_preview {
respond 404
}
handle {
root * /var/www/pub
file_server browse
}
'';
# Help2Travel: static landing independent of the polling bot.
"help2travel.ru".extraConfig = ''
encode zstd gzip
header {
X-Content-Type-Options nosniff
Referrer-Policy strict-origin-when-cross-origin
Content-Security-Policy "default-src 'self'; base-uri 'none'; frame-ancestors 'none'; form-action 'self'"
}
handle /api/* {
reverse_proxy 127.0.0.1:8791 {
header_up X-Client-IP {remote_host}
}
}
handle {
root * /var/www/help2travel
file_server
}
'';
"www.help2travel.ru".extraConfig = ''
redir https://help2travel.ru{uri} permanent
'';
};
};
}