{ config, lib, pkgs, homeyConfig, ... }: # Cloudflare Tunnel (cloudflared) — remote access without open inbound ports. # # Architecture: # Internet → Cloudflare edge → cloudflared tunnel (outbound from Pi) # → Caddy on localhost → service containers # # The tunnel is configured to route each hostname to Caddy's HTTPS listener. # Caddy handles TLS and forward_auth; cloudflared just carries the traffic. # # Setup steps (one-time, done from the Cloudflare dashboard): # 1. Go to Zero Trust → Networks → Tunnels → Create a tunnel # 2. Name it (e.g. "pi-main") # 3. Copy the tunnel token — add it to secrets.yaml as cloudflare/tunnel_token # 4. In the tunnel's "Public Hostnames" config, add routes: # auth.home.zakobar.com → http://localhost:80 (or https://localhost:443) # git.home.zakobar.com → https://localhost:443 # nextcloud.home.zakobar.com → https://localhost:443 # ldapadmin.home.zakobar.com → https://localhost:443 # jellyfin.home.zakobar.com → https://localhost:443 # torrent.home.zakobar.com → https://localhost:443 # Set "No TLS Verify" = true (Caddy's cert is from Let's Encrypt but # the hostname seen by cloudflared is localhost, so hostname verification # would fail without this flag). # # The tunnel_token approach (--token) is the simplest: one secret, no config # file needed on the Pi. # # Secrets consumed from sops: # cloudflare/tunnel_token let cfg = config.homey.cloudflared; in { options.homey.cloudflared = { enable = lib.mkEnableOption "Cloudflare Tunnel for remote access"; }; config = lib.mkIf cfg.enable { # ----------------------------------------------------------------------- # Secrets # ----------------------------------------------------------------------- sops.secrets."cloudflare/tunnel_token" = { owner = "cloudflared"; }; # ----------------------------------------------------------------------- # cloudflared service # NixOS 24.11 ships services.cloudflared natively. # ----------------------------------------------------------------------- services.cloudflared = { enable = true; tunnels = { "pi-main" = { # credentialsFile is not used with token-based auth; # the token is passed via environment variable instead. # We override the systemd unit below to inject it. default = "http_status:404"; }; }; }; # Inject the tunnel token from the sops secret file systemd.services."cloudflared-tunnel-pi-main" = { serviceConfig = { ExecStart = lib.mkForce (pkgs.writeShellScript "cloudflared-start" '' exec ${pkgs.cloudflared}/bin/cloudflared tunnel \ --no-autoupdate \ run \ --token "$(cat ${config.sops.secrets."cloudflare/tunnel_token".path})" ''); }; after = lib.mkAfter [ "caddy.service" ]; wants = lib.mkAfter [ "caddy.service" ]; }; }; }