150 lines
4.4 KiB
Nix
150 lines
4.4 KiB
Nix
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}:
|
|
let
|
|
domain = "kennys.mom";
|
|
derpPort = 3478;
|
|
# Generate the exact YAML config headplane wants
|
|
format = pkgs.formats.yaml {};
|
|
configStrict = lib.recursiveUpdate (builtins.removeAttrs config.services.headscale.settings [ "oidc" ]) {
|
|
tls_cert_path = "/dev/null";
|
|
tls_key_path = "/dev/null";
|
|
policy.path = "/dev/null";
|
|
};
|
|
headscaleConfigFile = format.generate "headscale-strict.yml" configStrict;
|
|
in
|
|
{
|
|
services.headscale = {
|
|
enable = true;
|
|
address = "0.0.0.0";
|
|
port = 8085;
|
|
settings = {
|
|
dns = {
|
|
override_local_dns = true;
|
|
base_domain = "hs.${domain}";
|
|
magic_dns = true;
|
|
domains = [ "hs.${domain}" ];
|
|
nameservers = {
|
|
global = [
|
|
"1.1.1.1"
|
|
"9.9.9.9"
|
|
];
|
|
};
|
|
};
|
|
server_url = "https://headscale.${domain}";
|
|
metrics_listen_addr = "127.0.0.1:8095";
|
|
logtail = {
|
|
enabled = false;
|
|
};
|
|
log = {
|
|
level = "warn";
|
|
};
|
|
derp.server = {
|
|
enable = true;
|
|
region_id = 999;
|
|
stun_listen_addr = "0.0.0.0:${toString derpPort}";
|
|
};
|
|
ip_prefixes = [
|
|
"100.64.0.0/10"
|
|
"fd7a:115c:a1e0::/48"
|
|
];
|
|
grpc_listen_addr = "127.0.0.1:50443"; # Required for Headplane communication
|
|
api_key_path = "/etc/headscale/apikey";
|
|
policy.mode = "database";
|
|
};
|
|
};
|
|
# Put strict config as file for headplane
|
|
environment.etc."headscale-strict.yml".source = headscaleConfigFile;
|
|
services.nginx = {
|
|
enable = true;
|
|
virtualHosts."headscale.${domain}" = {
|
|
forceSSL = true;
|
|
enableACME = true;
|
|
locations = {
|
|
"/" = {
|
|
proxyPass = "http://127.0.0.1:${toString config.services.headscale.port}";
|
|
proxyWebsockets = true;
|
|
extraConfig = ''
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
'';
|
|
};
|
|
"/metrics" = {
|
|
proxyPass = "http://${config.services.headscale.settings.metrics_listen_addr}/metrics";
|
|
};
|
|
};
|
|
};
|
|
# Separate virtual host for Headplane UI
|
|
virtualHosts."headplane.${domain}" = {
|
|
forceSSL = true;
|
|
enableACME = true;
|
|
locations."/" = {
|
|
return = "301 http://$host/admin";
|
|
};
|
|
locations."/admin" = {
|
|
proxyPass = "http://127.0.0.1:3000";
|
|
proxyWebsockets = true;
|
|
extraConfig = ''
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "Upgrade";
|
|
'';
|
|
};
|
|
# Also proxy assets and other paths to headplane
|
|
locations."/assets" = {
|
|
proxyPass = "http://127.0.0.1:3000";
|
|
};
|
|
locations."/api" = {
|
|
proxyPass = "http://127.0.0.1:3000";
|
|
};
|
|
};
|
|
};
|
|
|
|
# configure ssl certificate options
|
|
security.acme = {
|
|
defaults.email = "dj@monumetric.com";
|
|
acceptTerms = true;
|
|
};
|
|
|
|
# punch through firewall
|
|
networking.firewall.allowedUDPPorts = [ derpPort ];
|
|
networking.firewall.allowedTCPPorts = [
|
|
80
|
|
443
|
|
];
|
|
|
|
# add headscale package to system
|
|
environment.systemPackages = [ config.services.headscale.package ];
|
|
|
|
# Ensure headscale API key exists for Headplane
|
|
systemd.services.headscale-api-key = {
|
|
description = "Generate Headscale API key for Headplane";
|
|
wantedBy = [ "multi-user.target" ];
|
|
before = [ "headplane.service" ];
|
|
after = [ "headscale.service" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
};
|
|
script = ''
|
|
if [ ! -f /etc/headscale/apikey ]; then
|
|
echo "Generating Headscale API key..."
|
|
mkdir -p /etc/headscale
|
|
${config.services.headscale.package}/bin/headscale apikeys create --expiration 999d > /etc/headscale/apikey
|
|
chmod 600 /etc/headscale/apikey
|
|
echo "API key generated at /etc/headscale/apikey"
|
|
else
|
|
echo "API key already exists"
|
|
fi
|
|
'';
|
|
};
|
|
}
|