My nix-darwin and NixOS config
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(server): move to CF Tunnel for all services

+21 -40
+9 -6
modules/cloudflare-tunnel.nix
··· 30 30 cfg = config.myConfig; 31 31 32 32 # Build ingress routes based on enabled services. 33 - # NOTE: Nextcloud is intentionally excluded — it is gated to the Tailnet only. 34 - # Its Caddy port is not in allowedTCPPorts, and tailscale0 is a trusted 35 - # interface, so only Tailnet peers can reach it. Update the Cloudflare DNS 36 - # record for ${cfg.nextcloud.hostname} to an A record pointing to the 37 - # server's Tailscale IP (`tailscale ip -4`) so the hostname still resolves 38 - # correctly for Tailnet clients. 39 33 ingressRoutes = 40 34 lib.optionalAttrs cfg.services.pds.enable { 41 35 ${cfg.pds.hostname} = "http://127.0.0.1:${toString cfg.pds.caddyPort}"; ··· 43 37 } 44 38 // lib.optionalAttrs cfg.services.forgejo.enable { 45 39 ${cfg.forgejo.hostname} = "http://127.0.0.1:${toString cfg.forgejo.caddyPort}"; 40 + } 41 + // lib.optionalAttrs cfg.services.nextcloud.enable { 42 + ${cfg.nextcloud.hostname} = "http://127.0.0.1:${toString cfg.nextcloud.caddyPort}"; 43 + } 44 + // lib.optionalAttrs cfg.services.immich.enable { 45 + ${cfg.immich.hostname} = "http://127.0.0.1:${toString cfg.immich.caddyPort}"; 46 + } 47 + // lib.optionalAttrs cfg.services.jellyfin.enable { 48 + ${cfg.jellyfin.hostname} = "http://127.0.0.1:${toString cfg.jellyfin.caddyPort}"; 46 49 }; 47 50 in 48 51 lib.mkIf cfg.services.cloudflare.enable {
+6 -15
modules/immich.nix
··· 4 4 # Architecture: 5 5 # Immich server (127.0.0.1:cfg.immich.port) 6 6 # ↑ reverse proxy 7 - # Caddy (http://immich.ewancroft.uk:cfg.immich.caddyPort — Tailnet-only) 8 - # ✗ NOT in Cloudflare Tunnel — Tailnet access only 9 - # 10 - # Access model (Tailnet-only): 11 - # Port cfg.immich.caddyPort is NOT in allowedTCPPorts, so it is blocked 12 - # on all external interfaces. The firewall marks tailscale0 as a 13 - # trustedInterface, meaning Tailnet peers bypass the firewall entirely. 14 - # Point immich.ewancroft.uk at the server's Tailscale IP in Cloudflare DNS 15 - # (A record, proxying disabled — grey cloud). 7 + # Caddy (http://immich.ewancroft.uk:cfg.immich.caddyPort) 8 + # ↑ Cloudflare Tunnel (outbound only, no firewall ports needed) 16 9 # 17 10 # Storage — shared with Nextcloud: 18 11 # Media lives at cfg.immich.mediaDir, which defaults to ··· 34 27 # from Nextcloud's — no conflicts). 35 28 # 36 29 # First-run: 37 - # Navigate to http://immich.ewancroft.uk:<caddyPort> (or the raw Tailscale 38 - # IP) and complete the onboarding wizard to create your admin account. 39 - # Then configure the library path to cfg.immich.mediaDir from the UI. 30 + # Navigate to https://immich.ewancroft.uk and complete the onboarding 31 + # wizard to create your admin account. Then configure the library path 32 + # to cfg.immich.mediaDir from the UI. 40 33 ############################################################################## 41 34 { 42 35 config, ··· 96 89 wants = [ "srv.mount" ]; 97 90 }; 98 91 99 - # ── Caddy reverse proxy (Tailnet-only) ──────────────────────────────────── 100 - # Port cfg.immich.caddyPort is NOT in allowedTCPPorts. Access is restricted 101 - # to Tailnet peers via the trustedInterfaces firewall rule on tailscale0. 92 + # ── Caddy reverse proxy ─────────────────────────────────────────────────── 102 93 services.caddy.virtualHosts."http://${im.hostname}:${toString im.caddyPort}" = { 103 94 extraConfig = '' 104 95 reverse_proxy http://127.0.0.1:${toString im.port}
+6 -16
modules/jellyfin.nix
··· 4 4 # Architecture: 5 5 # Jellyfin server (127.0.0.1:cfg.jellyfin.port) 6 6 # ↑ reverse proxy 7 - # Caddy (http://jellyfin.ewancroft.uk:cfg.jellyfin.caddyPort — Tailnet-only) 8 - # ✗ NOT in Cloudflare Tunnel — Tailnet access only 9 - # 10 - # Access model (Tailnet-only): 11 - # Port cfg.jellyfin.caddyPort is NOT in allowedTCPPorts, so it is blocked 12 - # on all external interfaces. The firewall marks tailscale0 as a 13 - # trustedInterface, meaning Tailnet peers bypass the firewall entirely. 14 - # Point jellyfin.ewancroft.uk at the server's Tailscale IP in Cloudflare 15 - # DNS (A record, proxying disabled — grey cloud). 7 + # Caddy (http://jellyfin.ewancroft.uk:cfg.jellyfin.caddyPort) 8 + # ↑ Cloudflare Tunnel (outbound only, no firewall ports needed) 16 9 # 17 10 # Storage — shared with Nextcloud: 18 11 # Media lives at cfg.jellyfin.mediaDir, which defaults to ··· 41 34 # separate from the /srv volume. 42 35 # 43 36 # First-run: 44 - # Navigate to http://jellyfin.ewancroft.uk:<caddyPort> (or the raw 45 - # Tailscale IP) and complete the setup wizard. Add media libraries pointing 46 - # at subdirectories of cfg.jellyfin.mediaDir. 37 + # Navigate to https://jellyfin.ewancroft.uk and complete the setup wizard. 38 + # Add media libraries pointing at subdirectories of cfg.jellyfin.mediaDir. 47 39 ############################################################################## 48 40 { 49 41 config, ··· 83 75 dataDir = jf.dataDir; 84 76 85 77 # Do NOT open Jellyfin's default ports (8096/8920) — Caddy is the sole 86 - # entry point and only tailscale0 traffic can reach the Caddy port. 78 + # entry point, proxied through the Cloudflare tunnel. 87 79 openFirewall = false; 88 80 }; 89 81 ··· 101 93 }; 102 94 }; 103 95 104 - # ── Caddy reverse proxy (Tailnet-only) ──────────────────────────────────── 105 - # Port cfg.jellyfin.caddyPort is NOT in allowedTCPPorts. Access is restricted 106 - # to Tailnet peers via the trustedInterfaces firewall rule on tailscale0. 96 + # ── Caddy reverse proxy ─────────────────────────────────────────────────── 107 97 services.caddy.virtualHosts."http://${jf.hostname}:${toString jf.caddyPort}" = { 108 98 extraConfig = '' 109 99 reverse_proxy http://127.0.0.1:${toString jf.port}
-3
modules/server/firewall.nix
··· 13 13 allowedTCPPorts = lib.unique (cfg.server.firewall.allowedTCPPorts ++ [ cfg.server.sshd.port ]); 14 14 allowedUDPPorts = cfg.server.firewall.allowedUDPPorts; 15 15 16 - # Trust Tailscale interface for inter-host communication 17 - trustedInterfaces = [ "tailscale0" ]; 18 - 19 16 # Allow ICMP (ping) if configured 20 17 allowPing = lib.mkDefault cfg.server.firewall.allowPing; 21 18 };