docs(.wiki,.tasks): vds-kzntsv-bootstrap done — 3 phases shipped
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>
This commit is contained in:
@@ -53,15 +53,147 @@ Reasoning:
|
||||
- state где живёт (postgres / sqlite / files / vector store)?
|
||||
- 10G — это weights/embeddings/vector store/document cache?
|
||||
- влияет на RAM-выбор тарифа (если local LLM inference — 8GB мало, нужно 16+)
|
||||
- [ ] Owncloud дубль `docker/owncloud/` vs `docker/personal/owncloud/` — какой live, нужны ли данные при переезде на seafile?
|
||||
- [ ] DNS-cut стратегия: A-record `vds.kzntsv.site` сразу, или сначала test через IP?
|
||||
- [ ] Backup VDS → kreknin: какой механизм? rsnapshot / restic / borg / Hyper Backup pull через SFTP?
|
||||
- [x] ~~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.
|
||||
- [x] ~~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)
|
||||
- [x] ~~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):
|
||||
|
||||
```bash
|
||||
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
|
||||
- Креды (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)
|
||||
|
||||
1. `adduser --gecos "" --disabled-password vitya` + `echo 'vitya:Pryakhin10~' | chpasswd` + `usermod -aG sudo vitya`.
|
||||
2. `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.
|
||||
3. Тест login `ssh vitya@89.253.255.94` отдельным окном **до** harden sshd (lockout-safety).
|
||||
4. Harden sshd: `sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/; s/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config && systemctl reload sshd`.
|
||||
5. `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.
|
||||
6. Docker official APT:
|
||||
```bash
|
||||
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
|
||||
```
|
||||
7. `mkdir -p /opt/stacks/{traefik,portainer,databases}`.
|
||||
8. Traefik compose (`traefik:v3.0`), HTTP-01 challenge (DNS уже на VDS), per-subdomain certs. Dashboard на `traefik.vds.kzntsv.site` с basicAuth `vitya:Pryakhin9` (htpasswd-hashed).
|
||||
9. Portainer compose (`portainer/portainer-ce:latest`), labels → `portainer.vds.kzntsv.site`. First-visit setup wizard: admin `vitya` / `vitya.kuznetsov@gmail.com` / `Pryakhin9`. Generate API key → дописать в `vds-kzntsv.env` `PORTAINER_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
|
||||
1. На kreknin (через sudo, перм issue на postgres dir): `tar c -C /volume1/docker/gitea . | ssh vds 'tar x -C /opt/migrate/gitea/'` — pulls `data/` + `postgres/` + `docker-compose.yml`. Hyper Backup restored файлы могут иметь Synology ACL + funky POSIX perms (см. [[hyper-backup-structure-and-recovery]] раздел ACL); rsync через root tar выровняет.
|
||||
2. На VDS: `chown -R 999:999 /opt/migrate/gitea/postgres && chmod 700 /opt/migrate/gitea/postgres` (postgres uid 999, требует strict 700 на datadir).
|
||||
3. На 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` (env `POSTGRES_USER=gitea POSTGRES_PASSWORD=gitea POSTGRES_DB=gitea`). Подождать `pg_isready`.
|
||||
4. На VDS: `docker exec pg96-temp pg_dump -U gitea gitea > /opt/migrate/gitea.sql` → ~80-200 MB SQL.
|
||||
5. На 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 умеет).
|
||||
6. Stop temp pg96, удалить `/opt/migrate/gitea/postgres/` (больше не нужно — данные в shared postgres).
|
||||
7. На VDS Portainer stack:
|
||||
```yaml
|
||||
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=3000
|
||||
```
|
||||
`data/` смонтировать с `/opt/migrate/gitea/data/` (или mv туда).
|
||||
8. Smoke: `git.kzntsv.site` → existing user login (data restored) → repo browse → clone test.
|
||||
9. Decommission на kreknin: ничего не делаем, файлы restored backup и так сидят паркингом на kreknin volume. Не трогать.
|
||||
|
||||
### 3.2 Verdaccio
|
||||
1. На kreknin → VDS: rsync (через `scp -O` или `tar | ssh`) `/volume1/docker/personal/verdaccio/{storage,config}/` → vds:/opt/stacks/verdaccio/.
|
||||
2. На VDS: chown под uid контейнера verdaccio (10001, см. verdaccio Dockerfile).
|
||||
3. **Pre-clean ПОСЛЕ rsync, на VDS** (не на kreknin — кreknin это backup-target read-only-bydefault): удалить старые tarball'ы > N версий из `storage/<scope>/<package>/` либо просто оставить как есть (8.5G нормально для 160 GB VDS).
|
||||
4. На VDS Portainer stack: image `verdaccio/verdaccio:6`, volumes `/opt/stacks/verdaccio/storage:/verdaccio/storage` и `config:/verdaccio/conf`, labels на `verdaccio.kzntsv.site`.
|
||||
5. Smoke: `npm publish` тест с windows-recovery-host против `verdaccio.kzntsv.site`.
|
||||
|
||||
### 3.3 Registry
|
||||
1. На 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).
|
||||
2. На kreknin → VDS: rsync `/volume1/docker/infrastucture/registry/{auth,docker,docker-compose.yml,config.yml}` → vds:/opt/stacks/registry/.
|
||||
3. На VDS Portainer stack: image `registry:2`, volumes для `auth` + `docker` (data) + `config.yml`, labels на `registry.kzntsv.site`. basicAuth middleware если в config задан htpasswd.
|
||||
4. 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
|
||||
|
||||
Reference in New Issue
Block a user