VDS Rusonyx 160 NVMe (89.253.255.94 / vds.kzntsv.site) активирован 2026-05-20. 3 фазы за ~6 часов: - Phase 1: harden + docker 29.5.1 + traefik v2.11 + portainer 2.21.5 - Phase 2: shared DB park (postgres 16 / mariadb 11.4 / mongo 7 / redis 7) via traefik raw TCP forward + self-signed TLS - Phase 3: миграция gitea (132 repos), verdaccio (2063 pkgs), registry fresh install (user accepted loss old images) + Joxit GUI Ingest 1 source + 1 entity (vds-kzntsv) + 6 concepts (traefik-tcp- passthrough-vs-starttls / portainer-2.21-admin-password-regression / db-tls-self-signed-via-traefik-raw-tcp / rusonyx-vps-onboarding-quirks / registry-gc-mount-and-modify-flag / compose-bcrypt-escape-trap). 3 follow-up ⚪ tasks: vds-gc-cron, vds-backup-rsync-kreknin, vds-ntfy-push. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
20 KiB
vds-kzntsv-bootstrap
Goal
Поднять облачный VDS vds.kzntsv.site (Rusonyx) и вынести туда ключевые инфраструктурные сервисы пользователя, чтобы не зависеть от собственного железа (мёртвая NAS показала single-point-of-failure). Цель — устранить риск повторения 2026-05-18 для инфраструктурного слоя (gitea/verdaccio/seafile/registry/hermes); production CMS (MoreThenCms) остаётся на windows-recovery-host и обсуждается отдельно в future-resilient-architecture-goals.
После миграции kreknin-synology остаётся как backup target, не как live host инфры.
Сервисы под миграцию (snapshot 2026-05-19)
Источник размеров — du -sh /volume1/docker/*/ на kreknin (см. Decisions log 2026-05-19).
| Сервис | Сейчас на kreknin | После cleanup / на VDS | План |
|---|---|---|---|
| gitea | /volume1/docker/gitea/ 2.6G |
~2.6G | lift-and-shift (compose + data tar) |
| verdaccio | /volume1/docker/personal/verdaccio/ 8.5G |
2–3G | prune old tarballs до миграции |
| owncloud | /volume1/docker/owncloud/ 187M + дубль 195M |
— | отказ, заменяется seafile |
| seafile | (новый) | 30–40G | green install на VDS |
| registry | /volume1/docker/infrastucture/registry/ 99G |
5–15G | registry garbage-collect ДО миграции (write op, требует read-only/stopped registry) |
| hermes | /volume1/docker/hermes/ 0 (пусто на kreknin) |
~10G (user estimate) | TBD — что это, где state |
Раскладка после cleanup: ~55–75G data + ~5G OS/docker → ~80–100G с headroom.
Тариф VDS (Rusonyx, https://www.rusonyx.ru/hosting/vps/#ssd)
Заказан (финал, user 2026-05-19): 160 NVMe (Rusonyx переименовал прежний 160 SSD тариф в NVMe — апгрейд storage по той же цене, IOPS выше).
Конфигурация заказа:
- 6 vCPU 2.6GHz
- 8192 MiB RAM (8 GiB)
- 163840 MiB disk (160 GiB) NVMe
- Ubuntu Server 24.04
- 1 IPv4 (free)
- Лицензия / CMS / ispmanager — нет (docker-only, control-panel мусор не нужен)
- VPS Backup от Rusonyx — 0 шт (свой backup через rsync/borg → kreknin или off-site cloud)
- SSH root access — Вкл на старте (после bootstrap — отключить, sudo-user)
Reasoning:
- 160GB headroom ~45% на старте после миграции (~60-70G data + 5G OS) — годен на 2-3 года без add-on operations.
- 8GB RAM overkill для baseline (~2.1G) но даёт реальный запас под burst и любые будущие сервисы.
- User выбрал «купи-и-забудь» вариант over 80 SSD+add-on; +1000 ₽/мес vs 80 SSD = +12k₽/год за operational simplicity.
Не выбраны:
- 40 SSD — 4GB RAM впритык, OOM risk под seafile+registry burst.
- 80 SSD — RAM ок, но 80GB диск требует add-on (цены непрозрачны без звонка в managers).
- 220+ SSD — overkill без local LLM-inference.
Open questions
- Hermes — Nous Research agent runtime (https://hermes-agent.nousresearch.com/). Открытые подвопросы:
- self-host их open-source / docker image, или client-wrapper к managed API?
- если self-host — какой репо/образ, какие порты, какие external deps (vector DB, LLM endpoint)?
- state где живёт (postgres / sqlite / files / vector store)?
- 10G — это weights/embeddings/vector store/document cache?
- влияет на RAM-выбор тарифа (если local LLM inference — 8GB мало, нужно 16+)
Owncloud дубль— live =/volume1/docker/owncloud/(vitya:users, mysql активен 2026-05-20), stale =/volume1/docker/personal/owncloud/(alexey, mysql last May 5). Owncloud в scope этих 3 фаз не входит — user явно убрал в Phase 3.DNS-cut стратегия— DNS A-records проставлены user'ом 2026-05-20 сразу на VDS IP до bootstrap'а (vds,*.vds,git,registry,verdaccio). Сервисы на kreknin продолжают отвечать пока traefik там жив; cut фактический произойдёт когда remote DNS resolver кэш протухнет (≤ TTL).- Backup VDS → kreknin: какой механизм? rsnapshot / restic / borg / Hyper Backup pull через SFTP? (deferred — после Phase 3)
OS на VDS→ Ubuntu 24.04 LTS (decision 2026-05-19): LTS до апреля 2029, docker official APT repo flow, mainstream community для docker-стека, гарантированно есть в Rusonyx templates.
Key files
(пока нет; появятся по ходу — compose-файлы, ansible-плейбук если будет, sync scripts)
🚨 Pre-Phase-1 — Rusonyx warning 2026-05-20
apt upgrade Ubuntu 24.04 на Rusonyx виртуализации перезапускает SSH service. Делать ТОЛЬКО через VNC console Rusonyx-панели, иначе SSH рвётся посередине, апгрейд бьётся.
Sequence (paste-ready в VNC console, root login):
apt update
apt upgrade -y
apt --fix-broken install -y
apt upgrade -y
После reboot SSH повторно достижим (89.253.255.94, root, пароль из vds-kzntsv.env). Отсюда мой Phase 1 начинается.
Connectivity (2026-05-20)
- IP:
89.253.255.94 - Vendor hostname:
vps-21075162-534388.host4g.ru - DNS (REGRU, user 2026-05-20):
- A
vds.kzntsv.site→ 89.253.255.94 - A
*.vds.kzntsv.site→ 89.253.255.94 - A
git.kzntsv.site→ 89.253.255.94 - A
registry.kzntsv.site→ 89.253.255.94 - A
verdaccio.kzntsv.site→ 89.253.255.94
- A
- Креды (root initial + sudo user vitya + portainer admin + LE email):
C:\Users\vitya\projects\.common\secrets\vds-kzntsv.env. Root pass одноразовый, rotate'нется в Phase 1 (PasswordAuthentication off, SSH-key-only).
Kreknin pre-migration findings (probe 2026-05-20)
SSH vitya@195.19.90.188 через id_ed25519_kreknin ✅. Sudo требует пароль (пока не у меня).
| Сервис | Путь | Размер | DB | Compose live? |
|---|---|---|---|---|
| gitea | /volume1/docker/gitea/ |
data 2.6G + own postgres 9.6 dir | внутренний Postgres 9.6 (gitea:gitea) |
✅ gitea + gitea-db на сети proxy |
| verdaccio | /volume1/docker/personal/verdaccio/ |
storage 8.5G + config 8K | нет | ✅ |
| registry | /volume1/docker/infrastucture/registry/ |
99G | нет (auth + docker filesystem) | ✅ (compose-файл есть) |
| owncloud-live | /volume1/docker/owncloud/ |
mysql активен 2026-05-20 | mysql + redis в одном compose | ✅ live (vitya:users owner) |
| owncloud-stale | /volume1/docker/personal/owncloud/ |
mysql последний May 5 | mysql + redis | устарел |
| hermes | /volume1/docker/hermes/ |
только /data/ (uid 10000), нет compose |
? | ❓ конфиг где-то ещё (DSM Container Manager?) — open question |
Phase 1 — Bootstrap (план, после VNC-upgrade)
🖥️ paste-ready, root@89.253.255.94 через SSH (после VNC-upgrade reboot)
adduser --gecos "" --disabled-password vitya+echo 'vitya:Pryakhin10~' | chpasswd+usermod -aG sudo vitya.mkdir -p /home/vitya/.ssh && echo '<pubkey>' > /home/vitya/.ssh/authorized_keys && chmod 700 /home/vitya/.ssh && chmod 600 /home/vitya/.ssh/authorized_keys && chown -R vitya:vitya /home/vitya/.ssh. Pubkey =~/.ssh/id_ed25519.pubс Windows-PC.- Тест login
ssh vitya@89.253.255.94отдельным окном до harden sshd (lockout-safety). - Harden sshd:
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/; s/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && systemctl reload sshd. apt install -y ufw fail2ban+ufw default deny incoming && ufw default allow outgoing && ufw allow 22/tcp && ufw allow 80/tcp && ufw allow 443/tcp && ufw enable. fail2ban sshd jail дефолт-on.- Docker official APT:
install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable" > /etc/apt/sources.list.d/docker.list apt update apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin usermod -aG docker vitya mkdir -p /opt/stacks/{traefik,portainer,databases}.- Traefik compose (
traefik:v3.0), HTTP-01 challenge (DNS уже на VDS), per-subdomain certs. Dashboard наtraefik.vds.kzntsv.siteс basicAuthvitya:Pryakhin9(htpasswd-hashed). - Portainer compose (
portainer/portainer-ce:latest), labels →portainer.vds.kzntsv.site. First-visit setup wizard: adminvitya/vitya.kuznetsov@gmail.com/Pryakhin9. Generate API key → дописать вvds-kzntsv.envPORTAINER_API_KEY=.... С этого момента я могу деплоить stacks через Portainer REST API.
Traefik v2.11 vs v3.0 decision: v3 mainline, breaking changes в middleware label syntax. v2.11 LTS до Q1 2027, совместим с существующими compose-стеками на windows-recovery-host. Recommend v3.0 — VDS green install, нет legacy compose-файлов к pin'ить; за год v3 уже зрелый.
Phase 2 — Shared DBs (план)
DB-park (Postgres 16, MariaDB 11, Redis 7, MongoDB? — см. Open questions). Каждый — отдельный compose в /opt/stacks/databases/<engine>/, на общей docker network shared-dbs (external). Admin GUI через Portainer (или отдельные образы adminer/pgadmin/redis-commander если нужно).
Exposure model — см. Open questions ниже.
Phase 3 — Migration с kreknin
🚨 Источник данных — restored backup, НЕ live containers
Данные /volume1/docker/{gitea,personal/verdaccio,infrastucture/registry}/ на kreknin-synology это restored Hyper Backup мёртвой dead-synology-diskstation (restore сессии 2026-05-18 вытащил /docker шару из .hbk репо). На kreknin сами эти сервисы не запущены — files сидят на disk. Поэтому миграция = чистый pull данных + standup на VDS, без docker stop / pg_dump на kreknin. Container'ы умерли вместе с DiskStation 2026-05-18.
Read first: .wiki/concepts/hyper-backup-structure-and-recovery.md, .wiki/sources/nas-recovery-session-2026-05-18.md, .wiki/entities/kreknin-synology.md, .wiki/entities/dead-synology-diskstation.md.
3.1 Gitea
- На kreknin (через sudo, перм issue на postgres dir):
tar c -C /volume1/docker/gitea . | ssh vds 'tar x -C /opt/migrate/gitea/'— pullsdata/+postgres/+docker-compose.yml. Hyper Backup restored файлы могут иметь Synology ACL + funky POSIX perms (см. hyper-backup-structure-and-recovery раздел ACL); rsync через root tar выровняет. - На VDS:
chown -R 999:999 /opt/migrate/gitea/postgres && chmod 700 /opt/migrate/gitea/postgres(postgres uid 999, требует strict 700 на datadir). - На VDS: запустить temporary Postgres 9.6 на restored datadir →
docker run --rm -d --name pg96-temp -v /opt/migrate/gitea/postgres:/var/lib/postgresql/data postgres:9.6(envPOSTGRES_USER=gitea POSTGRES_PASSWORD=gitea POSTGRES_DB=gitea). Подождатьpg_isready. - На VDS:
docker exec pg96-temp pg_dump -U gitea gitea > /opt/migrate/gitea.sql→ ~80-200 MB SQL. - На VDS shared postgres-16:
psql -U postgres -c 'CREATE DATABASE gitea OWNER gitea;'(после создания юзера gitea в shared cluster) →psql -U gitea -d gitea < /opt/migrate/gitea.sql. Гитеа автоматически мигрирует schema под 16 (Gitea умеет). - Stop temp pg96, удалить
/opt/migrate/gitea/postgres/(больше не нужно — данные в shared postgres). - На VDS Portainer stack:
services: gitea: image: gitea/gitea:1.25.5 environment: - USER_UID=1000 - USER_GID=1000 - DB_TYPE=postgres - DB_HOST=postgres:5432 # shared - DB_NAME=gitea - DB_USER=gitea - DB_PASSWD=gitea volumes: - /opt/stacks/gitea/data:/data networks: [proxy, shared-dbs] labels: - traefik.enable=true - traefik.http.routers.gitea.rule=Host(`git.kzntsv.site`) - traefik.http.routers.gitea.entrypoints=websecure - traefik.http.routers.gitea.tls.certresolver=letsEncrypt - traefik.http.services.gitea.loadbalancer.server.port=3000data/смонтировать с/opt/migrate/gitea/data/(или mv туда). - Smoke:
git.kzntsv.site→ existing user login (data restored) → repo browse → clone test. - Decommission на kreknin: ничего не делаем, файлы restored backup и так сидят паркингом на kreknin volume. Не трогать.
3.2 Verdaccio
- На kreknin → VDS: rsync (через
scp -Oилиtar | ssh)/volume1/docker/personal/verdaccio/{storage,config}/→ vds:/opt/stacks/verdaccio/. - На VDS: chown под uid контейнера verdaccio (10001, см. verdaccio Dockerfile).
- Pre-clean ПОСЛЕ rsync, на VDS (не на kreknin — кreknin это backup-target read-only-bydefault): удалить старые tarball'ы > N версий из
storage/<scope>/<package>/либо просто оставить как есть (8.5G нормально для 160 GB VDS). - На VDS Portainer stack: image
verdaccio/verdaccio:6, volumes/opt/stacks/verdaccio/storage:/verdaccio/storageиconfig:/verdaccio/conf, labels наverdaccio.kzntsv.site. - Smoke:
npm publishтест с windows-recovery-host противverdaccio.kzntsv.site.
3.3 Registry
- На kreknin: pre-clean GC доступен без running registry container — запустить temp registry:2 локально на kreknin против restored datadir:
sudo docker run --rm -v /volume1/docker/infrastucture/registry/docker:/var/lib/registry -v /volume1/docker/infrastucture/registry/config.yml:/etc/docker/registry/config.yml registry:2 garbage-collect /etc/docker/registry/config.yml. Write op on kreknin — требует согласия user'а (правка backup'а на kreknin диске). Альтернатива: skip GC на kreknin → rsync 99G сетью → GC на VDS пост-фактум (медленнее по сети, безопаснее для kreknin). - На kreknin → VDS: rsync
/volume1/docker/infrastucture/registry/{auth,docker,docker-compose.yml,config.yml}→ vds:/opt/stacks/registry/. - На VDS Portainer stack: image
registry:2, volumes дляauth+docker(data) +config.yml, labels наregistry.kzntsv.site. basicAuth middleware если в config задан htpasswd. - Smoke:
docker login registry.kzntsv.site+docker pullизвестный image.
Open question по 3.3 GC
- GC на kreknin (write-op на backup-target, ~30 мин обработка, экономит ~85G сетевого трафика и ~85G диска на VDS)
- GC на VDS пост-rsync (читает 99G по сети — медленно при типичном Rusonyx ~50-100 Mbps, ~3-5 ч; не трогает kreknin)
Recommend GC на kreknin — backup-target, но garbage-collect registry:2 пересоберёт data IN-PLACE, не deletes; risk минимальный.
Связанные wiki-страницы (для контекста):
.wiki/entities/kreknin-synology.md— текущий host kreknin.wiki/concepts/future-resilient-architecture-goals.md— глобальные цели resilience.wiki/concepts/recovery-architecture-snapshot.md— текущая prod-инфра
Decisions log
- 2026-05-19: OS на VDS = Ubuntu 24.04 LTS (Noble). Reasoning: LTS support до апреля 2029, docker official APT flow, mainstream community для docker-workload. Debian 12 отвергнут — не даёт material выгоды при 8GB RAM (idle разница ~100M), а docker-docs primary-target — Ubuntu LTS.
- 2026-05-19 (заказан): Тариф
160 NVMe(Rusonyx переименовал 160 SSD → 160 NVMe, та же цена, апгрейд по IOPS). VPS Backup от Rusonyx — 0 шт (свой backup pipeline). SSH root — Вкл на bootstrap, потом отключить. - 2026-05-19 (final tier): User выбрал 160 SSD (2500 ₽/мес). Reasoning user'а — operational simplicity, не звонить в support за add-on ценой, есть запас на 2-3 года. +1000 ₽/мес vs 80 SSD приемлемо.
- 2026-05-19 (промежуточный заход, откатан): Рекомендовалось 80 SSD + disk add-on исходя из того что 8GB RAM избыточно после уточнения hermes-профиля. User решил что 500 ₽/мес экономии не стоят звонков в support и риска что add-on окажется дорогой.
- 2026-05-19 (первый заход): Изначально 160 SSD по budget-расчёту headroom; затем переоценено вниз после уточнения hermes; затем user вернул обратно к 160 SSD по user-preference.
- 2026-05-19: Owncloud → seafile. Reasoning: пользователь решил заменить (rationale пока не записан).
- 2026-05-19: Registry garbage-collect ДО миграции (на kreknin), чтобы не тащить 99G чтобы потом всё равно чистить.
- 2026-05-19: Verdaccio тоже prune ДО миграции, по аналогичной логике.
Next actions (по порядку)
- Уточнить hermes — что это, где его state.
- Решить owncloud дубль — нужны ли данные для миграции в seafile или green install.
- Registry GC на kreknin — stop писателей,
docker run --rm -v ...:/var/lib/registry registry:2 garbage-collect /etc/docker/registry/config.yml, measure delta. ⚠️ prod-changing, согласие от user. - Verdaccio prune —
npm cache clean+ удалить old tarballs из storage. (low risk, restorable из upstream npm) Закупить тариф у Rusonyx→ заказан 160 NVMe, Ubuntu 24.04, 8GB/6vCPU/160GB, 1 IPv4 (2026-05-19, ожидание выделения IP).- DNS — A
vds.kzntsv.site → <IP>в REGRU. - Bootstrap VDS (zero-day чек-лист): apt update/upgrade → создать sudo-user
vitya+ копировать SSH key →PermitRootLogin no+PasswordAuthentication no→ ufw (22/80/443 only) → fail2ban → docker official APT repo (docker-ce + buildx + compose-plugin). Полная paste-ready команда в чате сессии. - Per-service migration (gitea → tarball+restore, verdaccio → tar storage, seafile → green install, registry → rsync, hermes → repo+state).
- Backup pipeline VDS → kreknin (или cloud — Backblaze B2 для off-site, см. future-resilient-architecture-goals).
- DNS cut к production, удаление сервисов с kreknin (с paranoid keep-on-kreknin-7days).