Files
homey/modules/cloudflared.nix
2026-05-10 11:30:43 +03:00

92 lines
3.7 KiB
Nix

{ 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.zakobar.com → http://localhost:80 (or https://localhost:443)
# git.zakobar.com → https://localhost:443
# nextcloud.zakobar.com → https://localhost:443
# ldapadmin.zakobar.com → https://localhost:443
# jellyfin.zakobar.com → https://localhost:443
# torrent.zakobar.com → https://localhost:443
# uptime.zakobar.com → https://localhost:443
# ntfy.zakobar.com → https://localhost:443
# grafana.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
#
# We use the token-based tunnel approach (cloudflared tunnel run --token).
# This needs no credentials file and no local tunnel config — just the
# token from the Cloudflare dashboard.
#
# Rather than using services.cloudflared.tunnels (which requires a
# credentialsFile), we create a plain systemd service that runs cloudflared
# directly with the token read from the sops secret.
# -----------------------------------------------------------------------
users.users.cloudflared = {
isSystemUser = true;
group = "cloudflared";
description = "cloudflared tunnel daemon";
};
users.groups.cloudflared = {};
systemd.services."cloudflared-tunnel" = {
description = "Cloudflare Tunnel (token-based)";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" "caddy.service" ];
wants = [ "network-online.target" "caddy.service" ];
serviceConfig = {
Type = "simple";
User = "cloudflared";
Group = "cloudflared";
Restart = "on-failure";
RestartSec = "5s";
ExecStart = pkgs.writeShellScript "cloudflared-start" ''
exec ${pkgs.cloudflared}/bin/cloudflared tunnel \
--no-autoupdate \
run \
--token "$(cat ${config.sops.secrets."cloudflare/tunnel_token".path})"
'';
# Hardening
NoNewPrivileges = true;
PrivateTmp = true;
};
};
};
}