# heather — сервер на Yandex Cloud (NixOS 26.11). # https://git.iscg.dev/mikl/nix-config # # Перенесено из muscari (переименование 2026-07-11). # VM на Yandex Cloud, 2 vCPU / 8 GB / 64 GB SSD (network-ssd), Legacy BIOS. # Образ NixOS собирается как qcow2 (см. ./image.nix, make-disk-image.nix) и # заливается как boot disk в YC. НЕ через nixos-anywhere — kexec на YC хрупкий. # См. memory/yandex-nixos-qcow2.md. # # Архитектура (2026-07-12, заменила k3s): # Caddy (edge, TLS) → host-сервисы (syncthing) + docker-контейнеры (arion) # Cilium/k3s выключены — overhead 1.3 GB был неоправдан для single-node. # См. ./docker.nix, ./caddy.nix, ./syncthing.nix, ./arion-compose.nix. { config, pkgs, lib, ... }: { imports = [ ./image.nix # YC guest profile + qcow2 build target ./docker.nix # docker + arion CLI (контейнеры) ./caddy.nix # edge proxy, TLS, роутинг по доменам ./syncthing.nix # sync + relay ./tuwunel-admin.nix # matrix admin web UI (systemd, статический бинарник) ./pi-web.nix # pi-web (web UI для pi coding agent, systemd + npm global) ./mesh-clients.nix # Sol-style client pool (wg-clients1) ]; # First server-to-server WireGuard backbone link: heather ↔ hyacinth. # The private key is generated on the live host and stays outside the flake. environment.systemPackages = [ pkgs.wireguard-tools ]; # NixOS uses scripted networking here (not systemd-networkd), so create the # dummy identity interface through a small idempotent systemd unit. systemd.services.mesh-identity = { description = "Create mesh identity interface"; wantedBy = [ "network.target" ]; after = [ "wireguard-wg-mesh.service" "network-addresses-wg-mesh.service" ]; wants = [ "wireguard-wg-mesh.service" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStart = pkgs.writeShellScript "mesh-identity-up" '' set -eu ${pkgs.iproute2}/bin/ip link show mesh0 >/dev/null 2>&1 || ${pkgs.iproute2}/bin/ip link add mesh0 type dummy ${pkgs.iproute2}/bin/ip addr replace 10.0.0.1/32 dev mesh0 ${pkgs.iproute2}/bin/ip link set mesh0 up ''; ExecStop = "${pkgs.iproute2}/bin/ip link del mesh0"; }; }; networking.wireguard.interfaces.wg-mesh = { ips = [ "10.99.0.1/30" ]; listenPort = 51820; privateKeyFile = "/var/lib/wireguard/wg-mesh.key"; # Keep WG as transport/crypto ACL; install the identity route explicitly below. allowedIPsAsRoutes = false; peers = [ { publicKey = "BxTH8+MiA8Hv48UfpWJDVXIhbO5HgO2KTBEXIqqr23k="; allowedIPs = [ "10.99.0.2/32" "10.0.0.2/32" ]; endpoint = "195.242.119.59:51820"; persistentKeepalive = 25; } ]; }; networking.interfaces.wg-mesh.ipv4.routes = [ { address = "10.0.0.2"; prefixLength = 32; } ]; # Needed later when this node becomes a transit/exit peer. boot.kernel.sysctl."net.ipv4.ip_forward" = 1; # Arion-проект как systemd-сервис: arion-compose.nix → docker-compose → up. # NB: settings — это модуль с imports, НЕ `import ./arion-compose.nix`. virtualisation.arion.backend = "docker"; virtualisation.arion.projects.heather = { serviceName = "heather"; # systemd: arion-heather.service settings = { imports = [ ./arion-compose.nix ]; }; }; networking = { hostName = "heather"; # Firewall выключен в ./image.nix (полагаемся на YC Security Groups). # Порты тут только для документации — реально открывает YC SG. firewall.allowedTCPPorts = [ 22 # SSH 80 # HTTP (Caddy → redirect to HTTPS) 443 # HTTPS (Caddy, TLS termination) 2222 # forgejo git ssh (публично) 22000 # syncthing sync 22067 # strelaysrv (relay) 22070 # strelaysrv (status) 3478 # coturn TURN (tcp+udp) 8443 # xray VLESS+Reality (публичный прокси) 51820 # WireGuard mesh backbone ]; firewall.allowedUDPPorts = [ 51820 # WireGuard mesh backbone 22000 # syncthing sync (QUIC) 10000 # jitsi jvb (RTP media) 3478 # coturn TURN ]; # coturn RTP relay range firewall.allowedUDPPortRanges = [ { from = 49152; to = 65535; } # coturn RTP relay ]; }; # useDHCP задаёт ./image.nix (mkDefault) — облачный профиль. # SSH ключи для mikl: forgejo .keys endpoint с sha256-pinning. # Poppy-ключ (этот ноутбук) лежит там последней строкой. users.users.mikl.openssh.authorizedKeys.keyFiles = [ (pkgs.fetchurl { url = "https://git.iscg.dev/mikl.keys"; sha256 = "sha256-Omc/3NJn0nM8SWeF33trFwOAVgSX0fXB5dfEakcRoTA="; }) ]; # Rescue-канал: root с тем же poppy-ключом. PermitRootLogin = prohibit-password # (см. image.nix) пускает root только по ключу — парольного root-логина нет. # Нужен, чтобы не оказаться запертым без root, если passwordless sudo сломается # (как произошло на первом образе heather): ssh root@heather и nixos-rebuild. users.users.root.openssh.authorizedKeys.keyFiles = [ (pkgs.fetchurl { url = "https://git.iscg.dev/mikl.keys"; sha256 = "sha256-Omc/3NJn0nM8SWeF33trFwOAVgSX0fXB5dfEakcRoTA="; }) ]; # После первой установки 25.11 не трогаем (NixOS convention) system.stateVersion = "25.11"; }