feat: add headscale service
This commit is contained in:
parent
6cedde7e17
commit
eb50441b92
@ -4,6 +4,9 @@
|
|||||||
inputs,
|
inputs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib) concatLists unique;
|
||||||
|
in
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
inputs.srvos.nixosModules.server
|
inputs.srvos.nixosModules.server
|
||||||
@ -94,7 +97,6 @@
|
|||||||
mkvtoolnix-cli
|
mkvtoolnix-cli
|
||||||
nfs-utils
|
nfs-utils
|
||||||
p7zip
|
p7zip
|
||||||
podman-compose
|
|
||||||
pwgen
|
pwgen
|
||||||
ripgrep
|
ripgrep
|
||||||
rsync
|
rsync
|
||||||
@ -117,6 +119,51 @@
|
|||||||
ataraxia.services.gitea.enable = true;
|
ataraxia.services.gitea.enable = true;
|
||||||
ataraxia.services.syncyomi.enable = true;
|
ataraxia.services.syncyomi.enable = true;
|
||||||
ataraxia.services.vaultwarden.enable = true;
|
ataraxia.services.vaultwarden.enable = true;
|
||||||
|
ataraxia.services.headscale.enable = true;
|
||||||
|
ataraxia.services.headscale.extraDns = unique (
|
||||||
|
concatLists (
|
||||||
|
map
|
||||||
|
(name: [
|
||||||
|
{
|
||||||
|
inherit name;
|
||||||
|
type = "A";
|
||||||
|
value = "100.64.0.1";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
inherit name;
|
||||||
|
type = "AAAA";
|
||||||
|
value = "fd7a:115c:a1e0::1";
|
||||||
|
}
|
||||||
|
])
|
||||||
|
[
|
||||||
|
"api.ataraxiadev.com"
|
||||||
|
"cache.ataraxiadev.com"
|
||||||
|
"cal.ataraxiadev.com"
|
||||||
|
"code.ataraxiadev.com"
|
||||||
|
"docs.ataraxiadev.com"
|
||||||
|
"element.ataraxiadev.com"
|
||||||
|
"files.ataraxiadev.com"
|
||||||
|
"home.ataraxiadev.com"
|
||||||
|
"jackett.ataraxiadev.com"
|
||||||
|
"jellyfin.ataraxiadev.com"
|
||||||
|
"kavita.ataraxiadev.com"
|
||||||
|
"ldap.ataraxiadev.com"
|
||||||
|
"lib.ataraxiadev.com"
|
||||||
|
"matrix.ataraxiadev.com"
|
||||||
|
"medusa.ataraxiadev.com"
|
||||||
|
"pdf.ataraxiadev.com"
|
||||||
|
"qbit.ataraxiadev.com"
|
||||||
|
"radarr.ataraxiadev.com"
|
||||||
|
"restic.ataraxiadev.com"
|
||||||
|
"s3.ataraxiadev.com"
|
||||||
|
"sonarr.ataraxiadev.com"
|
||||||
|
"tools.ataraxiadev.com"
|
||||||
|
"turn.ataraxiadev.com"
|
||||||
|
"vw.ataraxiadev.com"
|
||||||
|
"wiki.ataraxiadev.com"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
ataraxia.virtualisation.guests = {
|
ataraxia.virtualisation.guests = {
|
||||||
omv = {
|
omv = {
|
||||||
|
158
modules/nixos/services/headscale.nix
Normal file
158
modules/nixos/services/headscale.nix
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
secretsDir,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mkEnableOption
|
||||||
|
mkIf
|
||||||
|
mkOption
|
||||||
|
recursiveUpdate
|
||||||
|
;
|
||||||
|
inherit (lib.types)
|
||||||
|
bool
|
||||||
|
enum
|
||||||
|
listOf
|
||||||
|
str
|
||||||
|
submodule
|
||||||
|
;
|
||||||
|
|
||||||
|
cfg = config.ataraxia.services.headscale;
|
||||||
|
nginx = config.ataraxia.services.nginx;
|
||||||
|
domain = "wg.ataraxiadev.com";
|
||||||
|
|
||||||
|
dnsEntry = submodule {
|
||||||
|
options = {
|
||||||
|
name = mkOption {
|
||||||
|
type = str;
|
||||||
|
};
|
||||||
|
type = mkOption {
|
||||||
|
type = enum [
|
||||||
|
"A"
|
||||||
|
"AAAA"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
value = mkOption {
|
||||||
|
type = str;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.ataraxia.services.headscale = {
|
||||||
|
enable = mkEnableOption "Enable headscale service";
|
||||||
|
sopsDir = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = config.networking.hostName;
|
||||||
|
description = ''
|
||||||
|
Name for sops secrets directory. Defaults to hostname.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
nginxHost = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = config.ataraxia.services.nginx.enable;
|
||||||
|
description = "Enable nginx vHost integration";
|
||||||
|
};
|
||||||
|
extraDns = mkOption {
|
||||||
|
type = listOf dnsEntry;
|
||||||
|
description = ''
|
||||||
|
Extra dns records for headscale.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
services.headscale = {
|
||||||
|
enable = true;
|
||||||
|
address = "0.0.0.0";
|
||||||
|
port = 8005;
|
||||||
|
settings = {
|
||||||
|
server_url = "https://${domain}";
|
||||||
|
ip_prefixes = [
|
||||||
|
"fd7a:115c:a1e0::/64"
|
||||||
|
"100.64.0.0/16"
|
||||||
|
];
|
||||||
|
dns = {
|
||||||
|
override_local_dns = true;
|
||||||
|
base_domain = "tailnet.ataraxiadev.com";
|
||||||
|
nameservers.global = [ "127.0.0.1" ];
|
||||||
|
extra_records = cfg.extraDns;
|
||||||
|
};
|
||||||
|
oidc = {
|
||||||
|
only_start_if_oidc_is_available = true;
|
||||||
|
issuer = "https://auth.ataraxiadev.com/application/o/headscale/";
|
||||||
|
client_id = "n6UBhK8PahexLPb7GkU1xzoFLcYxQX0HWDytpUoi";
|
||||||
|
client_secret_path = config.sops.secrets.headscale-oidc.path;
|
||||||
|
scope = [
|
||||||
|
"openid"
|
||||||
|
"profile"
|
||||||
|
"email"
|
||||||
|
"groups"
|
||||||
|
];
|
||||||
|
allowed_groups = [ "headscale" ];
|
||||||
|
};
|
||||||
|
grpc_listen_addr = "127.0.0.1:50443";
|
||||||
|
grpc_allow_insecure = true;
|
||||||
|
disable_check_updates = true;
|
||||||
|
ephemeral_node_inactivity_timeout = "4h";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nginx.virtualHosts = mkIf cfg.nginxHost {
|
||||||
|
${domain} = recursiveUpdate nginx.defaultSettings {
|
||||||
|
locations."/headscale." = {
|
||||||
|
extraConfig = ''
|
||||||
|
grpc_pass grpc://${config.services.headscale.settings.grpc_listen_addr};
|
||||||
|
'';
|
||||||
|
priority = 1;
|
||||||
|
};
|
||||||
|
locations."/metrics" = {
|
||||||
|
proxyPass = "http://127.0.0.1:${toString config.services.headscale.port}";
|
||||||
|
extraConfig = ''
|
||||||
|
allow 100.64.0.0/16;
|
||||||
|
allow 10.10.10.0/24;
|
||||||
|
deny all;
|
||||||
|
'';
|
||||||
|
priority = 2;
|
||||||
|
};
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:${toString config.services.headscale.port}";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
priority = 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sops.secrets.headscale-oidc = {
|
||||||
|
sopsFile = secretsDir + /${cfg.sopsDir}/headscale.yaml;
|
||||||
|
owner = "headscale";
|
||||||
|
restartUnits = [ "headscale.service" ];
|
||||||
|
};
|
||||||
|
systemd.services.headscale = {
|
||||||
|
serviceConfig.TimeoutStopSec = 15;
|
||||||
|
serviceConfig.ExecStartPre =
|
||||||
|
let
|
||||||
|
waitAuthnetikReady = pkgs.writeShellScript "waitAuthnetikReady" ''
|
||||||
|
# Check until authentik is alive
|
||||||
|
max_retry=100
|
||||||
|
counter=0
|
||||||
|
until ${lib.getExe pkgs.curl} -fsSL http://auth.ataraxiadev.com/-/health/ready/
|
||||||
|
do
|
||||||
|
echo "Waiting for the authentik..."
|
||||||
|
sleep 3
|
||||||
|
[[ counter -eq $max_retry ]] && echo "Could not connect to authentik!" && exit 1
|
||||||
|
echo "Trying again. Try #$counter"
|
||||||
|
((counter++))
|
||||||
|
done
|
||||||
|
echo "Authentik is alive!"
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
waitAuthnetikReady;
|
||||||
|
};
|
||||||
|
|
||||||
|
persist.state.directories = [ "/var/lib/headscale" ];
|
||||||
|
};
|
||||||
|
}
|
27
secrets/orion/headscale.yaml
Normal file
27
secrets/orion/headscale.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
headscale-oidc: ENC[AES256_GCM,data:lu1c/XSD7/fV1MuwAETDV1PCn3C7zr0UKK0u4/5Z2AoQXHLsUES3Yvu7B9kStFd3M+GoOq6Y0xYVGLS9x5TcEVFDKSsdRRgGYlu2C/x+NUOlP0cEKKq222NYIZ6iA9emP6A2ZVy1ZpM1UE65vJHk1NHHbS4zYiiJMskOacwW1bs=,iv:o9/TG+9/MU6mchYtj6navG97eJhP/4kUlWcx/xjhvK0=,tag:l2xQhGn1vkcBZvBZevpTOg==,type:str]
|
||||||
|
headscale-oidc-env: ENC[AES256_GCM,data:LX26VJfqImj5hHGSczey4okdPsNdxsIQ4OD3kRhwRt4P2MAdlVWiBQl47Jj5lk1Nm/yZejf4GXARLoQf3TK1ie4aDaWJx8Yhl8aSpy1s3h/1lcM7OCNb9WhUB+ZmikXaA6sOui4sQfGEtf0ydeIE0CwH04WL+Qomu+WxFzUVSzPW3baR2AKSqKiLGLGB0mZrRmdbhSdxCJN85j2i/Q==,iv:9b4pMMLj9huMg2RnrU10xqjRoA3NCWUKn4rc956Gm+s=,tag:+XN0KzJqWvTS/8ufGooNfg==,type:str]
|
||||||
|
sops:
|
||||||
|
shamir_threshold: 1
|
||||||
|
age:
|
||||||
|
- recipient: age13phpsegg6vu7a34ydtfa9s904dfpgzqhzru7epnky7glezk0xvkst9qh6h
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhdWVNQVRkYUwvVkRnUlJV
|
||||||
|
ZFI3K1NsTzBFWDZXSU5Md0NQRTlsUTlCTHhZCjFObFNMSENXN2NIZlQ1ZHBEZ3Fu
|
||||||
|
R0JhVXdsRThUS3ZDWXV2OTFkODdQUGMKLS0tIEZiZ1ZEWTBaMnlIc2lTWGQxSW1W
|
||||||
|
bjNGQnFnOFVwbHdsVkpuNHJlRVc2c1kK/IQzoSi17GU8D6LP+4ccxq+Ip3lary62
|
||||||
|
0dkRYgMOf+jR21VA+1jhyFFYkwzZl7ajnM+pXYKf+/togQv6MnML/g==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1m5msm7rgqye2q9zesgedg0emga4ntehlr629786lrxs3rhk0squq0ly9je
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSZFdCQmltbnduUklHdTJB
|
||||||
|
OGR6WllGaS8xUUhNT0t6cU1JVHF0V0tsSlF3CmlSYlNDZEJvRzdCT3hrRGFPeGdZ
|
||||||
|
eFRCVUFtbFJBUnNPREd2RzR1eUYyOFkKLS0tIGZBWGJURE5Cb2lreWdPYjJWL0FV
|
||||||
|
VzBXZTNORldzcGo2KzVhTmQ5dERMMjAKMEV+wMtClLbgur/Qx/xLaQNjjqNtm1sf
|
||||||
|
5z+Hi/D0aqgA09k5iAxGdfez0rFJAX32w6vJouMTfYzCLqC6iaaomQ==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2024-01-24T20:09:29Z"
|
||||||
|
mac: ENC[AES256_GCM,data:akcHfxJrGSPINI28sQdxcz4s6P9Va+GAvF0TC7adgf2mgVtqkZdaZPJZ/BaVlxccWf3tFgBMKwLVHcfmxMi93KnxFxOuA3DWYnjmBfHzxHFq+jWke7BHzRhPvVsKOKKHdfkXPCZnqyHLwRPp0jUyrANw9m9Ub2JTomfHy3j2+FA=,iv:784bnpb7v0z3KewsnH+RXYkdml+o2sj/qvR7qqn/om0=,tag:L1c/p8GcUlT+4sLyr0T5fA==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.8.1
|
Loading…
x
Reference in New Issue
Block a user