🏦 Capital - архитектура продакшен-инфраструктуры
Версия 1.0 - 15.09.2026 - CTO-план Продукт: core-banking платформа Capital (bo. / app. / kyc. algorys.cc) Подготовлено: CTO (Claude) по итогам совета с внешними консультантами (Grok reasoning + GPT), референс - платформа Iorys.
1. 📌 Резюме для CEO
Продукт функционально готов (183 автотеста, AML/KYT, 4-eyes, 2FA, аудит), но инфраструктура - стартаперская: всё живёт на одном шаредном сервере вместе с Nextcloud, и у базы данных нет ни одного бэкапа. Любой отказ диска = полная потеря банка.
Целевое состояние достижимо за ~2-4 рабочих дня критики + месяц доводки, бюджет ~$60-80/мес (профи-вариант ~$130-150/мес). Ни один компонент не стоит «тысячи долларов».
Три главных решения: 1. 🖥 Capital переезжает на собственный выделенный сервер (team-nextcloud остаётся файловым сервером команды - его не трогаем). 2. 💾 Бэкапы прежде всего: pgBackRest + WAL-архивация в два независимых хранилища, шифрование age, автоматический еженедельный restore-тест. RPO ≤ 5 минут. 3. 📈 Мониторинг + staging + CI/CD-деплой - чтобы выглядеть и работать как банк, а не как pet-проект.
2. 🔍 Текущее состояние (as-is) и точки отказа
| Компонент | Сейчас | Риск |
|---|---|---|
| Сервер | 1 шаредный VPS (вместе с Nextcloud), 75GB | 🔴 единая точка отказа всего банка |
| Postgres | 1 контейнер, 1 volume | 🔴 отказ диска = потеря всех данных |
| Бэкапы БД | отсутствуют | 🔴 критично, риск №1 |
| Деплой | rsync с dev-машины + build на проде | 🟠 нет воспроизводимости, нет отката |
| Секреты | .env chmod 600 | 🟠 без версионирования/шифрования |
| Мониторинг | только Docker healthcheck | 🟠 о падении узнаём от клиента |
| Cloudflare tunnel | 1 connector | 🟡 перезапуск = недоступность |
| Документы клиентов | BLOB в Postgres (cap 5MB) | 🟡 раздувает БД и бэкапы |
| Что уже хорошо | CF proxy + скрытый origin, HMAC-вебхуки fail-closed, 2FA, RBAC, CSRF, rate-limit, аудит-лог, Alembic, git-remote | ✅ |
3. 🗺 Целевая топология (to-be)
Интернет
|
[Cloudflare: WAF/proxy/tunnel]
(2 connector'а cloudflared)
|
+------------------+------------------+
| |
🖥 capital-prod (Hetzner, NEW) 🖥 capital-ops (Hetzner, NEW)
CCX23: 4 vCPU ded / 16GB / 160GB CX22 + volume 100GB
- backoffice / cabinet / kyc - staging (тот же compose, throwaway-БД)
- Postgres 16 (WAL-архивация) - Uptime Kuma (внешний надзор за prod)
- pgBackRest (клиент) - pgBackRest repo-зеркало + restore-тест
- Netdata, node-alerts → Telegram - Netdata
| |
+----------- бэкапы (age) ------------+
|
☁️ Backblaze B2 (EU, Object Lock/WORM) - копия №1 off-site
☁️ Hetzner Storage Box 1TB - копия №2 off-site
|
team-nextcloud - ОСТАЁТСЯ как файл-сервер команды.
Capital с него уезжает целиком (переезд = первый DR-тест).
Принципы распределения рисков: - Prod и ops/staging - разные серверы в разных дата-центрах Hetzner (Nuremberg / Falkenstein). - Бэкапы - в двух независимых хранилищах у двух разных провайдеров (B2 + Storage Box), обе копии зашифрованы age, ключ расшифровки НЕ на prod-сервере. - Мониторинг prod живёт НЕ на prod (ops-сервер видит падение prod снаружи). - HA-кластер (Patroni и т.п.) сейчас НЕ нужен - на нашем масштабе правильнее быстрый DR (восстановление ≤ 2-4 ч), это в 10 раз дешевле и проще. - Managed Postgres не берём: дороже, меньше контроля для аудита; self-hosted + PITR на этом масштабе надёжнее по цене/качеству (консенсус обоих консультантов).
4. 🗄 Хранение данных
| Данные | Где | Политика |
|---|---|---|
| Операционные (клиенты, счета, платежи, ledger) | Postgres 16 на capital-prod | WAL-архивация каждые ≤5 мин, PITR |
| Документы клиентов (KYC-файлы) | поэтапно: Postgres BLOB → Backblaze B2 (шифрование age, в БД - только метаданные + ключ объекта) | миграция в месяц 1 |
| Аудит-лог | append-only схема в Postgres + hash-chain (каждая запись несёт хэш предыдущей - доказуемая неизменность) | ежедневный дайджест → B2 c Object Lock (WORM) |
| Retention (комплаенс) | операционные + аудит: 7 лет; AML/KYT-материалы: 10 лет | закрепить в политике |
| Секреты | sops + age в git (зашифрованы) + runtime через .env/Docker secrets | ключ age - только у CEO + на prod |
Postgres-настройки банковского уровня: wal_level=replica, archive_mode=on, wal_compression, archive_command → pgBackRest; контрольная запись LSN перед каждой миграцией.
5. 💾 Бэкапы и Disaster Recovery (правило 3-2-1)
Инструменты: pgBackRest (БД) + restic (конфиги/файлы), всё шифруется age.
| Что | Частота | Куда |
|---|---|---|
| Full-бэкап БД | ежесуточно 03:00 UTC | B2 + Storage Box |
| Incremental | каждые 6 ч | B2 |
| WAL-архив (PITR) | непрерывно, ≤5 мин | B2 |
| Конфиги/compose/секреты (sops) | ежесуточно | B2 + Storage Box |
| Копия №2 всего | еженедельно | Storage Box (независимый от B2) |
Целевые показатели: RPO ≤ 5 минут (теряем максимум 5 минут данных), RTO ≤ 2-4 часа (полное восстановление банка на новом сервере).
Restore-тест - автоматический, еженедельный: ops-сервер разворачивает бэкап в изолированный контейнер, проверяет pg_isready + контрольные суммы ключевых таблиц, шлёт отчёт в Telegram. Бэкап, который не восстанавливали, - это не бэкап.
DR-ранбук (документируется в репо): заказ нового сервера → restore из B2 → deploy образов из GHCR → перевод Cloudflare tunnel → смоук-тест. Прогоняем учения раз в квартал.
Мониторинг бэкапов: каждая джоба пингует Healthchecks.io - если бэкап НЕ прошёл, алерт в Telegram (отсутствие сигнала = тревога, а не тишина).
6. 📈 Мониторинг и алертинг (всё бесплатное)
| Слой | Инструмент | Где | $/мес |
|---|---|---|---|
| Uptime всех URL + партнёрских API | Uptime Kuma | ops-сервер | 0 |
| Метрики хоста/контейнеров/Postgres | Netdata | оба сервера | 0 |
| Ошибки приложений (stack-traces) | Sentry free tier | SaaS | 0 |
| Cron/бэкап-джобы | Healthchecks.io | SaaS | 0 |
| Дашборды/логи (по мере роста) | Grafana Cloud free | SaaS | 0 |
Все алерты - в Telegram, три канала: 🔴 critical (будим CEO), 🟠 warning, 🔵 backup/report. Внешняя status-page (BetterStack free / GitHub Pages) - вне Cloudflare, чтобы работала даже при падении CF.
7. 🔐 Безопасность (поверх уже сделанного)
- Hardening-стандарт группы на оба новых сервера с первого часа: SSH только через Tailscale, ufw deny inbound, fail2ban, unattended-upgrades, Telegram-алерт на SSH-вход (с анти-спамом), порты приложений только на 127.0.0.1, Docker без privileged.
- Секреты: sops + age (конфиги в git зашифрованы, расшифровка только на серверах); значения впрыскиваются оператором мимо чата - как заведено.
- CI-сканеры (все бесплатные): gitleaks (секреты в коммитах), Trivy (уязвимости образов), Dependabot (зависимости), CodeQL.
- Доступы: GitHub - protected main + обязательная 2FA; Tailscale ACL - prod видит только CEO и деплой-ключ; ревизия доступов раз в квартал.
- Incident Response план (короткий документ): кто, что, в каком порядке при инциденте: изоляция → оценка → восстановление → пост-мортем → уведомления клиентам.
- Внешний pentest - 1 раз в год (~$2-3.5k разово, закладываем в бюджет квартала, обязателен перед активными продажами и для партнёров/регуляторов).
- Graceful degradation при отказе партнёров (частично уже в коде): rail недоступен → платёж в
pending_partner, клиент видит «принят, в обработке», ledger не финализируется; SumSub упал → заявка сохраняется draft; Resend упал → email-очередь с ретраями. Клиент никогда не видит ошибку 500 вместо статуса.
8. 🚀 Деплой-пайплайн (уходим от rsync)
git push → GitHub Actions: тесты (183) + сканеры → сборка образов → GHCR
→ авто-деплой на staging (ops) → смоук-тест
→ ручное подтверждение → деплой на prod (docker compose pull && up -d)
- Rollback = откат на предыдущий образ (храним 5 последних в GHCR) - секунды.
- Миграции - строго expand/contract: сначала совместимая миграция, потом код, деструктивные изменения - отдельным релизом позже. Перед миграцией - автоматический чекпоинт бэкапа + запись LSN (можно PITR ровно к моменту «до»).
- Staging - обязателен (на ops-сервере, throwaway-БД): каждый релиз сначала живёт там. Стресс/security-тесты - только на staging (стандарт группы).
- Kоротое окно (5-15 сек) при рестарте compose на пилоте приемлемо; blue-green - в квартале 1.
9. 🧯 Матрица отказов
| Отказ | Клиент видит | Наши действия | Время |
|---|---|---|---|
| capital-prod умер | страницу тех-работ (CF) | DR: новый сервер + restore из B2 + перевод tunnel | ≤ 2-4 ч |
| Диск/данные повреждены | тех-работы | PITR на момент до сбоя | ≤ 2-4 ч, потеря ≤ 5 мин |
| Cloudflare упал | недоступность | status-page вне CF; ждём CF (SLA выше нашего не обещаем) | по CF |
| Rail-партнёр упал | «платёж в обработке» | очередь pending_partner, ретраи, алерт |
авто |
| NS Cards упал | «операция ожидает» | pending_external, reconcile-джоба |
авто |
| SumSub упал | заявка сохранена | pending_provider, ретраи вебхуков |
авто |
| Resend упал | письмо позже | email-очередь, ретраи | авто |
| ops-сервер умер | ничего (prod живёт) | пересоздать ops по ранбуку | ≤ 1 день |
10. 🗓 Roadmap внедрения
Неделя 1 - «перестать жить без бэкапов» (2-4 рабочих дня)
- Заказать capital-prod + capital-ops (Hetzner API), hardening с первого часа.
- pgBackRest + WAL → B2 + Storage Box, age-шифрование, Healthchecks-пинги.
- Переезд Capital на capital-prod (по сути - первый DR-тест: restore из бэкапа).
- Uptime Kuma + Netdata + Telegram-алерты.
- Первый ручной restore-тест - убедиться, что восстановление реально работает.
Месяц 1 - «профессиональная база» (1-2 недели работ)
- GitHub Actions CI/CD + GHCR + staging на ops.
- sops + age для секретов; сканеры gitleaks/Trivy/Dependabot в CI.
- Sentry + автоматический еженедельный restore-тест.
- Миграция документов из BLOB → B2; второй cloudflared connector.
- DR-ранбук + первые учения; IR-план; hash-chain аудита + WORM-дайджесты.
Квартал 1 - «зрелость» (3-5 недель суммарно)
- Blue-green деплой, status-page, второй email-провайдер (резерв).
- Квартальные DR-учения + security tabletop.
- Внешний pentest (перед активными продажами).
- Формальный risk-register + политики (backup/retention/access/change) - партнёры и регуляторы такое спрашивают.
11. 💰 Бюджет
Базовый (рекомендую стартовать с него)
| Компонент | Продукт | $/мес |
|---|---|---|
| Prod-сервер | Hetzner CCX23 (4 vCPU ded, 16GB, 160GB) | ~33 |
| Ops/staging-сервер | Hetzner CX22 + volume 100GB | ~12 |
| Бэкап off-site №1 | Backblaze B2 (Object Lock) | ~3-6 |
| Бэкап off-site №2 | Hetzner Storage Box 1TB | ~4 |
| Мониторинг/ошибки/CI/WAF/VPN | Uptime Kuma, Netdata, Sentry, Healthchecks, Grafana Cloud, GitHub Actions, Cloudflare, Tailscale - все free-tier | 0 |
| Итого | ~$52-55/мес |
Профи-апгрейд (когда пойдут клиенты)
| Добавка | Зачем | $/мес |
|---|---|---|
| Cloudflare Pro | расширенный WAF/правила | 25 |
| Sentry Team | больше ошибок/ретеншн | ~26 |
| Healthchecks/BetterStack paid | больше проверок | ~5-10 |
| GitHub Team + Tailscale Starter | орг-контроли доступа | ~20 |
| Итого профи | ~$130-150/мес |
Разовые: внешний pentest ~$2-3.5k/год (квартал 1+).
12. 🤝 Что нужно от CEO
- 🔑 Hetzner API token (проект для Capital) - закажу и настрою оба сервера сам, мимо UI.
- 🔑 Backblaze B2 - аккаунт (или создаём новый), ключ сгенерирую на стороне сервера мимо чата.
- ✅ Утвердить бюджет (~$52-55/мес база) и переезд prod на выделенный сервер.
- 💳 (Отдельный трек) Оплата инвойсов Papaya и NS Cards - для флипа симуляторов на live.
- 🔒 Age-ключ восстановления бэкапов - сгенерирую, приватная половина хранится у CEO (не на серверах): без него бэкапы не расшифровать, с ним банк восстанавливается даже при потере всего.
13. 📎 Приложение: сводка мнений консультантов
| Вопрос | 🛰 Grok (reasoning) | 🤖 GPT | Решение CTO |
|---|---|---|---|
| Серверов | 3 (prod + DR/staging + backup-node) | 2 (prod + ops) | 2 - backup-node избыточен, его роль закрывают B2+Storage Box |
| Postgres | self-hosted + hot-replica сразу | self-hosted, warm standby позже | self-hosted, replica позже - на пилоте DR за 2-4 ч достаточен |
| Деплой | Coolify (PaaS-панель) | GitHub Actions + compose pull | GitHub Actions + compose - меньше движущихся частей, Coolify опционально позже |
| Бэкапы | pgBackRest + WAL в R2, restore-тест еженедельно | pgBackRest + WAL в B2, restore-тест на ops | консенсус, B2 (Object Lock дешевле) + Storage Box |
| BLOB-документы | вынести в R2 | вынести в B2, постепенно | консенсус - выносим, поэтапно |
| Секреты | sops + age | sops + age | консенсус |
| Мониторинг | Netdata + Uptime Kuma + Grafana free + Sentry | то же + Healthchecks.io | консенсус |
| HA сейчас | нет, быстрый DR | нет, быстрый DR | консенсус |
| Бюджет | ~$82-84 | ~$50-75 база / $130-150 профи | ~$52-55 база |
Оба консультанта независимо назвали одни и те же топ-риски: нет бэкапов → нет restore-тестов → прод смешан с Nextcloud → ручной деплой → нет мониторинга. Это и есть порядок работ.