118 lines
4 KiB
Nix
118 lines
4 KiB
Nix
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.services.tailscale;
|
|
tailscaleInterface = cfg.interfaceName;
|
|
inherit (config.networking) hostName;
|
|
tailnetHost = "${hostName}.tail05275.ts.net";
|
|
in
|
|
{
|
|
networking.wireguard.enable = true;
|
|
networking.firewall.trustedInterfaces = [ tailscaleInterface ];
|
|
|
|
systemd.network = {
|
|
# Fixes issues with other systemd networks when tailscale exist nodes are used
|
|
config.networkConfig = {
|
|
ManageForeignRoutes = false;
|
|
ManageForeignRoutingPolicyRules = false;
|
|
};
|
|
wait-online.ignoredInterfaces = [ "tailscale0" ];
|
|
};
|
|
|
|
services.networkd-dispatcher = {
|
|
enable = true;
|
|
rules = {
|
|
# exclude LANs from tailscale subnet routes (when using `--accept-routes`)
|
|
"50-tailscale-exclude-lan-routes" = {
|
|
onState = [ "routable" ];
|
|
script = ''
|
|
#!${pkgs.runtimeShell}
|
|
# shellcheck disable=SC2010
|
|
|
|
lan_interfaces=$(ls /sys/class/net | grep -E '^(enp|eth|wlp)')
|
|
if [[ "$lan_interfaces" == "" ]]; then exit 0; fi
|
|
echo "$lan_interfaces" | while IFS= read -r lan_if; do
|
|
for ipv in 4 6; do
|
|
subnets=$(${pkgs.iproute2}/bin/ip -"$ipv" route show dev "$lan_if" proto kernel | cut -f1 -d' ' | grep '/')
|
|
if [[ "$subnets" == "" ]]; then break; fi
|
|
echo "$subnets" | while IFS= read -r subnet; do
|
|
if ${pkgs.iproute2}/bin/ip -"$ipv" route show table 52 | grep -q "$subnet dev tailscale0"; then
|
|
${pkgs.iproute2}/bin/ip -"$ipv" route del "$subnet" dev tailscale0 table 52
|
|
${pkgs.iproute2}/bin/ip -"$ipv" route add throw "$subnet" table 52
|
|
fi
|
|
done
|
|
done
|
|
done
|
|
'';
|
|
};
|
|
# UDP throughput improvements
|
|
# https://tailscale.com/kb/1320/performance-best-practices?q=gro#linux-optimizations-for-subnet-routers-and-exit-nodes
|
|
"50-tailscale-rx-udp-gro-forwarding" = {
|
|
onState = [ "routable" ];
|
|
script = ''
|
|
for dev in $(${pkgs.iproute2}/bin/ip route show 0/0 | cut -f5 -d' '); do
|
|
${lib.getExe pkgs.ethtool} -K "$dev" rx-udp-gro-forwarding on rx-gro-list off
|
|
done
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
services.tailscale = {
|
|
enable = true;
|
|
package = pkgs.unstable.tailscale;
|
|
openFirewall = true;
|
|
useRoutingFeatures = lib.mkDefault "client";
|
|
extraUpFlags = [
|
|
"--reset"
|
|
"--exit-node-allow-lan-access"
|
|
"--exit-node=de-fra-wg-106.mullvad.ts.net"
|
|
];
|
|
};
|
|
|
|
systemd.services.tailscaled = {
|
|
serviceConfig.Environment = [ "TS_DEBUG_FIREWALL_MODE=auto" ];
|
|
after = [
|
|
"network-online.target"
|
|
"systemd-resolved.service"
|
|
];
|
|
};
|
|
|
|
# call taiscale up without --auth-key
|
|
systemd.services.tailscaled-autoconnect = lib.mkIf (cfg.authKeyFile == null) {
|
|
after = [ "tailscaled.service" ];
|
|
wants = [ "tailscaled.service" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
serviceConfig.Type = "oneshot";
|
|
script =
|
|
''
|
|
status=$(${config.systemd.package}/bin/systemctl show -P StatusText tailscaled.service)
|
|
if [[ $status != Connected* ]]; then
|
|
${cfg.package}/bin/tailscale up
|
|
fi
|
|
|
|
# some options cannot be set immediately
|
|
${cfg.package}/bin/tailscale up ${lib.escapeShellArgs cfg.extraUpFlags}
|
|
|
|
${cfg.package}/bin/tailscale cert ${tailnetHost}
|
|
''
|
|
+ lib.optionalString config.services.nginx.enable ''
|
|
chown nginx:nginx /var/lib/tailscale/certs/${tailnetHost}.{key,crt}
|
|
'';
|
|
};
|
|
|
|
services.nginx.virtualHosts.${tailnetHost} = {
|
|
sslCertificate = "/var/lib/tailscale/certs/${tailnetHost}.crt";
|
|
sslCertificateKey = "/var/lib/tailscale/certs/${tailnetHost}.key";
|
|
};
|
|
|
|
# TODO Tailscale Mullvad exit nodes currently don't support IPv6 and this is
|
|
# causing issues with nginx (proxy pass) requests timing out and high CPU load.
|
|
# Until Mullvad exit nodes support IPv6, we'll just disable IPv6 for nginx.
|
|
services.nginx.resolver.ipv6 = false;
|
|
}
|