From b3a36d9dbef837ef74740377b40e0328f9cf0817 Mon Sep 17 00:00:00 2001 From: alisceon Date: Fri, 29 May 2026 14:25:51 +0200 Subject: [PATCH 1/3] add wg support --- flake.nix | 1 + home/modules/programs/waybar/default.nix | 33 ++++++++----- nixos/modules/profiles/workstation.nix | 2 + nixos/modules/services/wireguard-peer.nix | 57 +++++++++++++++++++++++ util/toggle_wg.xsh | 25 ++++++++++ 5 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 nixos/modules/services/wireguard-peer.nix create mode 100755 util/toggle_wg.xsh diff --git a/flake.nix b/flake.nix index 5d1fcde..77d2c4f 100644 --- a/flake.nix +++ b/flake.nix @@ -57,6 +57,7 @@ mkSharedModules = pkgs: pkgs-unstable: [ ./nixos/modules/base.nix + ./nixos/modules/services/wireguard-peer.nix inputs.home-manager.nixosModules.home-manager ({ ... }: { home-manager.useGlobalPkgs = true; diff --git a/home/modules/programs/waybar/default.nix b/home/modules/programs/waybar/default.nix index 5889e60..e475dc7 100644 --- a/home/modules/programs/waybar/default.nix +++ b/home/modules/programs/waybar/default.nix @@ -1,8 +1,9 @@ -{ pkgs, ... }: +{ pkgs, repoRoot, ... }: let commands = import ../../../../lib/commands.nix { inherit pkgs; }; inherit (commands) uwsm term; height = 20; + wireguardToggle = "${pkgs.xonsh}/bin/xonsh ${repoRoot}/util/toggle_wg.xsh"; in { imports = [ @@ -37,6 +38,7 @@ in "clock" "sway/language" "network" + "custom/wireguard" "bluetooth" "pulseaudio" "idle_inhibitor" @@ -53,7 +55,7 @@ in spacing = 8; }; idle_inhibitor = { - format = "| {icon}"; + format = "| {icon} "; start-activated = true; format-icons = { activated = "🫨"; @@ -61,7 +63,7 @@ in }; }; "sway/language" = { - format = "| {short}"; + format = "| {short} "; tooltip-format = "{long}"; }; clock = { @@ -72,29 +74,36 @@ in }; battery = { interval = 60; - format = "| {capacity}%"; + format = "| {capacity}% "; format-charging = "| ch:{capacity}%"; }; network = { tooltip-format = "{ifname} = {ipaddr}/{cidr}"; - format-wifi = "| w:{ipaddr}"; - format-ethernet = "| e:{ipaddr}"; - format-linked = "| l:{ipaddr}"; - format-disconnected = "| d"; + format-wifi = "| w:{essid} "; + format-ethernet = "| e:{ipaddr} "; + format-linked = "| l:{ipaddr} "; + format-disconnected = "| d "; interval = 15; on-click = "${uwsm} ${term} -e nmtui"; }; + "custom/wireguard" = { + exec = "${wireguardToggle} status"; + on-click = "${wireguardToggle} toggle"; + format = "| wg:{text} "; + interval = 15; + tooltip = false; + }; bluetooth = { - format = "| bt:{num_connections}"; + format = "| bt:{num_connections} "; format-disabled = ""; format-no-controller = ""; interval = 15; on-click = "${uwsm} ${term} -e bluetui"; }; pulseaudio = { - format = "| snd{volume}%"; - format-muted = "| snd:-"; - format-bluetooth = "| snd(bt):{volume}%"; + format = "| snd{volume}% "; + format-muted = "| snd:- "; + format-bluetooth = "| snd(bt):{volume}% "; on-click = "${uwsm} pavucontrol"; }; }; diff --git a/nixos/modules/profiles/workstation.nix b/nixos/modules/profiles/workstation.nix index d39d714..2fadb28 100644 --- a/nixos/modules/profiles/workstation.nix +++ b/nixos/modules/profiles/workstation.nix @@ -24,6 +24,8 @@ in security.sudo.wheelNeedsPassword = false; + alisceon.wireguardPeer.enable = true; + services = { printing.enable = true; pulseaudio.enable = false; diff --git a/nixos/modules/services/wireguard-peer.nix b/nixos/modules/services/wireguard-peer.nix new file mode 100644 index 0000000..65d07a1 --- /dev/null +++ b/nixos/modules/services/wireguard-peer.nix @@ -0,0 +1,57 @@ +{ config, lib, pkgs, repoLocalPath, ... }: + +let + cfg = config.alisceon.wireguardPeer; +in +{ + options.alisceon.wireguardPeer = { + enable = lib.mkEnableOption "a single WireGuard peer managed by wg-quick"; + + interface = lib.mkOption { + type = lib.types.str; + default = "wg0"; + description = "WireGuard interface name."; + }; + + configFile = lib.mkOption { + type = lib.types.str; + default = "/etc/wireguard/${cfg.interface}.conf"; + defaultText = "/etc/wireguard/.conf"; + description = '' + Path to an external wg-quick config file. Keep it root-owned and mode + 0600 so private keys and peer material stay outside Git and the Nix store. + ''; + }; + + autostart = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Whether to bring the WireGuard interface up at boot."; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = lib.hasPrefix "/" cfg.configFile; + message = "alisceon.wireguardPeer.configFile must be an absolute path outside the repo."; + } + { + assertion = !(lib.hasPrefix repoLocalPath cfg.configFile); + message = "alisceon.wireguardPeer.configFile must be outside ${repoLocalPath}."; + } + ]; + + networking.wg-quick.interfaces.${cfg.interface} = { + inherit (cfg) autostart configFile; + }; + + systemd.services."wg-quick-${cfg.interface}".unitConfig.ConditionPathExists = cfg.configFile; + + environment.systemPackages = [ pkgs.wireguard-tools ]; + + systemd.tmpfiles.rules = [ + "d /etc/wireguard 0700 root root -" + ]; + }; +} diff --git a/util/toggle_wg.xsh b/util/toggle_wg.xsh new file mode 100755 index 0000000..bc88bc4 --- /dev/null +++ b/util/toggle_wg.xsh @@ -0,0 +1,25 @@ +import sys + +isup = "does not exist." not in $(ip link show dev wg0 2>&1) + +try: + match sys.argv[1]: + case "toggle": + if isup: + footclient wg-quick down wg0 + else: + footclient wg-quick up wg0 + case "status": + if isup: + print("u") + else: + print("d") + case _: + raise RuntimeError + +except (RuntimeError, IndexError): + print('"toggle" or "status" must be provided') + exit(1) + +exit(0) + From ec5edefad8c769a39e8812e4c8226ecec330d63e Mon Sep 17 00:00:00 2001 From: alisceon Date: Fri, 29 May 2026 14:42:02 +0200 Subject: [PATCH 2/3] small fix for waybar widget --- home/modules/programs/waybar/default.nix | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/home/modules/programs/waybar/default.nix b/home/modules/programs/waybar/default.nix index e475dc7..e2def8f 100644 --- a/home/modules/programs/waybar/default.nix +++ b/home/modules/programs/waybar/default.nix @@ -36,12 +36,12 @@ in }; "modules" = [ "clock" + "idle_inhibitor" "sway/language" "network" "custom/wireguard" "bluetooth" "pulseaudio" - "idle_inhibitor" ]; }; "sway/workspaces" = { @@ -63,7 +63,8 @@ in }; }; "sway/language" = { - format = "| {short} "; + # this one gobbles all trailing ascii whitespace for some reason. use this unicode instead + format = "| {short} "; tooltip-format = "{long}"; }; clock = { @@ -75,14 +76,14 @@ in battery = { interval = 60; format = "| {capacity}% "; - format-charging = "| ch:{capacity}%"; + format-charging = "| ch:{capacity}% "; }; network = { tooltip-format = "{ifname} = {ipaddr}/{cidr}"; format-wifi = "| w:{essid} "; format-ethernet = "| e:{ipaddr} "; format-linked = "| l:{ipaddr} "; - format-disconnected = "| d "; + format-disconnected = "| w:d "; interval = 15; on-click = "${uwsm} ${term} -e nmtui"; }; From 6c60161d1a12f77b587b1c6f3dee89fd3fea2bdc Mon Sep 17 00:00:00 2001 From: alisceon Date: Fri, 29 May 2026 15:17:42 +0200 Subject: [PATCH 3/3] add syncthing to alisceon-core --- nixos/hosts/alisceon-core/configuration.nix | 76 ++++++++++++++++++++- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/nixos/hosts/alisceon-core/configuration.nix b/nixos/hosts/alisceon-core/configuration.nix index 8468905..50b0fa4 100644 --- a/nixos/hosts/alisceon-core/configuration.nix +++ b/nixos/hosts/alisceon-core/configuration.nix @@ -1,7 +1,7 @@ { lib, pkgs, modulesPath, ... }: let forgejoDomain = "git.alisceon.com"; - forgejoRunnerTokenFile = "/var/lib/forgejo/runner_token"; + syncthingDomain = "syncthing.alisceon.com"; fetchOciAuthorizedKeys = pkgs.writeShellApplication { name = "fetch-oci-authorized-keys"; @@ -34,7 +34,7 @@ let pkgs.util-linux ]; text = '' - token_file=${lib.escapeShellArg forgejoRunnerTokenFile} + token_file=${lib.escapeShellArg "/var/lib/forgejo/runner_token"} if [ -s "$token_file" ]; then chmod 0600 "$token_file" @@ -69,8 +69,12 @@ in 22 80 443 + 22000 24601 ]; + firewall.allowedUDPPorts = [ + 22000 + ]; }; boot = { @@ -123,6 +127,32 @@ in PermitRootLogin = lib.mkForce "prohibit-password"; }; + services.syncthing = { + enable = true; + dataDir = "/var/lib/syncthing"; + guiAddress = "127.0.0.1:8384"; + openDefaultPorts = false; + overrideDevices = false; + overrideFolders = false; + settings = { + gui = { + insecureAdminAccess = false; + insecureSkipHostcheck = false; + }; + options = { + globalAnnounceEnabled = false; + localAnnounceEnabled = false; + listenAddresses = [ + "tcp://0.0.0.0:22000" + "quic://0.0.0.0:22000" + ]; + natEnabled = false; + relaysEnabled = false; + urAccepted = -1; + }; + }; + }; + services.forgejo = { enable = true; package = pkgs.forgejo-lts; @@ -164,7 +194,7 @@ in enable = true; name = "alisceon-core-podman"; url = "https://${forgejoDomain}"; - tokenFile = forgejoRunnerTokenFile; + tokenFile = "/var/lib/forgejo/runner_token"; labels = [ "ubuntu-latest:docker://node:22-bookworm" "debian-latest:docker://node:22-bookworm" @@ -203,6 +233,24 @@ in recommendedProxySettings = true; }; }; + ${syncthingDomain} = { + serverName = syncthingDomain; + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://127.0.0.1:8384"; + recommendedProxySettings = false; + extraConfig = '' + proxy_set_header Host $proxy_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-Host $host; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + ''; + }; + }; }; }; @@ -264,6 +312,28 @@ in systemd.services.fetch-ssh-keys.enable = false; + systemd.services.syncthing = { + serviceConfig = { + LockPersonality = true; + PrivateIPC = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectHome = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = [ "/var/lib/syncthing" ]; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + "AF_UNIX" + ]; + SystemCallArchitectures = "native"; + UMask = "0077"; + }; + }; + systemd.services.forgejo-runner-token = { description = "Generate Forgejo runner registration token"; wantedBy = [ "multi-user.target" ];