# Robot2B B2 VPS — конфигурационная Библия > Замороженная историческая конфигурация — 10.08.2026 > > Не применять описанные ниже `backhaul`, `relay`, Tailscale/SSH LocalForward, > Synology enrollment или открытие `9921`. Целевой транспорт заменён на > Core-initiated mTLS full-duplex channel по > `docs/ADR_0001_CORE_INITIATED_EDGE_CHANNEL.md`. Документ сохраняется как > evidence уже выполненных экспериментов и текущего predecessor VPS. Статус документа: живой manual реализации от 2026-08-06. Контур: Robot2B / NODE.DC Device Plane. VPS: `155.212.211.15`, hostname `koffyvngij`. ## 1. Назначение VPS является минимальным публичным Device Edge для трекеров Arnavi B2. Он не владеет бизнес-логикой, протоколом, БД, карточками устройств, визуализацией или командами. Его единственная целевая функция — принять ограниченный поток raw TCP на `155.212.211.15:9921`, не интерпретируя пакет, и передать его по шифрованному private backhaul в уже существующий `device-gateway` NODE.DC. Gelios остаётся отдельным legacy-источником. Эта конфигурация не меняет Gelios, DNS `device.nodedc.ru`, маршруты B2 или command transport. ```mermaid flowchart LR B2["Arnavi B2 trackers"] VPS["Device Edge VPS\n155.212.211.15:9921"] TS["Tailscale userspace\nSOCKS5 127.0.0.1:1055"] SSH["SSH local forward\n127.0.0.1:19921"] TARGET["Synology device-backhaul-target\n100.109.216.21:2222"] GW["device-gateway\n127.0.0.1:9921"] CORE["device-control-core + PostgreSQL"] FOUNDRY["Foundry / visualization"] GELIOS["Gelios legacy source"] B2 -->|"raw TCP, planned route"| VPS VPS --> TS -->|"grant: tag:device-edge-vps → TCP/2222 only"| SSH --> TARGET --> GW --> CORE --> FOUNDRY GELIOS -->|"independent legacy ingest"| CORE ``` ## 2. Красные границы - На VPS нет базы данных и durable telemetry storage. - VPS не разбирает Arnavi/B2 protocol и не принимает решения по IMEI. - IMEI остаётся claimed identifier, а не доказательством владения устройством. - Неизвестное устройство должно попадать в quarantine/discovery lifecycle. - Command transport отключён. Команды через VPS или Gelios не вводятся. - Gelios не выключается и не перетирается новым потоком. - На Synology не публикуется Docker-порт `2222`; доступ только через private Tailscale Serve. - Public VPS не является пользовательским tailnet-узлом. Его service identity `tag:device-edge-vps` может инициировать только TCP к `100.109.216.21:2222`. - VPS не принимает subnet routes, DNS tailnet, exit-node capability или Tailscale SSH. Доступ к DSM, MacBook и другим tailnet-узлам запрещён. - Приватные ключи, auth keys, токены и пароли не входят в Git, deploy artifacts, Ops или этот документ. - До отдельного pilot/cutover не меняются `device.nodedc.ru` и настройки B2. ## 3. Фактический predecessor VPS Снято до первого apply: - Ubuntu `24.04.4 LTS`, kernel `6.8.0-137-generic`, KVM/QEMU. - 1 vCPU, 961 MiB RAM, swap отсутствует. - Root filesystem около 8.7 GiB; свободно около 6.4 GiB. - `eth0`: `155.212.211.15/32`, default gateway `100.100.1.1`. - Публично слушал только TCP/22; TCP/9921 был закрыт. - Docker, Node.js, Tailscale и WireGuard отсутствовали. - `fail2ban`, NTP и unattended upgrades были активны. - UFW был inactive, nftables/iptables использовали INPUT ACCEPT. - SSH допускал root/password и forwarding; это устранено foundation-переходом. ## 4. Канонические переходы Конфигурация разделена на независимые data-only артефакты. Порядок нельзя переставлять. 1. `foundation`: - pin статических Node.js и Tailscale runtimes; - service account `nodedc-edge`; - key-only SSH; - default-deny nftables, публично только TCP/22; - отдельный ED25519 backhaul key, сгенерированный на VPS; - userspace `tailscaled`, но без скрытого auth key; - TCP/9921 закрыт. 2. Внешняя регистрация и сегментация `nodedc-b2-vps` в существующем tailnet: - заменить default wildcard policy на проверяемую deny-by-default policy; - назначить `tag:device-edge-vps`, тем самым удалить user ownership; - разрешить тегу только `100.109.216.21:2222/tcp`; - отрицательно проверить Synology `22/5001`, MacBook `22` и другие узлы; - только после этого вернуть Tailscale service в состояние Running. 3. Synology `backhaul-vps-enrollment`: - принять только публичный VPS key через enrollment; - заменить прежний Mini key; - пересоздать только `device-backhaul-target`; - сохранить Device Plane, PostgreSQL, Tailscale Serve и Gelios; - при ошибке автоматически вернуть прежний key и target generation. 4. VPS `backhaul`: - pinned Synology host key; - key-only SSH через Tailscale userspace SOCKS5; - `127.0.0.1:19921 -> 127.0.0.1:9921`; - публичный TCP/9921 всё ещё закрыт. 5. VPS `relay`: - открыть публичный TCP/9921; - bounded opaque relay на `127.0.0.1:19921`; - loopback health на `127.0.0.1:18221`. 6. Отдельный pilot: изменить адрес сервера у ограниченной группы B2. Это не часть конфигурации VPS. ## 5. Идентичности и ключи ### 5.1 Management SSH Команда с MacBook: ```bash ssh -i ~/.ssh/nodedc_b2_vps \ -o IdentitiesOnly=yes \ -o StrictHostKeyChecking=yes \ root@155.212.211.15 ``` В Ops и manual фиксируются только путь и fingerprints: - локальный private key path: `~/.ssh/nodedc_b2_vps`; - MacBook management public key fingerprint: `SHA256:DYYy1E3DaxIQGC0jnsW6SP7gXdBHUy3A1zn4pvgVUEw` (ED25519); - VPS SSH server host key fingerprint: `SHA256:mhqNn2S6zstkYL7VFdvt3SYHv1nLjB4J7/s57RrKG6w` (ED25519). Foundation принудительно задаёт: - `PermitRootLogin prohibit-password`; - `AuthenticationMethods publickey`; - `PasswordAuthentication no`; - `KbdInteractiveAuthentication no`; - forwarding, agent forwarding, X11 и tunnels запрещены; - `MaxAuthTries 3`, `LoginGraceTime 20`. В `/root/.ssh/authorized_keys` остаются две management identity: - MacBook ED25519 — fingerprint выше; - provider recovery key `beget-access-key`, RSA 1024, fingerprint `SHA256:9W1cgovqOlegteEWV0r5j4OjJgG0PGr97eVmpUBjg54`. RSA-1024 provider key — остаточный риск. Он не удалён автоматически, потому что отзыв внешнего recovery-доступа является отдельным необратимым решением. После подтверждения владельца нужно либо удалить его отдельным каноническим переходом, либо документировать как принятый break-glass access. ### 5.2 VPS backhaul client identity Private key генерирует root-owned runner непосредственно на VPS: - private: `/var/lib/nodedc-b2-vps/trust/backhaul_ed25519`, owner `nodedc-edge` на foundation и `nodedc-backhaul` после backhaul apply, mode `0400`; - public: `/var/lib/nodedc-b2-vps/trust/backhaul_ed25519.pub`, mode `0444`; - fingerprint: `SHA256:HHTiDYiCRxSiKjBLCip6JMSzGfLGrDz5g8SIkosJcVw`; - public key: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGUlvJ8a83qov9DHO2S/BHbVAEH4Chyc4v/DKwOIWeES nodedc-device-edge-vps-backhaul`. В Synology staging этот public key хранится по пути: `/volume1/docker/nodedc-device-plane/enrollment/device-edge-vps-backhaul.pub` Private key никогда не покидает VPS. Foundation генерирует ключ до появления публичного relay, поэтому его временным владельцем является `nodedc-edge`. Backhaul transition атомарно создаёт `nodedc-backhaul`, передаёт ему каталог trust и ключ и валидирует mode. Relay запускается как третий пользователь `nodedc-relay`; он не может читать ни private key, ни Tailscale state. Даже локальный доступ relay к SOCKS5 не расширяет полномочия: tailnet grant разрешает только target `2222`, где аутентификация дополнительно требует private key пользователя `nodedc-backhaul`. ### 5.3 Synology backhaul target identity - Tailnet IP: `100.109.216.21`. - Private SSH endpoint: `100.109.216.21:2222` через Tailscale Serve. - User: `device-backhaul`. - PermitOpen: только `127.0.0.1:9921`. - Host key fingerprint: `SHA256:QERJ5CIUXRj0nLChGT6HMtoX+WTaeaEY5ZgaWqT8d30`. - Public host key: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJsmoyS+0Tbhz9VXxrSxXwNMFpfbdTckCilObOnKdlEc nodedc-device-plane-backhaul-target`. - VPS pinned known_hosts: `/var/lib/nodedc-b2-vps/trust/backhaul_known_hosts`. ### 5.4 Tailscale service identity и grant Живая policy сохранена 2026-08-06. Каноническая копия: `device-plane/deployment/tailscale-device-edge-policy.hujson`. - `autogroup:member -> autogroup:self`, все протоколы: сохраняет привычный доступ пользователя только между собственными user-owned устройствами; - `tag:device-edge-vps -> device-plane-backhaul`, только `tcp:2222`; - `device-plane-backhaul = 100.109.216.21`; - tag owner: только `autogroup:admin`; - policy test требует accept `100.109.216.21:2222` и deny для Synology `22/5001`, MacBook `22`, `nodedc-device-edge:22`. Назначение тега удалило `dcctouch@gmail.com` из поля `Managed by`; живой VPS управляется `tag:device-edge-vps`. После включения проверено с самого VPS: - `100.109.216.21:2222` — reachable; - `100.109.216.21:22` — blocked; - `100.109.216.21:5001` — blocked; - `100.114.248.4:22` — blocked; - `100.64.19.31:22` — blocked. Enrollment запускается с `--accept-dns=false --accept-routes=false --ssh=false`. Runner для backhaul/relay дополнительно требует `BackendState=Running`, online hostname `nodedc-b2-vps` и ровно один tag `tag:device-edge-vps`. ## 6. Runtime и файловая система VPS ### 6.1 Root-owned source/runtime - runner: `/usr/local/sbin/nodedc-b2-vps-deploy`; - live root: `/opt/nodedc-b2-vps`; - deploy state: `/var/lib/nodedc-b2-vps-deploy`; - inbox: `/var/lib/nodedc-b2-vps-deploy/inbox`; - applied/failed artifacts: `applied/`, `failed/`; - backups: `backups/`; - journals: `state/applied.jsonl`, `state/failed.jsonl`; - lock: `state/deploy.lock`; - service state/trust: `/var/lib/nodedc-b2-vps`. ### 6.2 Pinned runtimes - Node.js `22.23.2`; archive SHA-256 `d60acfe00a2932254bb0ad20e01b0d74397a0875595de719654b214f4b03f307`. - Tailscale `1.102.2`; archive SHA-256 `ad2cde12f8de95f7b93a1e0401e652291c603d42b9d60a33fb1741eb38ab04d8`. Docker не устанавливается: для 961 MiB RAM он не нужен и добавляет лишний daemon/state surface. ### 6.3 systemd units - `nodedc-b2-tailscaled.service`: - user `nodedc-edge`; - userspace networking, без TUN; - socket `/run/nodedc-b2-vps/tailscaled.sock`; - SOCKS5 `127.0.0.1:1055`; - `MemoryMax=160M`; - разрешены `AF_UNIX AF_INET AF_INET6 AF_NETLINK`. - `nodedc-b2-backhaul.service`: - user `nodedc-backhaul`, единственный читатель backhaul private key; - strict host key pinning; - local forward `127.0.0.1:19921`; - `MemoryMax=64M`. - `nodedc-b2-relay.service`: - user `nodedc-relay`, без credential access; - public `0.0.0.0:9921`; - health `127.0.0.1:18221`; - upstream `127.0.0.1:19921`; - `MemoryMax=192M`. Все units используют `NoNewPrivileges`, `ProtectSystem=strict`, `ProtectHome=yes`, `PrivateTmp`, `PrivateDevices`, ограничение address families, tasks и file descriptors. ## 7. Firewall и порты Foundation nftables policy: - input: default drop; - loopback, established/related и ICMP разрешены; - новый TCP/22 ограничен `30/minute`, burst `60`; - TCP/9921 отсутствует; - forward: default drop; - output: accept. Relay policy добавляет: - drop новых соединений на TCP/9921 сверх `300/second`; - accept TCP/9921 после rate guard. Портовая матрица: | Endpoint | Видимость | Владелец | Стадия | |---|---|---|---| | `155.212.211.15:22` | public | OpenSSH | foundation | | `127.0.0.1:1055` | loopback | tailscaled SOCKS5 | foundation | | `127.0.0.1:19921` | loopback | SSH local forward | backhaul | | `127.0.0.1:18221` | loopback | relay health | relay | | `155.212.211.15:9921` | public | bounded relay | relay | | `100.109.216.21:2222` | tailnet grant только для VPS tag | Synology target | existing | | `127.0.0.1:9921` на Synology | loopback | device-gateway | existing | ## 8. Relay limits - max concurrent sessions: `128`; - max sessions per source IP: `16`; - max new connections/minute/source IP: `60`; - max tracked source IPs: `4096`; - max bytes per direction/session: `64 MiB`; - session timeout: `300000 ms`; - source policy: `public-ipv4-only`; - protocol inspection: disabled на VPS; - command transport: disabled. ## 9. Установленный foundation release Принят 2026-08-06: - patch: `device-edge-vps-foundation-20260806-003`; - artifact SHA-256: `1be852f144e9f0fea32af70bebd07a2607b6a1818825094bd4c1b4062064716a`; - foundation-time runner SHA-256: `3f42d23431937e70c16ce1fd346fb84a706e506ae99d89eaf11780ff1ad56c03`; - current promoted runner SHA-256: `5ccdc1b53ce0688e7c120976e82937842bc8491a2e05eb5f280165accfd40b6c`; - backup: `device-edge-vps-foundation-20260806-003-20260806-151415`; - terminal result: `deploy-ok`; - fresh MacBook key-only SSH acceptance: success. Два предыдущих ID терминальны и никогда не должны применяться повторно: - `...-001`: `tailscaled` заблокирован отсутствием `AF_NETLINK`; automatic rollback `ok`; - `...-002`: cloud-init `50-cloud-init.conf` опередил `90-*` и сохранил `PasswordAuthentication yes`; automatic rollback `ok`; - `...-003`: исправлены `AF_NETLINK` и ранний `00-nodedc-b2-vps.conf`; acceptance успешна. Следующие exact isolation-aware artifacts стадированы в VPS inbox и не применяются до своих predecessor barriers: - backhaul `device-edge-vps-backhaul-20260806-002`, SHA-256 `830750da8f9590ca4db458ec9e90f4d48ad8d1403160d3878a968b54e9eb6913`; - relay `device-edge-vps-relay-20260806-002`, SHA-256 `305a6de769f24b2c6cee801426ec43b98a44d10e08cad75a96fd65d20b16b697`. Версии `...-001` не применялись и recoverably перемещены из inbox в `/var/lib/nodedc-b2-vps-deploy/withdrawn/*.superseded-by-002`, потому что в них все три процесса использовали один Unix account `nodedc-edge`. ## 10. Synology VPS enrollment release Стадировано, но до авторизации Tailscale и root plan/apply не считается применённым: - runner candidate: `/volume1/docker/nodedc-deploy/runner-install/candidates/nodedc-deploy.device-plane-backhaul-vps-enrollment-20260806-011`; - runner SHA-256: `453228c41b411d9c925091c77dc94e501f2eb3534fc241db0d2e58f0a28e12e2`; - artifact: `/volume1/docker/nodedc-deploy/inbox/nodedc-device-plane-device-plane-backhaul-vps-enrollment-20260806-001.tgz`; - artifact SHA-256: `576dabdafde5e3b2de09c7265127928c4b463e7b40dd554fd71babc16cc70e08`; - VPS enrollment public-key file SHA-256: `c2718c117fd09965386524d32fa9816d9d2d9cf00b59010dcf8bcf78f29bea8c`. Root-переход на Synology: ```bash sudo sha256sum \ /volume1/docker/nodedc-deploy/runner-install/candidates/nodedc-deploy.device-plane-backhaul-vps-enrollment-20260806-011 sudo install -o root -g root -m 0755 \ /volume1/docker/nodedc-deploy/runner-install/candidates/nodedc-deploy.device-plane-backhaul-vps-enrollment-20260806-011 \ /usr/local/sbin/nodedc-deploy sudo /usr/local/sbin/nodedc-deploy verify-install sudo /usr/local/sbin/nodedc-deploy plan \ /volume1/docker/nodedc-deploy/inbox/nodedc-device-plane-device-plane-backhaul-vps-enrollment-20260806-001.tgz # Apply только после review exact plan. sudo /usr/local/sbin/nodedc-deploy apply \ /volume1/docker/nodedc-deploy/inbox/nodedc-device-plane-device-plane-backhaul-vps-enrollment-20260806-001.tgz ``` Ожидаемый plan обязан показать: - predecessor patch `device-plane-backhaul-target-tailnet-serve-20260804-002`; - predecessor artifact SHA `219408705dd4d80a962ed00eeb53a69df0b9ab6458443734d5c9cd1d1f795eba`; - build `none`; - recreate только `device-backhaul-target`; - next fingerprint `SHA256:HHTi…osJcVw`; - public ingress disabled; - Docker port publication disabled; - Tailscale Serve, router/NAT/firewall, PostgreSQL и Gelios unchanged; - automatic rollback на previous key + target recreate. ## 11. Внешняя регистрация Tailscale На VPS auth key не хранится. Для первой регистрации root запускает: ```bash /opt/nodedc-b2-vps/runtime/tailscale/tailscale \ --socket=/run/nodedc-b2-vps/tailscaled.sock \ up \ --hostname=nodedc-b2-vps \ --accept-dns=false \ --accept-routes=false \ --ssh=false ``` Одноразовый login URL не копируется в Ops. До включения service владелец tailnet обязан сохранить policy и назначить tag из раздела 5.4. Backhaul plan требует `BackendState=Running`, online hostname `nodedc-b2-vps` и exact service tag. ## 12. Сборка VPS artifacts Из корня repository `platform`: ```bash NODEDC_DEVICE_EDGE_VPS_RUNTIME_DIR=/tmp \ node infra/deploy-runner/build-device-edge-vps-artifact.mjs \ foundation node infra/deploy-runner/build-device-edge-vps-artifact.mjs \ backhaul node infra/deploy-runner/build-device-edge-vps-artifact.mjs \ relay ``` Builder создаёт deterministic archive с `manifest.env`, `files.txt` и `payload/`. В artifact запрещены `.env`, keys, trust, runtime, logs, uploads, node_modules и symlinks. Foundation дополнительно проверяет pinned runtime digests. Каждый release: 1. собрать дважды и сравнить SHA-256; 2. проверить file list и отсутствие секретов; 3. скопировать exact artifact в VPS inbox; 4. выполнить свежий `plan`; 5. review границ; 6. выполнить один exact `apply`; 7. считать `deploy-ok` терминальным результатом и не запускать apply повторно. ## 13. Rollback model VPS runner перед mutation создаёт backup exact partition и сохраняет текущий nft ruleset и service enablement. При ошибке: - candidate services останавливаются; - source/config возвращаются; - nftables и SSH config восстанавливаются; - service enablement возвращается; - при failed foundation удаляются созданные live/runtime roots и service user; - при failed backhaul ключ возвращается `nodedc-edge`, а созданный `nodedc-backhaul` удаляется; - при failed relay созданный `nodedc-relay` удаляется; - artifact переносится в `failed/`; - failed ID и digest становятся терминальными. Synology VPS enrollment отдельно сохраняет previous `authorized_keys`. При любой ошибке он: - удаляет candidate marker; - атомарно возвращает прежний restricted key; - пересоздаёт только `device-backhaul-target`; - проверяет target, три preserved Device Plane services, Tailscale Serve и loopback `9921`. ## 14. Развёртывание аналогичного VPS Перед клонированием нельзя просто переиспользовать текущий artifact. Нужно создать новый descriptor/release с новыми параметрами: 1. Получить чистый Ubuntu 24.04 LTS VPS и зафиксировать hostname, public `/32`, gateway, CPU/RAM/disk. 2. Добавить отдельный ED25519 management key и проверить fresh connection. 3. Зафиксировать server host key fingerprint с доверенного канала. 4. Проверить active fail2ban/NTP/unattended upgrades и отсутствие listeners, кроме TCP/22. 5. Изменить pin в runner/descriptor: `RUNTIME_HOST`, `PUBLIC_IPV4`, management/server fingerprints и Tailscale node name. 6. Не переносить private backhaul key: новый VPS должен сгенерировать новую пару самостоятельно. 7. Собрать deterministic foundation с новым terminal patch ID. 8. Promoted runner проверить отдельным `verify-install`. 9. Сделать plan → review → apply. 10. Зарегистрировать новый tailnet node без сохранения auth key. 11. Скопировать только public backhaul key в новый enrollment path. 12. Выполнить отдельный Synology key rotation/grant transition. 13. Только после принятого private backhaul применять relay. 14. Только после relay acceptance перенаправлять ограниченный pilot B2. ## 15. Acceptance checklist - [x] Foundation artifact deterministic и secret-free. - [x] Foundation accepted с automatic rollback coverage. - [x] Fresh key-only SSH с MacBook работает. - [x] Public TCP/9921 не открыт на foundation. - [x] Отдельный VPS backhaul public key создан и pinned. - [x] Synology enrollment key, runner candidate и artifact стадированы. - [ ] Tailnet node `nodedc-b2-vps` авторизован и `Running`. - [x] Tailnet wildcard grant удалён; VPS tagged и negative-route tests пройдены. - [x] Isolation-aware VPS runner promoted и `verify-install-ok`. - [ ] Synology runner candidate promoted и `verify-install-ok`. - [ ] Synology enrollment `plan` reviewed и `deploy-ok`. - [ ] VPS backhaul artifact `deploy-ok`. - [ ] VPS relay artifact `deploy-ok`. - [ ] Public TCP/9921 принят внешним probe. - [ ] Pilot B2 route согласован отдельно. - [ ] Provider RSA-1024 recovery key удалён или принят как documented risk. ## 16. Исходники и проверки Канонические файлы: - `infra/deploy-runner/nodedc-b2-vps-deploy`; - `infra/deploy-runner/build-device-edge-vps-artifact.mjs`; - `infra/deploy-runner/test_device_edge_vps_artifact.py`; - `device-plane/vps/config/`; - `device-plane/vps/systemd/`; - `device-plane/deployment/device-edge-vps-*-v1.json`; - `infra/deploy-runner/nodedc-deploy`; - `infra/deploy-runner/build-device-plane-backhaul-vps-enrollment-artifact.mjs`; - `infra/deploy-runner/test_device_plane_backhaul_vps_enrollment_artifact.py`. Проверки на момент документа: - VPS artifact tests: 9/9 OK; - Device Plane targeted runner/artifact tests: 48/48 OK; - полный platform `npm test`: 41/41 OK во внешнем сетевом sandbox; - Python compilation: OK; - systemd unit syntax: OK; отсутствие binaries до foundation было ожидаемым; - `nft -c` foundation/relay: OK; - effective candidate OpenSSH policy: key-only; - `git diff --check`: OK для целевых файлов.