Postgres переезжает сюда физически — backend теперь на отдельном VPS

Раньше предполагалось, что backend и БД живут на одном хосте и делят
Docker-сеть — на деле backend будет на отдельном, ещё не арендованном
VPS, а Postgres стоит здесь же, рядом с Vaultwarden. Возвращает свой
контейнер `db` (общий для обеих баз — vaultwarden создаётся через
POSTGRES_USER/POSTGRES_DB, вторая, для backend, через новый
postgres/init-backend-db.sh), публикует 5432 наружу с hostssl+TLS
(postgres/pg_hba.conf, самоподписанный сертификат генерируется один раз
прямо в deploy.yml). Backup-джоба (pg_dump обеих баз) тоже переехала
сюда из netrunner-backend — дампить логичнее там, где физически лежат
данные.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 17:17:05 +07:00
parent 3b8c0aeebd
commit 9ca6df3dfc
7 changed files with 263 additions and 55 deletions
+106 -32
View File
@@ -1,31 +1,76 @@
# =====================================================================
# netrunner-data — сервисы хранения данных, вынесенные в отдельный от
# основного control-plane стек: сейчас только Vaultwarden (личный/командный
# менеджер паролей).
# netrunner-data — VPS хранения данных: Postgres (общий для Vaultwarden И
# netrunner-backend) + Vaultwarden + периодический backup.
#
# Раньше Vaultwarden жил на проде голым файлом (~/vaultwarden-data/docker-compose.yml)
# без git/CI, с захардкоженными в файле секретами и на SQLite (./data/db.sqlite3).
# Здесь: секреты — только через .env (сам .env НЕ в git, см. .gitignore; на
# деплое собирается из GitHub Actions/Gitea Actions secrets, см.
# .github/workflows/deploy.yml), БД — Postgres вместо SQLite.
# Топология: backend живёт на ОТДЕЛЬНОМ VPS (ещё не арендован) — только
# app/redis/мониторинг, без своей БД. Postgres физически стоит здесь, рядом
# с Vaultwarden, и backend ходит сюда ПО СЕТИ (не через общий Docker-network,
# как было бы, живи они на одном хосте). Из-за этого:
# - Postgres публикует 5432 наружу (не только 127.0.0.1) — обязательно
# см. postgres/pg_hba.conf: там TLS-required (hostssl) для внешних
# подключений и временная заглушка 0.0.0.0/0 вместо реального IP
# backend-VPS (заменить, как только он будет арендован).
# - Нужен TLS-сертификат для Postgres (самоподписанный — см. ниже, шаг
# генерации перед первым запуском).
# - Firewall (ufw/iptables) на этом VPS ОБЯЗАТЕЛЬНО должен ограничивать
# 5432 конкретным IP backend-VPS — pg_hba.conf сам по себе не защита от
# сканирования порта. ВАЖНО: Docker пишет свои правила в iptables
# напрямую и может обходить обычные ufw deny-правила для
# опубликованных портов — ограничивать нужно либо через цепочку
# DOCKER-USER, либо через `ufw route`, а не просто `ufw deny 5432`.
#
# ВАЖНО: своего Postgres-контейнера здесь больше нет — Vaultwarden делит один
# и тот же Postgres-процесс с netrunner-backend (сервис `db`/контейнер
# `netrunner-db` из netrunner-backend/docker-compose.prod.yml), просто в
# отдельной базе (vaultwarden) с собственным пользователем. Оба compose-стека
# должны быть подняты на одном VPS и слиты в общую внешнюю сеть
# `netrunner_grid` (см. миграцию в scripts/migrate-vaultwarden.md — там же и
# однократная команда CREATE DATABASE/CREATE USER на этом общем Postgres).
# Самоподписанный TLS-сертификат (postgres/certs/server.{crt,key}) генерируется
# автоматически и один раз .gitea/.github workflows/deploy.yml при первом
# деплое (если файлов ещё нет) — руками ничего генерировать не нужно, если
# деплоите через CI. Для ручного/локального запуска — см. ту же команду
# openssl в deploy.yml.
#
# ВАЖНО про переход со старого SQLite-инстанса: Vaultwarden сам не мигрирует
# данные из ./data/db.sqlite3 в Postgres при простой смене DATABASE_URL — это
# отдельная, аккуратная операция через pgloader (см. scripts/migrate-vaultwarden.md),
# а не просто "поднять новый сервис". Поднимать этот compose "как есть" поверх
# старых данных без миграции = Vaultwarden просто заведёт новую пустую БД в
# Postgres, старые данные останутся нетронутыми в ./data, но перестанут быть
# видны приложению.
# Перенос данных со старого SQLite-инстанса Vaultwarden — см.
# scripts/migrate-vaultwarden.md.
# =====================================================================
services:
db:
image: postgres:16-alpine
container_name: netrunner-db
restart: always
command:
- postgres
- -c
- ssl=on
- -c
- ssl_cert_file=/etc/postgresql-certs/server.crt
- -c
- ssl_key_file=/etc/postgresql-certs/server.key
- -c
- hba_file=/etc/postgresql/pg_hba.conf
environment:
# POSTGRES_USER/POSTGRES_DB — создают базу Vaultwarden при первой
# инициализации. Вторая база (для backend) создаётся отдельным
# init-скриптом ниже (postgres/init-backend-db.sh), т.к. официальный
# образ сам создаёт только одну базу+юзера из этих двух переменных.
POSTGRES_USER: ${VW_DB_USER}
POSTGRES_PASSWORD: ${VW_DB_PASSWORD}
POSTGRES_DB: ${VW_DB_NAME:-vaultwarden}
BACKEND_DB_USER: ${BACKEND_DB_USER}
BACKEND_DB_PASSWORD: ${BACKEND_DB_PASSWORD}
BACKEND_DB_NAME: ${BACKEND_DB_NAME:-netrunner}
volumes:
- netrunner_db_data:/var/lib/postgresql/data
- ./postgres/pg_hba.conf:/etc/postgresql/pg_hba.conf:ro
- ./postgres/certs:/etc/postgresql-certs:ro
- ./postgres/init-backend-db.sh:/docker-entrypoint-initdb.d/init-backend-db.sh:ro
ports:
# Не 127.0.0.1 — backend-VPS должен достучаться по сети. Обязательно
# firewall, см. шапку файла.
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${VW_DB_USER} -d ${VW_DB_NAME:-vaultwarden}"]
interval: 5s
timeout: 5s
retries: 5
networks:
- netrunner_data
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
@@ -37,10 +82,10 @@ services:
- LOG_LEVEL=${VAULTWARDEN_LOG_LEVEL:-info}
- ROCKET_PORT=8081
- WEBSOCKET_ENABLED=true
# Общий Postgres-процесс с netrunner-backend (контейнер netrunner-db,
# см. шапку файла) — отдельная база и юзер, не переиспользуем DB_USER/
# DB_PASSWORD бэкенда.
- DATABASE_URL=postgresql://${VW_DB_USER}:${VW_DB_PASSWORD}@netrunner-db:5432/${VW_DB_NAME:-vaultwarden}
# Тот же контейнер БД, что и backend, но в общей локальной Docker-сети
# (не через публичный 5432) — TLS тут не обязателен, трафик не выходит
# с хоста.
- DATABASE_URL=postgresql://${VW_DB_USER}:${VW_DB_PASSWORD}@db:5432/${VW_DB_NAME:-vaultwarden}
- SMTP_HOST=${SMTP_HOST}
- SMTP_FROM=${SMTP_FROM}
- SMTP_PORT=${SMTP_PORT:-465}
@@ -53,12 +98,41 @@ services:
- ./data:/data
ports:
- "127.0.0.1:8081:8081"
depends_on:
db:
condition: service_healthy
networks:
- netrunner_grid
- netrunner_data
# Периодический pg_dump обеих баз (vaultwarden + backend) + опциональная
# офсайт-копия через rclone. Раньше жил в netrunner-backend, переехал сюда
# вместе с самой БД — дампить логичнее там, где физически стоит Postgres.
backup:
image: postgres:16-alpine
container_name: netrunner-data-backup
restart: always
entrypoint: ["/bin/sh", "/scripts/backup.sh"]
environment:
- DATABASE_URL=postgres://${VW_DB_USER}:${VW_DB_PASSWORD}@db:5432/${VW_DB_NAME:-vaultwarden}
- EXTRA_DATABASE_URL=postgres://${BACKEND_DB_USER}:${BACKEND_DB_PASSWORD}@db:5432/${BACKEND_DB_NAME:-netrunner}
- BACKUP_DIR=/backups
- BACKUP_INTERVAL_SEC=${BACKUP_INTERVAL_SEC:-21600}
- BACKUP_RETENTION_DAYS=${BACKUP_RETENTION_DAYS:-14}
- RCLONE_REMOTE=${RCLONE_REMOTE:-}
- RCLONE_CONFIG_CONTENT=${RCLONE_CONFIG_CONTENT:-}
volumes:
- ./scripts/backup.sh:/scripts/backup.sh:ro
- netrunner_db_backups:/backups
depends_on:
db:
condition: service_healthy
networks:
- netrunner_data
networks:
# external: этот стек не поднимает Postgres сам — сеть уже создана
# netrunner-backend/docker-compose.prod.yml (там же живёт netrunner-db).
# Поднимать backend-стек первым.
netrunner_grid:
external: true
netrunner_data:
driver: bridge
volumes:
netrunner_db_data:
netrunner_db_backups: