Add Tailscale support to NixOS configurations
This commit is contained in:
@@ -50,6 +50,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
sops.secrets."users/server/hashedPassword".neededForUsers = true;
|
sops.secrets."users/server/hashedPassword".neededForUsers = true;
|
||||||
|
sops.secrets."tailscale/auth-key" = {
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
|
||||||
security.sudo.wheelNeedsPassword = true;
|
security.sudo.wheelNeedsPassword = true;
|
||||||
|
|
||||||
@@ -63,6 +66,11 @@
|
|||||||
networking = {
|
networking = {
|
||||||
hostName = "nix-server";
|
hostName = "nix-server";
|
||||||
networkManager.enable = true;
|
networkManager.enable = true;
|
||||||
|
tailscale = {
|
||||||
|
enable = true;
|
||||||
|
authKeyFile = config.sops.secrets."tailscale/auth-key".path;
|
||||||
|
subnetRouter.enable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
caching.attic = {
|
caching.attic = {
|
||||||
|
|||||||
@@ -38,6 +38,9 @@
|
|||||||
group = "users";
|
group = "users";
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
};
|
};
|
||||||
|
sops.secrets."tailscale/auth-key" = {
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
|
||||||
chiasson.system.librepods.enable = true;
|
chiasson.system.librepods.enable = true;
|
||||||
chiasson.system.palera1n.enable = true;
|
chiasson.system.palera1n.enable = true;
|
||||||
@@ -106,6 +109,11 @@
|
|||||||
networking = {
|
networking = {
|
||||||
hostName = "t2mbp";
|
hostName = "t2mbp";
|
||||||
networkManager.enable = true;
|
networkManager.enable = true;
|
||||||
|
tailscale = {
|
||||||
|
enable = true;
|
||||||
|
authKeyFile = config.sops.secrets."tailscale/auth-key".path;
|
||||||
|
acceptRoutes = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
self.nixosModules.systemLocalization
|
self.nixosModules.systemLocalization
|
||||||
self.nixosModules.systemFonts
|
self.nixosModules.systemFonts
|
||||||
self.nixosModules.systemNetworking
|
self.nixosModules.systemNetworking
|
||||||
|
self.nixosModules.systemTailscale
|
||||||
self.nixosModules.systemLocalsend
|
self.nixosModules.systemLocalsend
|
||||||
self.nixosModules.systemChromiumHevcVaapi
|
self.nixosModules.systemChromiumHevcVaapi
|
||||||
self.nixosModules.systemMonitorInput
|
self.nixosModules.systemMonitorInput
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.systemTailscale =
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.chiasson.system.networking.tailscale;
|
||||||
|
tsCfg = config.services.tailscale;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.chiasson.system.networking.tailscale = {
|
||||||
|
enable = lib.mkEnableOption ''
|
||||||
|
Tailscale mesh VPN. Joins this host to your tailnet for encrypted access
|
||||||
|
from anywhere without opening inbound ports on your router.
|
||||||
|
'';
|
||||||
|
|
||||||
|
authKeyFile = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/run/secrets/tailscale/auth-key";
|
||||||
|
description = ''
|
||||||
|
Reusable Tailscale auth key (sops path). Create one at
|
||||||
|
https://login.tailscale.com/admin/settings/keys — enable Reusable and
|
||||||
|
Pre-approved. Store under `tailscale/auth-key` in secrets/secrets.yaml.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Allow Tailscale UDP 41641 through the host firewall.";
|
||||||
|
};
|
||||||
|
|
||||||
|
acceptRoutes = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Accept subnet routes advertised by other tailnet nodes (e.g. home LAN
|
||||||
|
via nix-server). Enable on portable clients like t2mbp.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
subnetRouter = {
|
||||||
|
enable = lib.mkEnableOption ''
|
||||||
|
Advertise the home LAN through this node so other tailnet devices can
|
||||||
|
reach local IPs (SSH, Attic, Gitea, Jellyfin, etc.). Enable on an
|
||||||
|
always-on home host (nix-server). Approve the route in the Tailscale
|
||||||
|
admin console after first connect.
|
||||||
|
'';
|
||||||
|
|
||||||
|
routes = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
default = [ "192.168.2.0/24" ];
|
||||||
|
example = [ "192.168.2.0/24" ];
|
||||||
|
description = "Subnets to advertise to the tailnet.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
services.tailscale = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = cfg.openFirewall;
|
||||||
|
authKeyFile = cfg.authKeyFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.trustedInterfaces = lib.mkAfter [ "tailscale0" ];
|
||||||
|
}
|
||||||
|
(lib.mkIf cfg.acceptRoutes {
|
||||||
|
services.tailscale.useRoutingFeatures = "client";
|
||||||
|
services.tailscale.extraUpFlags = [ "--accept-routes" ];
|
||||||
|
})
|
||||||
|
(lib.mkIf cfg.subnetRouter.enable {
|
||||||
|
services.tailscale.useRoutingFeatures = "both";
|
||||||
|
services.tailscale.extraUpFlags =
|
||||||
|
map (route: "--advertise-routes=${route}") cfg.subnetRouter.routes;
|
||||||
|
})
|
||||||
|
(lib.mkIf (cfg.authKeyFile != null) {
|
||||||
|
# Upstream uses `$(cat $authKeyFile)` which breaks when sops leaves a trailing newline.
|
||||||
|
systemd.services.tailscaled-autoconnect.script = lib.mkOverride 50 ''
|
||||||
|
getState() {
|
||||||
|
tailscale status --json --peers=false | jq -r '.BackendState'
|
||||||
|
}
|
||||||
|
|
||||||
|
lastState=""
|
||||||
|
while state="$(getState)"; do
|
||||||
|
if [[ "$state" != "$lastState" ]]; then
|
||||||
|
case "$state" in
|
||||||
|
NeedsLogin|NeedsMachineAuth|Stopped)
|
||||||
|
echo "Server needs authentication, sending auth key"
|
||||||
|
tailscale up --auth-key "$(tr -d '\n\r' < ${cfg.authKeyFile})" ${lib.escapeShellArgs tsCfg.extraUpFlags}
|
||||||
|
;;
|
||||||
|
Running)
|
||||||
|
echo "Tailscale is running"
|
||||||
|
systemd-notify --ready
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Waiting for Tailscale State = Running or systemd timeout"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
echo "State = $state"
|
||||||
|
fi
|
||||||
|
lastState="$state"
|
||||||
|
sleep .5
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -10,6 +10,8 @@ cachix:
|
|||||||
caching:
|
caching:
|
||||||
attic:
|
attic:
|
||||||
token: ENC[AES256_GCM,data:8omssG3GwCFIegfz+8IAGGhFGj01RB3dqqHeFpmZOzMJUshIDvSRuTTpGFhUBC7Xue8h09hAhpirIHmqzyG3I+e2Se/VZZoByXmpyIKesl3+NqOXDkJvgImqhvFVkTiSe5p/vSN3slWDylfkThQ0hZYw5mB9J13M5965iUnWcRbg+1fYFdTuSgrHY8Rxt4da0287A0YGnsN63k7j32XOJndxsRoOLoo+IQ+X+hiPOJkfGYxY0MglnxaxhPwH8SP1V+p78N75Z2npOtMdEikdHmj/NmKbqUXN2P0+IXthxV17WePCulZVsKC1Jw+clgbyAvHcQeVG/yyrcb1CRRQpszHtq1Pz7DHvfAG+gxyPNyP7D6oQNT8foX4C6CwuHgYQtM1x0D6oAL+lppQWJ0kEV/GDlJSXQnp/aBbVAqDmqS0TCx40nVmQ0PvMcjtsiZJigkRJRNLCg6n+qmhc5Rh9RhslPN5JXU0orWs9QYAoLXzdDDGP/R9tlEhwQBxwGrFAp016iilqPavMdI8txrWWdvezQuAh//eeW5LQSa6t363VCjX8phnXeJltOgXYlyuKnCCmv0a6XwhmT0PA+32/F0BxTf9lcZConpurlvOHdznaVeUXcFOEwKouDC7smPIZZqcRU8OIbWs7YXqMgatgb/bJVtB0P0Avsj9t9Uz8Dv8xBV+90U5qwM7HV16FIERorDquzgKFcvtb8/QfjTINoswpHZKNCbmQPxfJYPheJFwMQGFn+b+ecv+Z7qng9JEujJSNtEPv2CIuVmSxZJaU5g2CMu3rFGIA3qF81Bf1Ri8n+KYWgOKpQt11nClouv2XePO8JKI6fslF411zJ8zD4E/6Qg95UWhLh0RG2cXzYSXXvrpXDlIe9spc4OLuj4tFtXkiZZvfM5MgRTtoh93soypUpEbswTji2UprC3OPikjIIW49YysGVsH2100/67HbtinRoazM1M+DjaD2pMryx7kW/oVpyaW61wiqtHk9nq8vqROLWBhQxzGSh9157z/46AT+8PN89gFh5uNdFuhFz8e8/HIV3HtIrzrtR+flJfHJ1ZT5dhTDicSMiC/DhG/hupX4GHGX6zlaMgBqB8bKxxvs+v0iHfSkDIkuenZ+nTD72DP5yuIQVIwGV16CZA6rusjb1zLn6QYpvQtCuqlih+epsGNEYP6B3rvNMc/N7JcwY4YMTK+C46EC9mXhpfPn0a5OdD4kQ6s=,iv:+g9W5MzgtLppD1K3dZ/tCuaMxaa194W3Lf23/jUmDvk=,tag:5uVwIOkB2+MRHPGlKGQtGg==,type:str]
|
token: ENC[AES256_GCM,data:8omssG3GwCFIegfz+8IAGGhFGj01RB3dqqHeFpmZOzMJUshIDvSRuTTpGFhUBC7Xue8h09hAhpirIHmqzyG3I+e2Se/VZZoByXmpyIKesl3+NqOXDkJvgImqhvFVkTiSe5p/vSN3slWDylfkThQ0hZYw5mB9J13M5965iUnWcRbg+1fYFdTuSgrHY8Rxt4da0287A0YGnsN63k7j32XOJndxsRoOLoo+IQ+X+hiPOJkfGYxY0MglnxaxhPwH8SP1V+p78N75Z2npOtMdEikdHmj/NmKbqUXN2P0+IXthxV17WePCulZVsKC1Jw+clgbyAvHcQeVG/yyrcb1CRRQpszHtq1Pz7DHvfAG+gxyPNyP7D6oQNT8foX4C6CwuHgYQtM1x0D6oAL+lppQWJ0kEV/GDlJSXQnp/aBbVAqDmqS0TCx40nVmQ0PvMcjtsiZJigkRJRNLCg6n+qmhc5Rh9RhslPN5JXU0orWs9QYAoLXzdDDGP/R9tlEhwQBxwGrFAp016iilqPavMdI8txrWWdvezQuAh//eeW5LQSa6t363VCjX8phnXeJltOgXYlyuKnCCmv0a6XwhmT0PA+32/F0BxTf9lcZConpurlvOHdznaVeUXcFOEwKouDC7smPIZZqcRU8OIbWs7YXqMgatgb/bJVtB0P0Avsj9t9Uz8Dv8xBV+90U5qwM7HV16FIERorDquzgKFcvtb8/QfjTINoswpHZKNCbmQPxfJYPheJFwMQGFn+b+ecv+Z7qng9JEujJSNtEPv2CIuVmSxZJaU5g2CMu3rFGIA3qF81Bf1Ri8n+KYWgOKpQt11nClouv2XePO8JKI6fslF411zJ8zD4E/6Qg95UWhLh0RG2cXzYSXXvrpXDlIe9spc4OLuj4tFtXkiZZvfM5MgRTtoh93soypUpEbswTji2UprC3OPikjIIW49YysGVsH2100/67HbtinRoazM1M+DjaD2pMryx7kW/oVpyaW61wiqtHk9nq8vqROLWBhQxzGSh9157z/46AT+8PN89gFh5uNdFuhFz8e8/HIV3HtIrzrtR+flJfHJ1ZT5dhTDicSMiC/DhG/hupX4GHGX6zlaMgBqB8bKxxvs+v0iHfSkDIkuenZ+nTD72DP5yuIQVIwGV16CZA6rusjb1zLn6QYpvQtCuqlih+epsGNEYP6B3rvNMc/N7JcwY4YMTK+C46EC9mXhpfPn0a5OdD4kQ6s=,iv:+g9W5MzgtLppD1K3dZ/tCuaMxaa194W3Lf23/jUmDvk=,tag:5uVwIOkB2+MRHPGlKGQtGg==,type:str]
|
||||||
|
tailscale:
|
||||||
|
auth-key: ENC[AES256_GCM,data:ffBLc/LIm67P/DUSvDUek/qWHLfQbmSE3jQL1/TLHrZEEGk+HqEO4Prlj5bGGAU37tiHaD7Ksj1wqX3U+Q==,iv:Uw1tnuxMPZVwqvrRkZZusJM/a7QeoggR047+CKx9fnY=,tag:kS1IixpXYm1QVBIAmmgQ6Q==,type:str]
|
||||||
sops:
|
sops:
|
||||||
age:
|
age:
|
||||||
- enc: |
|
- enc: |
|
||||||
@@ -75,7 +77,7 @@ sops:
|
|||||||
6POXxpxjGhlWJaV47jqeN+7mQY2oTHE/x4raoX/KA2ouXL29K8QpmA==
|
6POXxpxjGhlWJaV47jqeN+7mQY2oTHE/x4raoX/KA2ouXL29K8QpmA==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
recipient: age1pewusvlcgzcnk0kpskgc9qr6jlq8s2yzwnqrnh84p7v5z0kj3qhsya8h2x
|
recipient: age1pewusvlcgzcnk0kpskgc9qr6jlq8s2yzwnqrnh84p7v5z0kj3qhsya8h2x
|
||||||
lastmodified: "2026-03-24T00:15:02Z"
|
lastmodified: "2026-06-10T03:00:15Z"
|
||||||
mac: ENC[AES256_GCM,data:dYTwO5DtkKinTKfBXGuvXRFxl8yavxXMKTw27M5/GcK/kkstHBG119IRk9B9KC6s6IHTY81U3MeUxE9XwdBiE7q4m15+ZO2vmdBVhN8wAh+82P9BP0HSaxLkjWLeKWBfULyLX/YXmQVsr09/NUEVSZcugJ6m40Ta+X9AQgO+cyA=,iv:FmsznsKTuIr61s3Zn0QZKSKvb/e2AljEB1ijKE52RKk=,tag:rHF2Xi4iP9VF33rxpBr5pg==,type:str]
|
mac: ENC[AES256_GCM,data:F1DU7Sj9lsTOHWlyuY4L4N+urrBXv2GLKhlzohMA9iF6/bphRABa9we3WZX9MFNIc2Te+2SCh3f6Rv5eHwWSsZVdD4iwN/6HTabdNPTEOZyk/OVsap/F374MLu8ys3OVZ5vzg2PYCGmhlf4PQMrjvaz+CV3t8UezB6E4U0N3RuU=,iv:wT2ieUON5VInJhDtZFLENzyaty5TqcisLmYePnCHGM4=,tag:z9CYpCWa/XdSqPKMG3M41A==,type:str]
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.12.1
|
version: 3.13.1
|
||||||
|
|||||||
Reference in New Issue
Block a user