diff --git a/flake.lock b/flake.lock index 58bc92c..0198836 100644 --- a/flake.lock +++ b/flake.lock @@ -1,64 +1,5 @@ { "nodes": { - "arion": { - "inputs": { - "flake-parts": "flake-parts", - "haskell-flake": "haskell-flake", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1770259557, - "narHash": "sha256-EvZ09k9+mzXAngPzU2K7oLLUDlKoT1numb4bDb3Gtl4=", - "owner": "hercules-ci", - "repo": "arion", - "rev": "9b24cf65c72cb0e9616e437d55e1ac8e5c6bc715", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "arion", - "type": "github" - } - }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": [ - "arion", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1769996383, - "narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "57928607ea566b5db3ad13af0e57e921e6b12381", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "haskell-flake": { - "locked": { - "lastModified": 1675296942, - "narHash": "sha256-u1X1sblozi5qYEcLp1hxcyo8FfDHnRUVX3dJ/tW19jY=", - "owner": "srid", - "repo": "haskell-flake", - "rev": "c2cafce9d57bfca41794dc3b99c593155006c71e", - "type": "github" - }, - "original": { - "owner": "srid", - "ref": "0.1.0", - "repo": "haskell-flake", - "type": "github" - } - }, "home-manager": { "inputs": { "nixpkgs": [ @@ -117,7 +58,6 @@ }, "root": { "inputs": { - "arion": "arion", "home-manager": "home-manager", "nix-darwin": "nix-darwin", "nixpkgs": "nixpkgs", diff --git a/flake.nix b/flake.nix index 5be75f6..0810722 100644 --- a/flake.nix +++ b/flake.nix @@ -18,15 +18,10 @@ url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; - - arion = { - url = "github:hercules-ci/arion"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; outputs = - { self, nixpkgs, nix-darwin, home-manager, sops-nix, arion, ... }: + { self, nixpkgs, nix-darwin, home-manager, sops-nix, ... }: let mkNixos = hostname: nixpkgs.lib.nixosSystem { @@ -36,7 +31,6 @@ ./hosts/${hostname} sops-nix.nixosModules.sops home-manager.nixosModules.home-manager - arion.nixosModules.arion { home-manager = { useGlobalPkgs = true; diff --git a/home/git.nix b/home/git.nix index f621d30..35f2d35 100644 --- a/home/git.nix +++ b/home/git.nix @@ -1,17 +1,10 @@ { pkgs, ... }: { - # git-lfs на PATH (home-manager пакеты лежат в /etc/profiles/per-user/mikl/bin, - # он уже в home.sessionPath). lfs.package = null заставляет модуль генерить - # каноничную строку "git-lfs clean -- %f" вместо абсолютного nix-store пути — - # иначе git-lfs 3.7+ сыплет warning'ом при каждом вызове. - home.packages = [ pkgs.git-lfs ]; - programs.git = { enable = true; # Git LFS support lfs.enable = true; - lfs.package = null; settings = { user = { diff --git a/hosts/heather/arion-compose.nix b/hosts/heather/arion-compose.nix deleted file mode 100644 index b60b4ef..0000000 --- a/hosts/heather/arion-compose.nix +++ /dev/null @@ -1,127 +0,0 @@ -# heather — Arion compose (nix-native docker-compose). -# -# Все web-apps в docker-контейнерах, описаны декларативно в nix. -# Запускается как systemd-сервис через virtualisation.arion.projects.heather. -# -# Порты проброшены на localhost (127.0.0.1:PORT) — Caddy на хосте терминирует -# TLS и роутит по Host (см. caddy.nix). Контейнеры НЕ выставлены наружу -# напрямую (кроме jitsi UDP 10000/19132 — см. jitsi ниже, когда добавим). -# -# Data: named volumes везде, кроме silverbullet (bind mount на syncthing -# sync'аемую папку /srv/syncthing/herbarium — исключение, см. комментарии). -# -# Backup: offen/docker-volume-backup как sidecar, nightly tar.gz всех named -# volumes → /var/backups (добавим последним). -# -# Порядок миграции: forgejo → tuwunel+admin → cinny → jitsi → teable → -# silverbullet. Ниже forgejo как первый proof-of-concept, остальные добавим -# по мере миграции (секции заготовлены, закомментированы до теста). - -{ pkgs, ... }: - -{ - # Named volumes объявляются автоматически docker-compose при упоминании в - # services..service.volumes. Имена префиксуются проектом (heather_forgejo-data) - # — видно в `docker volume ls`. Никаких анонимных хэшей. - - services = { - # === Forgejo (git.iscg.dev) === - # Первый сервис, proof-of-concept для цепочки arion→docker→Caddy. - forgejo = { - service.image = "codeberg.org/forgejo/forgejo:9"; - service.container_name = "forgejo"; - service.restart = "unless-stopped"; - service.volumes = [ "forgejo-data:/data" ]; - service.ports = [ - "127.0.0.1:3030:3000" # web → Caddy git.iscg.dev - "2222:22" # git ssh (публично, как на jul11) - ]; - service.environment = { - # Домен для клонов: ssh://git@git.iscg.dev:2222/... - FORGEJO__server__DOMAIN = "git.iscg.dev"; - FORGEJO__server__ROOT_URL = "https://git.iscg.dev/"; - FORGEJO__server__SSH_DOMAIN = "git.iscg.dev"; - FORGEJO__server__SSH_PORT = "2222"; - }; - }; - - # === Matrix tuwunel + admin + cinny (iscg.dev, admin/chat.iscg.dev) === - # Добавить после forgejo. Crashloop на jul11 — нужно разобраться с - # конфигом/секретами до миграции. См. migration-inventory.md. - # - # tuwunel = { - # service.image = "ghcr.io/matrix-construct/tuwunel:v1.7.1"; - # service.container_name = "tuwunel"; - # service.restart = "unless-stopped"; - # service.volumes = [ - # "tuwunel-data:/data" - # "tuwunel-media-cache:/media-cache" - # ]; - # service.ports = [ "127.0.0.1:8008:8008" ]; - # # TODO: env vars, secrets (server_name, registration_shared_secret, ...) - # }; - - # cinny = { - # service.image = "ajbura/cinny:latest"; - # service.container_name = "cinny"; - # service.restart = "unless-stopped"; - # service.ports = [ "127.0.0.1:8080:80" ]; - # }; - - # tuwunel-admin был systemd на jul11 (knadh/tuwunel-admin). Если контейнер - # существует — добавить сюда, иначе оставить как NixOS-сервис или выкинуть. - - # === Jitsi Meet (jitsi.iscg.dev) === - # Стек: web, jicofo, prosody, jvb, coturn. На jul11 был конфликт :3478 - # (systemd coturn + docker stack-coturn). На heather — только docker coturn - # внутри стека, systemd coturn НЕ поднимаем. Добавить отдельнымcompose-файлом - # или секцией после forgejo. - - # === Teable (teable.iscg.dev) === - # Тяжёлый стек: app + postgres + redis. Добавить после forgejo. - # - # teable = { - # service.image = "teableio/teable:latest"; - # service.container_name = "teable"; - # service.restart = "unless-stopped"; - # service.ports = [ "127.0.0.1:2345:3000" ]; - # service.volumes = [ "teable-data:/app/data" ]; - # service.depends_on = [ "teable-db" "teable-redis" ]; - # # TODO: env (DATABASE_URL, REDIS_URL, SECRET_KEY, PUBLIC_ORIGIN, ...) - # }; - # teable-db = { - # service.image = "postgres:15-alpine"; - # service.container_name = "teable-db"; - # service.restart = "unless-stopped"; - # service.volumes = [ "teable-db:/var/lib/postgresql/data" ]; - # # TODO: POSTGRES_PASSWORD (sops) - # }; - # teable-redis = { - # service.image = "redis:alpine"; - # service.container_name = "teable-redis"; - # service.restart = "unless-stopped"; - # service.volumes = [ "teable-redis:/data" ]; - # }; - - # === Silverbullet (note.iscg.dev) — ИСКЛЮЧЕНИЕ: bind mount === - # Space = /srv/syncthing/herbarium (sync'ается syncthing на устройства). - # Единственный сервис без named volume — по твоему решению, чтобы notes - # были доступны и через web UI, и через obsidian/vscode на poppy. - # Конфликты syncthing (одновременная правка) решаются через .sync-conflict. - # - # silverbullet = { - # service.image = "zefhemel/silverbullet:latest"; - # service.container_name = "silverbullet"; - # service.restart = "unless-stopped"; - # service.ports = [ "127.0.0.1:3001:3000" ]; - # service.volumes = [ - # "/srv/syncthing/herbarium:/space" # bind mount, НЕ named volume - # ]; - # }; - - # === Backup sidecar (последним) === - # offen/docker-volume-backup: nightly tar.gz всех named volumes. - # Монтирует volumes read-only, шлёт в /var/backups (или S3). - # TODO: добавить когда основные сервисы мигрированы. - }; -} diff --git a/hosts/heather/caddy.nix b/hosts/heather/caddy.nix deleted file mode 100644 index b336658..0000000 --- a/hosts/heather/caddy.nix +++ /dev/null @@ -1,85 +0,0 @@ -# heather — Caddy как единый edge (TLS termination, reverse proxy). -# -# Заменяет Traefik (k3s built-in, отключён) и старые Caddy на iscg-dev/jul11. -# Паттерн как на iscg-dev: system Caddy, конфиг декларативно в nix. -# -# Caddy терминирует TLS на :80/:443 и роутит по Host на: -# - host-сервисы (syncthing GUI на localhost:8384) — напрямую -# - docker-контейнеры (forgejo на localhost:3030 и т.д.) — проброшенные порты -# -# ACME: пока staging (чтобы не забанили Let's Encrypt пока DNS не переведён на -# heather). Когда A-записи iscg.dev → 51.250.45.111 — переключим на production -# (убрать acme_ca, Caddy использует production LE по умолчанию). - -{ config, pkgs, lib, ... }: - -let - # caddy/basic-auth под паролем. hash сгенерить: - # caddy hash-password - # Пока заглушка — syncthing GUI имеет свой пароль + Caddy basicauth сверху. - syncBasicAuth = '' - basicauth { - mikl $2a$14$bQ5MVsSFUuIJjHETVXzISOTy5SpLxRUlH6krxpzLH1.E0imi37Zb. - } - ''; - -in { - services.caddy = { - enable = true; - # Staging ACME пока DNS не переведён на heather (см. комментарий выше). - # Для production: убрать acme_ca, Caddy сам использует Let's Encrypt. - acmeCA = "https://acme-staging-v02.api.letsencrypt.org/directory"; - email = "mikl@iscg.dev"; - - virtualHosts = { - # --- Syncthing GUI (host-сервис) --- - "sync.iscg.dev".extraConfig = syncBasicAuth + '' - reverse_proxy 127.0.0.1:8384 - ''; - - # --- Контейнеры (arion, см. arion-compose.nix) --- - # Forgejo - "git.iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:3030 - ''; - - # Matrix tuwunel (homeserver) - "iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:8008 - encode zstd gzip - ''; - - # Matrix federation - "iscg.dev:8448".extraConfig = '' - reverse_proxy 127.0.0.1:8008 - ''; - - # tuwunel-admin - "admin.iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:8009 - ''; - - # Cinny (matrix web client) - "chat.iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:8080 - encode zstd gzip - ''; - - # Jitsi Meet - "jitsi.iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:8000 - encode zstd gzip - ''; - - # Teable - "teable.iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:2345 - ''; - - # Silverbullet - "note.iscg.dev".extraConfig = '' - reverse_proxy 127.0.0.1:3001 - ''; - }; - }; -} diff --git a/hosts/heather/default.nix b/hosts/heather/default.nix index 7427da8..a0d0c8b 100644 --- a/hosts/heather/default.nix +++ b/hosts/heather/default.nix @@ -1,4 +1,4 @@ -# heather — сервер на Yandex Cloud (NixOS 26.11). +# heather — k3s single-node cluster на YC (NixOS 25.11, собирается как qcow2-образ) # https://git.iscg.dev/mikl/nix-config # # Перенесено из muscari (переименование 2026-07-11). @@ -6,48 +6,21 @@ # Образ 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 + ./image.nix # YC guest profile + qcow2 build target (заменяет disk-config.nix) + ./k3s.nix ]; - # 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) - # jitsi (когда добавим): 3478, 5349, 10000/udp, 49152-65535/udp - ]; - firewall.allowedUDPPorts = [ - 22000 # syncthing sync (QUIC) - # jitsi: 10000 (jvb), 49152-65535 (RTP) + 22 # SSH + 80 # HTTP (Ingress через Traefik) + 443 # HTTPS (Ingress через Traefik) + # 6443 не открываем — kubectl через SSH-туннель ]; }; # useDHCP задаёт ./image.nix (mkDefault) — облачный профиль. @@ -74,4 +47,4 @@ # После первой установки 25.11 не трогаем (NixOS convention) system.stateVersion = "25.11"; -} +} \ No newline at end of file diff --git a/hosts/heather/docker.nix b/hosts/heather/docker.nix deleted file mode 100644 index 63cfdd8..0000000 --- a/hosts/heather/docker.nix +++ /dev/null @@ -1,29 +0,0 @@ -# heather — docker + arion (nix-native docker-compose) -# -# Заменило k3s (2026-07-12): k3s сжирал 1.3 GB (16% от 8 GB) на single-node -# без реальной выгоды. docker+arion даёт ~100 MB overhead и знакомую модель. -# Caddy на хосте терминирует TLS (см. ./caddy.nix), Traefik/ServiceLB не нужны. -# -# Arion: читает arion-compose.nix (nix-выражение), генерирует docker-compose, -# запускает как systemd-сервис через virtualisation.arion.projects. -# Контейнеры описаны в ./arion-compose.nix. - -{ pkgs, ... }: -{ - virtualisation.docker = { - enable = true; - # Хост-docker (не rootless): mikl в группе docker для `docker` CLI без sudo. - # arion-проект запускается от root через systemd (см. ниже). - }; - - # Arion: nix-native docker-compose. backend задаётся в default.nix - # (virtualisation.arion.backend = "docker"), проект — там же. - - # mikl может управлять docker без sudo (docker group). - users.users.mikl.extraGroups = [ "docker" ]; - - environment.systemPackages = with pkgs; [ - docker-compose - arion - ]; -} diff --git a/hosts/heather/k3s.nix b/hosts/heather/k3s.nix new file mode 100644 index 0000000..40a604c --- /dev/null +++ b/hosts/heather/k3s.nix @@ -0,0 +1,34 @@ +# k3s daemon для heather (single-node + Cilium CNI) +# Traefik и servicelb остаются включены (встроенные в k3s) +# Cilium ставится отдельно через Helm после старта k3s + +{ config, pkgs, lib, ... }: +{ + services.k3s = { + enable = true; + extraFlags = [ + # CNI: отключаем встроенный flannel, ставим Cilium отдельно + "--flannel-backend=none" + "--disable-network-policy" # Cilium сам делает network policy + + # CIDR для подов и сервисов (default для k3s, но фиксируем явно) + "--cluster-cidr=10.42.0.0/16" + "--service-cidr=10.43.0.0/16" + + # TLS SANs для kubectl (если подключаемся не только по IP) + "--tls-san=heather.iscg.dev" + ]; + }; + + # Firewall выключен в ./image.nix (полагаемся на YC Security Groups). + # Cilium управляет pod-сетью через BPF, локальный iptables-firewall ему + # только мешает — поэтому блок trustedInterfaces/checkReversePath не нужен. + + # k3s-specific пакеты (НЕ в common — только для хостов с k3s) + environment.systemPackages = with pkgs; [ + kubectl + kubernetes-helm + kustomize + sops # для шифрования k8s secrets (если будем через SOPS) + ]; +} \ No newline at end of file diff --git a/hosts/heather/syncthing.nix b/hosts/heather/syncthing.nix deleted file mode 100644 index 2461d84..0000000 --- a/hosts/heather/syncthing.nix +++ /dev/null @@ -1,69 +0,0 @@ -# heather — Syncthing (sync + relay) как NixOS-сервис. -# -# Заменяет syncthing@michaotic + strelaysrv с iscg-dev. -# -# - services.syncthing: sync daemon. dataDir = /srv/syncthing (синкается на -# устройства poppy/телефон). configDir = /var/lib/syncthing (state syncthing). -# - relayOptions.enable: strelaysrv, public relay на :22067 (relay) / :22070 -# (status). Для устройств за NAT. -# -# GUI: 127.0.0.1:8384 (только localhost), Caddy проксирует на sync.iscg.dev -# с basicauth сверху (см. caddy.nix). Пароль GUI включить отдельно (syncthing -# сам требует при прослушивании не-localhost, но на localhost опционален — -# Caddy даёт внешний слой auth). -# -# /srv/syncthing/herbarium/ — silverbullet space (bind mount в контейнер, -# см. arion-compose.nix). syncthing sync'ает весь /srv/syncthing включая -# herbarium на устройства. - -{ config, pkgs, lib, ... }: -{ - services.syncthing = { - enable = true; - user = "mikl"; - group = "users"; - - # Что синкается (файлы). /srv — FHS для service data. - dataDir = "/srv/syncthing"; - - # State syncthing (config, certs, index). Не синкается. - configDir = "/var/lib/syncthing"; - - # Открывает firewall порты 22000 (sync). firewall выключен на heather - # (полагаемся на YC SG), но флаг для консистентности. - openDefaultPorts = true; - - # GUI только на localhost — Caddy проксирует снаружи. - guiAddress = "127.0.0.1:8384"; - - # НЕ override devices/folders из nix — конфигурим через GUI/API. - # overrideDevices/overrideFolders = false (default) = nix не трогает то, - # что добавлено через GUI. Иначе nix бы их стирал при rebuild. - overrideDevices = false; - overrideFolders = false; - }; - - # strelaysrv: public relay для syncthing-устройств за NAT. - # Порты 22067 (relay) и 22070 (status). - # NixOS-модуля syncthing не управляет strelaysrv — поднимаем вручную через - # systemd, пакет syncthing-relay (strelaysrv binary). - systemd.services.syncthing-relay = { - description = "Syncthing Relay Server (strelaysrv)"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${pkgs.syncthing-relay}/bin/strelaysrv"; - Restart = "on-failure"; - User = "mikl"; - Group = "users"; - # strelaysrv пишет ключи/статус в CWD — рабочая директория. - WorkingDirectory = "/var/lib/syncthing-relay"; - StateDirectory = "syncthing-relay"; - }; - }; - - # /srv/syncthing создаём, права mikl:users (syncthing работает от mikl). - systemd.tmpfiles.rules = [ - "d /srv/syncthing 0755 mikl users -" - ]; -}