{pkgs, ...}: let # sops-encrypted secrets (single file holds all service secrets), same as backup.nix. secretsFile = ../../secrets/secrets.yaml; # Root-only env file wg-easy reads the admin password from (0600 root). wgEnvFile = "/var/lib/wg-easy/environment"; # Materialize the wg-easy admin password from sops into a root-only env file, # so the secret never lands in the Nix store. writeSecrets = pkgs.writeShellScript "wg-easy-write-secrets" '' set -euo pipefail mkdir -p "$(dirname ${wgEnvFile})" PASSWORD="$(${pkgs.sops}/bin/sops \ --decrypt --extract '["wg_admin_password"]' \ --input-type yaml --output-type yaml ${secretsFile} | tr -d '\n')" printf 'INIT_PASSWORD=%s\n' "$PASSWORD" > "${wgEnvFile}" chmod 0600 "${wgEnvFile}" ''; in { boot.kernelModules = ["ip6table_nat"]; virtualisation.oci-containers.containers.wg-easy = { image = "ghcr.io/wg-easy/wg-easy:15"; autoStart = true; volumes = [ "/home/admin/config:/etc/wireguard:Z" ]; environmentFiles = [wgEnvFile]; environment = { INSECURE = "true"; INIT_ENABLED = "true"; INIT_USERNAME = "admin"; INIT_HOST = "severijnse.eu"; INIT_PORT = "51820"; INIT_DNS = "1.1.1.1,2606:4700:4700::1111"; INIT_IPV4_CIDR = "10.8.0.0/24"; INIT_IPV6_CIDR = "fd10:8::/64"; INIT_ALLOWED_IPS = "0.0.0.0/0, ::/0"; }; extraOptions = [ "--cap-add=NET_ADMIN" "--cap-add=SYS_MODULE" "--cap-add=NET_RAW" "--network=host" ]; }; # Materialize the wg-easy admin password from sops before the container starts. systemd.services.wg-easy-secrets = { description = "Materialize wg-easy admin password from sops"; wantedBy = ["multi-user.target"]; # The age key lives in /etc/age/keys.txt; the service must know where it is # and needs a HOME for age to report its user config directory. environment.SOPS_AGE_KEY_FILE = "/etc/age/keys.txt"; serviceConfig = { Type = "oneshot"; Environment = ["HOME=/root"]; ExecStart = "${writeSecrets}"; }; }; systemd.services."podman-wg-easy" = { requires = ["wg-easy-secrets.service"]; after = ["wg-easy-secrets.service"]; }; systemd.services.wg-nat66 = { description = "NAT66 for WireGuard IPv6"; after = ["network.target" "podman-wg-easy.service"]; wants = ["podman-wg-easy.service"]; wantedBy = ["multi-user.target"]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; script = '' ${pkgs.iptables}/bin/ip6tables -t nat -C POSTROUTING -s fd10:8::/64 -o enp1s0 -j MASQUERADE 2>/dev/null || \ ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fd10:8::/64 -o enp1s0 -j MASQUERADE ''; }; }