Compare commits

...

3 commits

Author SHA1 Message Date
alisceon
6c60161d1a add syncthing to alisceon-core 2026-05-29 15:17:42 +02:00
alisceon
ec5edefad8 small fix for waybar widget 2026-05-29 14:42:02 +02:00
alisceon
b3a36d9dbe add wg support 2026-05-29 14:25:51 +02:00
6 changed files with 182 additions and 17 deletions

View file

@ -57,6 +57,7 @@
mkSharedModules = pkgs: pkgs-unstable: [ mkSharedModules = pkgs: pkgs-unstable: [
./nixos/modules/base.nix ./nixos/modules/base.nix
./nixos/modules/services/wireguard-peer.nix
inputs.home-manager.nixosModules.home-manager inputs.home-manager.nixosModules.home-manager
({ ... }: { ({ ... }: {
home-manager.useGlobalPkgs = true; home-manager.useGlobalPkgs = true;

View file

@ -1,8 +1,9 @@
{ pkgs, ... }: { pkgs, repoRoot, ... }:
let let
commands = import ../../../../lib/commands.nix { inherit pkgs; }; commands = import ../../../../lib/commands.nix { inherit pkgs; };
inherit (commands) uwsm term; inherit (commands) uwsm term;
height = 20; height = 20;
wireguardToggle = "${pkgs.xonsh}/bin/xonsh ${repoRoot}/util/toggle_wg.xsh";
in in
{ {
imports = [ imports = [
@ -35,11 +36,12 @@ in
}; };
"modules" = [ "modules" = [
"clock" "clock"
"idle_inhibitor"
"sway/language" "sway/language"
"network" "network"
"custom/wireguard"
"bluetooth" "bluetooth"
"pulseaudio" "pulseaudio"
"idle_inhibitor"
]; ];
}; };
"sway/workspaces" = { "sway/workspaces" = {
@ -61,7 +63,8 @@ in
}; };
}; };
"sway/language" = { "sway/language" = {
format = "| {short}"; # this one gobbles all trailing ascii whitespace for some reason. use this unicode instead
format = "| {short}";
tooltip-format = "{long}"; tooltip-format = "{long}";
}; };
clock = { clock = {
@ -77,13 +80,20 @@ in
}; };
network = { network = {
tooltip-format = "{ifname} = {ipaddr}/{cidr}"; tooltip-format = "{ifname} = {ipaddr}/{cidr}";
format-wifi = "| w:{ipaddr}"; format-wifi = "| w:{essid} ";
format-ethernet = "| e:{ipaddr} "; format-ethernet = "| e:{ipaddr} ";
format-linked = "| l:{ipaddr} "; format-linked = "| l:{ipaddr} ";
format-disconnected = "| d"; format-disconnected = "| w:d ";
interval = 15; interval = 15;
on-click = "${uwsm} ${term} -e nmtui"; on-click = "${uwsm} ${term} -e nmtui";
}; };
"custom/wireguard" = {
exec = "${wireguardToggle} status";
on-click = "${wireguardToggle} toggle";
format = "| wg:{text} ";
interval = 15;
tooltip = false;
};
bluetooth = { bluetooth = {
format = "| bt:{num_connections} "; format = "| bt:{num_connections} ";
format-disabled = ""; format-disabled = "";

View file

@ -1,7 +1,7 @@
{ lib, pkgs, modulesPath, ... }: { lib, pkgs, modulesPath, ... }:
let let
forgejoDomain = "git.alisceon.com"; forgejoDomain = "git.alisceon.com";
forgejoRunnerTokenFile = "/var/lib/forgejo/runner_token"; syncthingDomain = "syncthing.alisceon.com";
fetchOciAuthorizedKeys = pkgs.writeShellApplication { fetchOciAuthorizedKeys = pkgs.writeShellApplication {
name = "fetch-oci-authorized-keys"; name = "fetch-oci-authorized-keys";
@ -34,7 +34,7 @@ let
pkgs.util-linux pkgs.util-linux
]; ];
text = '' text = ''
token_file=${lib.escapeShellArg forgejoRunnerTokenFile} token_file=${lib.escapeShellArg "/var/lib/forgejo/runner_token"}
if [ -s "$token_file" ]; then if [ -s "$token_file" ]; then
chmod 0600 "$token_file" chmod 0600 "$token_file"
@ -69,8 +69,12 @@ in
22 22
80 80
443 443
22000
24601 24601
]; ];
firewall.allowedUDPPorts = [
22000
];
}; };
boot = { boot = {
@ -123,6 +127,32 @@ in
PermitRootLogin = lib.mkForce "prohibit-password"; 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 = { services.forgejo = {
enable = true; enable = true;
package = pkgs.forgejo-lts; package = pkgs.forgejo-lts;
@ -164,7 +194,7 @@ in
enable = true; enable = true;
name = "alisceon-core-podman"; name = "alisceon-core-podman";
url = "https://${forgejoDomain}"; url = "https://${forgejoDomain}";
tokenFile = forgejoRunnerTokenFile; tokenFile = "/var/lib/forgejo/runner_token";
labels = [ labels = [
"ubuntu-latest:docker://node:22-bookworm" "ubuntu-latest:docker://node:22-bookworm"
"debian-latest:docker://node:22-bookworm" "debian-latest:docker://node:22-bookworm"
@ -203,6 +233,24 @@ in
recommendedProxySettings = true; 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.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 = { systemd.services.forgejo-runner-token = {
description = "Generate Forgejo runner registration token"; description = "Generate Forgejo runner registration token";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];

View file

@ -24,6 +24,8 @@ in
security.sudo.wheelNeedsPassword = false; security.sudo.wheelNeedsPassword = false;
alisceon.wireguardPeer.enable = true;
services = { services = {
printing.enable = true; printing.enable = true;
pulseaudio.enable = false; pulseaudio.enable = false;

View file

@ -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/<interface>.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 -"
];
};
}

25
util/toggle_wg.xsh Executable file
View file

@ -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)