From ed0379556156c3566d29952b5dc0cb986119193f Mon Sep 17 00:00:00 2001 From: Felix Buehler Date: Mon, 20 Jan 2025 23:46:00 +0100 Subject: [PATCH] service/vpn: init headscale --- modules/services/default.nix | 1 + modules/services/vpn/default.nix | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 modules/services/vpn/default.nix diff --git a/modules/services/default.nix b/modules/services/default.nix index c127919..755e83b 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -41,5 +41,6 @@ ./sonarr ./ssh-server ./tandoor-recipes + ./vpn ]; } diff --git a/modules/services/vpn/default.nix b/modules/services/vpn/default.nix new file mode 100644 index 0000000..981c00e --- /dev/null +++ b/modules/services/vpn/default.nix @@ -0,0 +1,90 @@ +# self-hosted vpn +{ config, lib, ... }: +let + cfg = config.my.services.vpn; + inherit (config.networking) domain; +in +{ + options.my.services.vpn = with lib; { + enable = mkEnableOption "Headscale VPN"; + isMaster = mkEnableOption "Headscale Master"; + port = mkOption { + type = types.port; + default = 8099; + example = 8080; + description = "Internal port"; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + services.tailscale.enable = true; + } + + (lib.mkIf cfg.isMaster { + + services.headscale = { + enable = true; + inherit (cfg) port; + settings = { + dns.base_domain = "buehler.internal"; + server_url = "https://vpn.${domain}"; + metrics_listen_addr = "127.0.0.1:8095"; + log.level = "warn"; + }; + }; + + services.prometheus = { + scrapeConfigs = [ + { + job_name = "headscale"; + static_configs = [ + { + targets = [ "localhost:8095" ]; + labels = { + instance = config.networking.hostName; + }; + } + ]; + } + ]; + }; + + # Proxy to Headscale + my.services = { + nginx.virtualHosts = [ + { + subdomain = "vpn"; + inherit (cfg) port; + extraConfig = { + locations = { + "/" = { + proxyWebsockets = true; + }; + }; + }; + } + ]; + + prometheus.rules = { + HeadscaleHighErrorRate = { + condition = ''rate(headscale_http_requests_total{status=~"5.."}[5m]) > 0.1''; + description = "The error rate for Headscale server {{ $labels.instance }} is above 10% in the last 2 minutes."; + }; + }; + }; + + # waiting for a nice web-ui + # webapps.apps.vpn = { + # dashboard = { + # name = "VPN"; + # category = "infra"; + # icon = "shield-halved"; + # url = "https://vpn.${domain}"; + # }; + # }; + }) + ] + ); +}