{ unstablePkgs, ... }: let antiScrape = '' @bad_bot { header_regexp User-Agent "(?i)(scrapy|cpython-requests|python-requests|curl|wget|go-http-client|ltx71|petalbot|bytespider|dotbot|ahrefsbot|semrushbot|mj12bot|dataforseo|facebookexternalhit|claudebot|anthropic-ai|perplexity|gptbot|chatgpt-user|omnisci|imgproxy|ccbot|exabot|360spider|baiduspider|sogou|duckduckgo|amazonbot|cohere-ai|diffbot|imagesiftbot).*" } respond @bad_bot "" 444 header { X-Robots-Tag "noindex, nofollow, noai, noimageai" } ''; in { services.caddy = { enable = true; group = "caddy"; package = unstablePkgs.caddy; dataDir = "/var/lib/caddy"; logDir = "/var/log/caddy"; globalConfig = '' email jory@severijnse.eu servers { trusted_proxies static private_ranges } ''; # Global Caddyfile snippets (shared across all virtual hosts). extraConfig = '' (admin_gate) { @notvpn not remote_ip 10.8.0.0/24 respond @notvpn "Forbidden" 403 } # Security headers applied to every response of every site that # imports this snippet (covers all current and future hosts). # For proxied hosts whose upstream sets its own copies, strip them # with `header_down` inside the reverse_proxy block instead. (security_headers) { header { X-Content-Type-Options "nosniff" X-XSS-Protection "0" X-Frame-Options "SAMEORIGIN" } } (csp) { header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; connect-src 'self' wss: ws:" } ''; virtualHosts = { "severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} @logo path /logo.svg handle @logo { root * /srv file_server header Content-Type image/svg+xml header Cache-Control "public, immutable, max-age=31536000" header X-Content-Type-Options nosniff } handle { redir https://jory.severijnse.eu{uri} permanent } ''; }; "www.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} redir https://jory.severijnse.eu{uri} permanent ''; }; "jory.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} root * /srv/jory file_server try_files {path} /index.html encode zstd gzip header Strict-Transport-Security "max-age=31536000;" @robots path /robots.txt handle @robots { header Content-Type text/plain respond `User-agent: * Allow: / User-agent: Googlebot Allow: / User-agent: Bingbot Allow: / User-agent: Twitterbot Allow: / User-agent: facebookexternalhit Allow: / User-agent: GPTBot User-agent: ChatGPT-User User-agent: OAI-SearchBot User-agent: ClaudeBot User-agent: Claude-Web User-agent: anthropic-ai User-agent: PerplexityBot User-agent: Bytespider User-agent: Amazonbot User-agent: CCBot User-agent: Google-Extended User-agent: Applebot-Extended Disallow: / ` 200 } ''; }; "mta-sts.severijnse.eu" = { extraConfig = '' import security_headers import csp root * /srv file_server header Content-Type text/plain header Cache-Control "public, max-age=300" header X-Content-Type-Options nosniff ''; }; "vault.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} header Strict-Transport-Security "max-age=31536000;" reverse_proxy 127.0.0.1:1001 encode zstd gzip ''; }; "git.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} reverse_proxy 127.0.0.1:3000 encode zstd gzip ''; }; "mail.severijnse.eu" = { extraConfig = '' import security_headers ${antiScrape} # Bulwark webmail (JMAP client for Stalwart), running on host port 3002. reverse_proxy 127.0.0.1:3002 encode zstd gzip ''; }; "admin.mail.severijnse.eu" = { extraConfig = '' import security_headers ${antiScrape} # Stalwart webadmin UI (served by the http-management listener on 8080). reverse_proxy 127.0.0.1:8080 encode zstd gzip ''; }; "vpn.severijnse.eu" = { extraConfig = '' import security_headers import csp reverse_proxy 127.0.0.1:51821 encode zstd gzip ''; }; "mine.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} reverse_proxy 127.0.0.1:81 ''; }; "music.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} reverse_proxy 127.0.0.1:4321 ''; }; "fail2ban.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} import admin_gate reverse_proxy 127.0.0.1:8080 ''; }; "automate.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} import admin_gate reverse_proxy 127.0.0.1:5678 encode zstd gzip ''; }; "pay.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} import admin_gate reverse_proxy 127.0.0.1:5000 encode zstd gzip ''; }; "virtualcam.severijnse.eu" = { extraConfig = '' import security_headers import csp ${antiScrape} basic_auth { chan $2a$14$7ZeNpGT0L68uZwzdWBcF0OulzhrYbfAs232Ojt//LHQ1qvXU4x32O } reverse_proxy 127.0.0.1:3001 encode zstd gzip ''; }; "http://ip.severijnse.eu" = { extraConfig = '' import security_headers import csp header Content-Type text/plain respond {client_ip} 200 ''; }; }; }; systemd.tmpfiles.rules = [ "d /srv 0755 caddy caddy -" "d /srv/jory 0755 caddy caddy -" ]; }