Vaultwarden делит один Postgres-процесс с netrunner-backend
Убирает собственный контейнер db — вместо своего Postgres подключается внешней сетью (netrunner_grid, external: true) к netrunner-db из netrunner-backend/docker-compose.prod.yml, в отдельной базе/юзере (VW_DB_*, был DB_*). Экономит ресурсы на VPS, где раньше крутились бы два отдельных Postgres-процесса. Добавляет пошаговый ранбук переноса существующих данных со старого SQLite-инстанса (scripts/migrate-vaultwarden.md, через checkpoint WAL + pgloader data-only на уже созданную diesel-схему). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+9
-6
@@ -1,12 +1,15 @@
|
|||||||
# Скопировать в .env и заполнить реальными значениями. .env — в .gitignore,
|
# Скопировать в .env и заполнить реальными значениями. .env — в .gitignore,
|
||||||
# никогда не коммитить с настоящими секретами. На деплое (см.
|
# никогда не коммитить с настоящими секретами. На деплое (см.
|
||||||
# .github/workflows/deploy.yml) этот файл целиком собирается из GitHub Actions
|
# .github/workflows/deploy.yml) этот файл целиком собирается из GitHub Actions/
|
||||||
# secrets прямо на VPS — локальный .env нужен только для ручного/dev-запуска.
|
# Gitea Actions secrets прямо на VPS — локальный .env нужен только для
|
||||||
|
# ручного/dev-запуска.
|
||||||
|
|
||||||
# --- Postgres (данные Vaultwarden) ---
|
# --- Postgres (общий контейнер netrunner-db из netrunner-backend, отдельная
|
||||||
DB_USER=vaultwarden
|
# база+юзер внутри него — см. scripts/migrate-vaultwarden.md, шаг "CREATE
|
||||||
DB_PASSWORD=CHANGE_ME_DB_PASSWORD_openssl_rand_base64_24
|
# DATABASE/CREATE USER") ---
|
||||||
DB_NAME=vaultwarden
|
VW_DB_USER=vaultwarden
|
||||||
|
VW_DB_PASSWORD=CHANGE_ME_VW_DB_PASSWORD_openssl_rand_base64_24
|
||||||
|
VW_DB_NAME=vaultwarden
|
||||||
|
|
||||||
# --- Vaultwarden ---
|
# --- Vaultwarden ---
|
||||||
VAULTWARDEN_DOMAIN=https://vault.netrunner-vpn.com
|
VAULTWARDEN_DOMAIN=https://vault.netrunner-vpn.com
|
||||||
|
|||||||
+28
-44
@@ -1,45 +1,31 @@
|
|||||||
# =====================================================================
|
# =====================================================================
|
||||||
# netrunner-data — сервисы хранения данных, вынесенные в отдельный от
|
# netrunner-data — сервисы хранения данных, вынесенные в отдельный от
|
||||||
# основного control-plane стек: сейчас только Vaultwarden (личный/командный
|
# основного control-plane стек: сейчас только Vaultwarden (личный/командный
|
||||||
# менеджер паролей) + его собственный Postgres.
|
# менеджер паролей).
|
||||||
#
|
#
|
||||||
# Раньше Vaultwarden жил на проде голым файлом (~/vaultwarden-data/docker-compose.yml)
|
# Раньше Vaultwarden жил на проде голым файлом (~/vaultwarden-data/docker-compose.yml)
|
||||||
# без git/CI, с захардкоженными в файле секретами и на SQLite (./data/db.sqlite3).
|
# без git/CI, с захардкоженными в файле секретами и на SQLite (./data/db.sqlite3).
|
||||||
# Здесь: секреты — только через .env (сам .env НЕ в git, см. .gitignore; на
|
# Здесь: секреты — только через .env (сам .env НЕ в git, см. .gitignore; на
|
||||||
# деплое собирается из GitHub Actions secrets, см. .github/workflows/deploy.yml),
|
# деплое собирается из GitHub Actions/Gitea Actions secrets, см.
|
||||||
# БД — Postgres вместо SQLite.
|
# .github/workflows/deploy.yml), БД — Postgres вместо SQLite.
|
||||||
#
|
#
|
||||||
# ВАЖНО про переход на Postgres: Vaultwarden сам не мигрирует данные из уже
|
# ВАЖНО: своего Postgres-контейнера здесь больше нет — Vaultwarden делит один
|
||||||
# существующего ./data/db.sqlite3 в Postgres при простой смене DATABASE_URL —
|
# и тот же Postgres-процесс с netrunner-backend (сервис `db`/контейнер
|
||||||
# это отдельная, аккуратная операция (см. официальный вики Vaultwarden,
|
# `netrunner-db` из netrunner-backend/docker-compose.prod.yml), просто в
|
||||||
# "Backing up your vault" + миграция бэкенда), а не просто "поднять новый
|
# отдельной базе (vaultwarden) с собственным пользователем. Оба compose-стека
|
||||||
# сервис". Перед первым запуском этого compose поверх УЖЕ ЖИВОГО инстанса с
|
# должны быть подняты на одном VPS и слиты в общую внешнюю сеть
|
||||||
# реальными данными пользователей — сначала сделать полный бэкап текущей
|
# `netrunner_grid` (см. миграцию в scripts/migrate-vaultwarden.md — там же и
|
||||||
# ./data (включая attachments и rsa-ключи), затем мигрировать содержимое
|
# однократная команда CREATE DATABASE/CREATE USER на этом общем Postgres).
|
||||||
# db.sqlite3 в Postgres, и только потом переключать DATABASE_URL. Поднимать
|
#
|
||||||
# этот compose "как есть" поверх существующих данных без миграции = Vaultwarden
|
# ВАЖНО про переход со старого SQLite-инстанса: Vaultwarden сам не мигрирует
|
||||||
# просто заведёт новую пустую БД в Postgres, старые данные останутся
|
# данные из ./data/db.sqlite3 в Postgres при простой смене DATABASE_URL — это
|
||||||
# нетронутыми в volume, но перестанут быть видны приложению.
|
# отдельная, аккуратная операция через pgloader (см. scripts/migrate-vaultwarden.md),
|
||||||
|
# а не просто "поднять новый сервис". Поднимать этот compose "как есть" поверх
|
||||||
|
# старых данных без миграции = Vaultwarden просто заведёт новую пустую БД в
|
||||||
|
# Postgres, старые данные останутся нетронутыми в ./data, но перестанут быть
|
||||||
|
# видны приложению.
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
services:
|
services:
|
||||||
db:
|
|
||||||
image: postgres:16-alpine
|
|
||||||
container_name: netrunner-data-db
|
|
||||||
restart: unless-stopped
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: ${DB_USER}
|
|
||||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
||||||
POSTGRES_DB: ${DB_NAME:-vaultwarden}
|
|
||||||
volumes:
|
|
||||||
- netrunner_data_db:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME:-vaultwarden}"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
networks:
|
|
||||||
- netrunner_data
|
|
||||||
|
|
||||||
vaultwarden:
|
vaultwarden:
|
||||||
image: vaultwarden/server:latest
|
image: vaultwarden/server:latest
|
||||||
container_name: vaultwarden
|
container_name: vaultwarden
|
||||||
@@ -51,9 +37,10 @@ services:
|
|||||||
- LOG_LEVEL=${VAULTWARDEN_LOG_LEVEL:-info}
|
- LOG_LEVEL=${VAULTWARDEN_LOG_LEVEL:-info}
|
||||||
- ROCKET_PORT=8081
|
- ROCKET_PORT=8081
|
||||||
- WEBSOCKET_ENABLED=true
|
- WEBSOCKET_ENABLED=true
|
||||||
# postgresql:// вместо файла-заглушки sqlite — сам образ vaultwarden/server
|
# Общий Postgres-процесс с netrunner-backend (контейнер netrunner-db,
|
||||||
# уже собран со всеми тремя бэкендами, отдельный тег не нужен.
|
# см. шапку файла) — отдельная база и юзер, не переиспользуем DB_USER/
|
||||||
- DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@db:5432/${DB_NAME:-vaultwarden}
|
# DB_PASSWORD бэкенда.
|
||||||
|
- DATABASE_URL=postgresql://${VW_DB_USER}:${VW_DB_PASSWORD}@netrunner-db:5432/${VW_DB_NAME:-vaultwarden}
|
||||||
- SMTP_HOST=${SMTP_HOST}
|
- SMTP_HOST=${SMTP_HOST}
|
||||||
- SMTP_FROM=${SMTP_FROM}
|
- SMTP_FROM=${SMTP_FROM}
|
||||||
- SMTP_PORT=${SMTP_PORT:-465}
|
- SMTP_PORT=${SMTP_PORT:-465}
|
||||||
@@ -66,15 +53,12 @@ services:
|
|||||||
- ./data:/data
|
- ./data:/data
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8081:8081"
|
- "127.0.0.1:8081:8081"
|
||||||
depends_on:
|
|
||||||
db:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
networks:
|
||||||
- netrunner_data
|
- netrunner_grid
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
netrunner_data:
|
# external: этот стек не поднимает Postgres сам — сеть уже создана
|
||||||
driver: bridge
|
# netrunner-backend/docker-compose.prod.yml (там же живёт netrunner-db).
|
||||||
|
# Поднимать backend-стек первым.
|
||||||
volumes:
|
netrunner_grid:
|
||||||
netrunner_data_db:
|
external: true
|
||||||
|
|||||||
@@ -0,0 +1,147 @@
|
|||||||
|
# Перенос Vaultwarden со старого VPS на новый (136.244.78.208), SQLite → Postgres
|
||||||
|
|
||||||
|
Все команды — ручные, выполняются вами на серверах (у меня нет SSH-доступа ни
|
||||||
|
к старому, ни к новому VPS). Ниже — точная последовательность без потери
|
||||||
|
данных. Не удалять старый сервер/старые файлы, пока не пройден пункт
|
||||||
|
"Проверка" в самом конце.
|
||||||
|
|
||||||
|
Старый инстанс живёт на SQLite в WAL-режиме (видно по файлам `db.sqlite3-wal`
|
||||||
|
и `db.sqlite3-shm` рядом с `db.sqlite3` — это значит часть последних изменений
|
||||||
|
может ещё не быть слита в основной файл). Поэтому нельзя просто скопировать
|
||||||
|
`db.sqlite3` в одиночку — копируем директорию `data/` целиком и только после
|
||||||
|
чистой остановки контейнера.
|
||||||
|
|
||||||
|
## Фаза 0 — предварительно, на новом VPS (136.244.78.208)
|
||||||
|
|
||||||
|
Задеплоить (или обновить) прод `netrunner-backend` **первым** — Vaultwarden
|
||||||
|
теперь не поднимает свой Postgres, а подключается к тому же контейнеру
|
||||||
|
`netrunner-db` и сети `netrunner_grid`, которые создаёт
|
||||||
|
`netrunner-backend/docker-compose.prod.yml`. Пока backend не поднят на этом
|
||||||
|
VPS — `docker compose up` для vaultwarden ниже упадёт с "network netrunner_grid
|
||||||
|
not found".
|
||||||
|
|
||||||
|
Затем создать отдельную базу и роль для Vaultwarden в этом общем Postgres
|
||||||
|
(не переиспользовать логин backend'а):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# На новом VPS, после того как netrunner-backend/docker-compose.prod.yml поднят
|
||||||
|
docker exec -it netrunner-db psql -U "$DB_USER" -d postgres -c \
|
||||||
|
"CREATE ROLE vaultwarden WITH LOGIN PASSWORD 'СЮДА_ТОТ_ЖЕ_ПАРОЛЬ_ЧТО_В_VW_DB_PASSWORD';"
|
||||||
|
docker exec -it netrunner-db psql -U "$DB_USER" -d postgres -c \
|
||||||
|
"CREATE DATABASE vaultwarden OWNER vaultwarden;"
|
||||||
|
```
|
||||||
|
|
||||||
|
(`$DB_USER` — существующий админ-юзер backend-Postgres, из его `.env`.)
|
||||||
|
|
||||||
|
## Фаза 1 — на СТАРОМ сервере (текущий Vaultwarden)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/vaultwarden-data
|
||||||
|
|
||||||
|
# Останавливаем контейнер — чистое закрытие sqlite-соединения (checkpoint
|
||||||
|
# WAL в основной файл на выходе). НЕ удалять после — только stop.
|
||||||
|
docker compose stop vaultwarden
|
||||||
|
|
||||||
|
# На всякий случай форсируем checkpoint+truncate WAL явно, а не полагаемся
|
||||||
|
# только на чистое закрытие процессом:
|
||||||
|
docker run --rm -v "$PWD/data:/data" alpine:3.20 sh -c \
|
||||||
|
"apk add --no-cache sqlite >/dev/null && sqlite3 /data/db.sqlite3 'PRAGMA wal_checkpoint(TRUNCATE);'"
|
||||||
|
|
||||||
|
# Теперь весь ./data — самодостаточный снимок. Архивируем целиком одним
|
||||||
|
# куском (attachments, rsa_key.pem, db.sqlite3 — всё вместе, не выборочно).
|
||||||
|
tar czf ~/vaultwarden-data-backup-$(date +%Y%m%d-%H%M%S).tar.gz -C ~/vaultwarden-data data
|
||||||
|
|
||||||
|
ls -la ~/vaultwarden-data-backup-*.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Скопировать архив на новый VPS (с любой машины, у которой есть доступ к
|
||||||
|
обоим — например, с вашего ноутбука):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
scp root@<СТАРЫЙ_VPS_IP>:~/vaultwarden-data-backup-*.tar.gz .
|
||||||
|
scp vaultwarden-data-backup-*.tar.gz root@136.244.78.208:~/
|
||||||
|
```
|
||||||
|
|
||||||
|
Старый Vaultwarden пока НЕ запускать обратно — он останется единственным
|
||||||
|
живым источником правды до подтверждённого успеха миграции (Фаза 4).
|
||||||
|
|
||||||
|
## Фаза 2 — распаковка на НОВОМ сервере
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# На новом VPS (136.244.78.208)
|
||||||
|
mkdir -p ~/netrunner-data
|
||||||
|
cd ~/netrunner-data
|
||||||
|
git clone <URL_РЕПО_netrunner-data> . 2>/dev/null || true # если ещё не клонирован
|
||||||
|
tar xzf ~/vaultwarden-data-backup-*.tar.gz -C ~/netrunner-data
|
||||||
|
# теперь ~/netrunner-data/data/db.sqlite3 (+ -wal/-shm, rsa_key.pem, ...) на месте
|
||||||
|
|
||||||
|
ls -la ~/netrunner-data/data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Фаза 3 — конвертация SQLite → Postgres через pgloader
|
||||||
|
|
||||||
|
Сначала дать Vaultwarden создать пустую Postgres-схему (diesel-миграции идут
|
||||||
|
из самого бинаря при первом старте с `DATABASE_URL=postgresql://...`) —
|
||||||
|
**НЕ через pgloader**: типы колонок в postgres-схеме vaultwarden подогнаны под
|
||||||
|
его собственный Rust/diesel-код, автосоздание схемы pgloader'ом из sqlite-типов
|
||||||
|
даст несовместимую структуру.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# .env уже должен быть заполнен (VW_DB_USER/VW_DB_PASSWORD/VW_DB_NAME и т.д.)
|
||||||
|
cd ~/netrunner-data
|
||||||
|
docker compose up -d vaultwarden
|
||||||
|
sleep 5
|
||||||
|
docker compose logs vaultwarden | tail -30 # убедиться что миграции прошли, схема создана
|
||||||
|
docker compose stop vaultwarden # снова стоп — дальше пишет только pgloader
|
||||||
|
```
|
||||||
|
|
||||||
|
Теперь перелить данные (не схему) из sqlite-файла в уже созданную схему:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm \
|
||||||
|
--network netrunner_grid \
|
||||||
|
-v ~/netrunner-data/data:/data \
|
||||||
|
dimitri/pgloader:latest \
|
||||||
|
pgloader \
|
||||||
|
--with "data only" \
|
||||||
|
--with "disable triggers" \
|
||||||
|
--with "quote identifiers" \
|
||||||
|
sqlite:///data/db.sqlite3 \
|
||||||
|
postgresql://vaultwarden:СЮДА_VW_DB_PASSWORD@netrunner-db:5432/vaultwarden
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверить, что pgloader завершился без ошибок ("... rows" summary без Errors)
|
||||||
|
— если есть ошибки по конкретным таблицам, здесь и надо разбираться, ДО того
|
||||||
|
как запускать vaultwarden поверх.
|
||||||
|
|
||||||
|
## Фаза 4 — запуск и проверка
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/netrunner-data
|
||||||
|
docker compose up -d vaultwarden
|
||||||
|
docker compose logs -f vaultwarden # ждём "Rocket has launched" без ошибок БД
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем, ДО переключения DNS на новый IP:
|
||||||
|
- Зайти по прежнему домену через `/etc/hosts`-подмену (временно указать
|
||||||
|
`vault.netrunner-vpn.com` на `136.244.78.208` только на своей машине) и
|
||||||
|
залогиниться существующим аккаунтом — проверить, что все записи/сейфы на
|
||||||
|
месте, вложения открываются.
|
||||||
|
- Проверить 2FA/WebAuthn там, где он был настроен — привязан к домену, не к
|
||||||
|
IP, так что при простой смене DNS (см. ниже) ломаться не должен.
|
||||||
|
|
||||||
|
Только после успешного логина и видимых данных:
|
||||||
|
|
||||||
|
1. Переключить DNS A-запись `vault.netrunner-vpn.com` на `136.244.78.208`.
|
||||||
|
2. Подождать TTL, ещё раз проверить логин уже по-настоящему через домен.
|
||||||
|
3. Только теперь можно выключить (не обязательно сразу удалять) старый
|
||||||
|
Vaultwarden — оставить его на пару дней выключенным как холодный откат,
|
||||||
|
прежде чем сносить директорию `~/vaultwarden-data` на старом сервере.
|
||||||
|
|
||||||
|
## Если pgloader ругается на конкретную таблицу
|
||||||
|
|
||||||
|
Обычно это `twofactor`/`ciphers` из-за BLOB/бинарных полей — можно догнать их
|
||||||
|
руками через `INSERT INTO ... SELECT` в отдельном скрипте или повторным
|
||||||
|
прогоном pgloader с `--with "batch rows = 1"` для этой таблицы (медленнее, но
|
||||||
|
проще диагностировать построчно). Не обязательно решать это заранее — сначала
|
||||||
|
просто прогнать команду выше и смотреть на реальный лог ошибок.
|
||||||
Reference in New Issue
Block a user