{ config, lib, pkgs, ... }: let # Cloudflare tunnel definitions tunnels = { warp = { remoteHost = "warp.ftl.host"; # Cloudflare hostname remoteTarget = "localhost:22"; # Where traffic routes to localBindPort = 4401; # Local port exposed by cloudflared logPath = "/var/log/cloudflared/warp.log"; }; }; in { # Install cloudflared environment.systemPackages = with pkgs; [ cloudflared ]; # Ensure /var/log/cloudflared exists systemd.tmpfiles.rules = [ "d /var/log/cloudflared 0755 root root -" ]; # Systemd services per tunnel systemd.services = lib.mapAttrs (name: tunnel: { description = "Cloudflared Access TCP Tunnel for ${tunnel.remoteHost}"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; # Create directory for log files preStart = '' mkdir -p "$(dirname ${tunnel.logPath})" touch ${tunnel.logPath} chmod 644 ${tunnel.logPath} ''; serviceConfig = { ExecStart = "${pkgs.cloudflared}/bin/cloudflared access tcp --hostname ${tunnel.remoteHost} --url ${tunnel.remoteTarget} --port ${toString tunnel.localBindPort} --logfile ${tunnel.logPath}"; # The key setting to ensure the service stays running Type = "simple"; Restart = "always"; RestartSec = "5s"; # Configure service to wait for network After = [ "network-online.target" ]; Wants = [ "network-online.target" ]; # Run as dedicated user for better security DynamicUser = true; # Configure systemd runtime directory RuntimeDirectory = "cloudflared"; RuntimeDirectoryMode = "0700"; # Standard outputs StandardOutput = "journal"; StandardError = "journal"; }; }) tunnels; # Activation step to ensure log directory exists system.activationScripts.cloudflaredLogs = lib.stringAfter [ "users" ] '' mkdir -p /var/log/cloudflared chmod 755 /var/log/cloudflared ''; # Optional documentation metadata meta.doc = '' This module defines persistent cloudflared TCP tunnels using access tcp. Add tunnels by appending to the `tunnels` attribute set. Required keys: - remoteHost: The public hostname exposed via Cloudflare Tunnel. - remoteTarget: The internal service to forward traffic to (e.g. localhost:22). - localBindPort: The port to expose locally (e.g. 4401). - logPath: File path to capture logs. ''; }