Skip to content

План миграции VPS — Partizap

Создан: 2026-02-28 Обновлён: 2026-03-09 Цель: Перенести все сервисы с текущего VPS (185.73.215.246, Debian 12) на два новых VPS (Ubuntu 24.04 LTS).


Архитектура: два VPS

VPS 1 — ProductionVPS 2 — DevOps
Доменыpartizap.rudev.partizap.ru, gitlab.partizap.ru, youtrack.partizap.ru
СервисыPHP-FPM (prod), PostgreSQL (prod), PgBouncer, Redis (prod), Centrifugo (prod), Nuxt SSR (prod), Nginx, Symfony Messenger worker, backup systemPHP-FPM (dev), PostgreSQL (dev), Redis (dev), Centrifugo (dev), Nuxt SSR (dev), Nginx, GitLab, YouTrack, Symfony Messenger worker
Рекомендуемый конфиг2–4 vCPU, 4 GB RAM, 40–60 GB SSD4 vCPU, 12–16 GB RAM, 60–80 GB SSD
ОСUbuntu 24.04 LTSUbuntu 24.04 LTS

Сервисы и распределение по VPS

VPS 1 — Production

СервисВерсияПорт / Сокет
Nginxlatest80, 443
PHP-FPM8.3 (Ondřej Surý PPA)/run/php/php8.3-fpm-prod.sock
PostgreSQL16127.0.0.1:5432
PgBouncer1.25+127.0.0.1:6432 (transaction mode, scram-sha-256)
Redis7127.0.0.1:6379
Centrifugov5 (Docker)127.0.0.1:8002 (API), 127.0.0.1:8003 (admin)
Nuxt SSRPM2127.0.0.1:3000
Symfony Messengersystemd worker
CertbotLet's Encrypt
DockerlatestТолько для Centrifugo
Backup systemcron + bashHourly rsync+hardlinks → /var/backup/

Redis (VPS 1):

DBНазначение
0Sessions, cache, queues (prefix: prod:)
5Centrifugo engine

VPS 2 — DevOps

СервисВерсияПорт / Сокет
Nginxlatest80, 443
PHP-FPM8.3 (Ondřej Surý PPA)/run/php/php8.3-fpm-dev.sock
PostgreSQL16127.0.0.1:5432
Redis7127.0.0.1:6379
Centrifugov5 (Docker)127.0.0.1:8000 (API), 127.0.0.1:8001 (admin)
Nuxt SSRPM2127.0.0.1:3001
Symfony Messengersystemd worker
GitLabself-hosted127.0.0.1:8081 (nginx), 127.0.0.1:8088 (puma)
YouTrack2025.3 (Docker)127.0.0.1:8080→443/tcp
CertbotLet's Encrypt
DockerlatestCentrifugo + YouTrack

Redis (VPS 2):

DBНазначение
1Sessions, cache, queues (prefix: dev:)
3Rate-limit keys
4Centrifugo engine

Phase 1 — Подготовка VPS 1 (Production, Ubuntu 24.04)

bash
# 1. Базовые пакеты
apt update && apt upgrade -y
apt install -y curl wget gnupg2 lsb-release ca-certificates apt-transport-https \
  software-properties-common ufw git rsync

# 2. Swap (2 GB)
fallocate -l 2G /swapfile
chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
sysctl vm.swappiness=10
echo 'vm.swappiness=10' >> /etc/sysctl.conf

# 3. PHP 8.3 (Ondřej Surý PPA — для Ubuntu используется PPA, не Sury Debian repo)
add-apt-repository -y ppa:ondrej/php
apt update
apt install -y php8.3-fpm php8.3-cli php8.3-pgsql php8.3-redis php8.3-mbstring \
  php8.3-xml php8.3-curl php8.3-intl php8.3-zip php8.3-gd php8.3-bcmath

# 4. Composer
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# 5. PostgreSQL 16
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
  > /etc/apt/sources.list.d/pgdg.list'
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/pgdg.gpg
apt update && apt install -y postgresql-16

# 6. PgBouncer
apt install -y pgbouncer

# 7. Redis 7
apt install -y redis-server

# 8. Nginx + Certbot
apt install -y nginx certbot python3-certbot-nginx

# 9. Docker (для Centrifugo)
curl -fsSL https://get.docker.com | sh

# 10. Node.js 22 + PM2
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
npm install -g pm2

# 11. Структура каталогов
mkdir -p /var/www/partizap/production/public
mkdir -p /var/www/partizap-frontend/production
mkdir -p /var/log/partizap/production
mkdir -p /var/www/cache
mkdir -p /var/backup/{logs,staging}
chown -R www-data:www-data /var/www/partizap /var/www/partizap-frontend /var/log/partizap /var/www/cache

# 12. Пользователь serpens (для деплоя)
adduser serpens
usermod -aG sudo serpens
# Скопировать SSH-ключи: mkdir -p /home/serpens/.ssh && ...

Phase 2 — Подготовка VPS 2 (DevOps, Ubuntu 24.04)

bash
# 1–10: Те же шаги, что и для VPS 1 (базовые пакеты, swap, PHP, Composer, PG, Redis, Nginx, Docker, Node)
# PgBouncer НЕ нужен на dev

# 11. Структура каталогов (dev)
mkdir -p /var/www/partizap/development/public
mkdir -p /var/www/partizap-frontend/development
mkdir -p /var/log/partizap/development
mkdir -p /var/www/cache
chown -R www-data:www-data /var/www/partizap /var/www/partizap-frontend /var/log/partizap /var/www/cache

# 12. GitLab (self-hosted)
curl -fsSL https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | bash
apt install -y gitlab-ce
# Настроить /etc/gitlab/gitlab.rb:
#   external_url 'https://gitlab.partizap.ru'
#   puma['worker_processes'] = 2
#   puma['port'] = 8088
#   sidekiq['concurrency'] = 10
#   nginx['listen_port'] = 8081
#   nginx['listen_https'] = false
#   prometheus_monitoring['enable'] = false
#   letsencrypt['enable'] = false
gitlab-ctl reconfigure

# 13. YouTrack (Docker)
mkdir -p /opt/youtrack/{data,conf,logs,backups}
docker run -d --name youtrack \
  -p 8080:443 \
  --restart unless-stopped \
  -v /opt/youtrack/data:/opt/youtrack/data \
  -v /opt/youtrack/conf:/opt/youtrack/conf \
  -v /opt/youtrack/logs:/opt/youtrack/logs \
  -v /opt/youtrack/backups:/opt/youtrack/backups \
  jetbrains/youtrack:2025.3.104432

# 14. Пользователь serpens
adduser serpens
usermod -aG sudo serpens

Phase 3 — Экспорт со старого VPS

Выполняется на старом сервере (185.73.215.246).

bash
mkdir -p /tmp/migration-prod/configs
mkdir -p /tmp/migration-devops/configs

# ===== PROD =====

# A. PostgreSQL prod
sudo -u postgres pg_dump -Fc partizap_prod > /tmp/migration-prod/partizap_prod.dump
sudo -u postgres pg_dumpall --roles-only > /tmp/migration-prod/pg_roles.sql

# B. Redis (только prod DB 0 и 5)
redis-cli -n 0 BGSAVE
sleep 2
cp /var/lib/redis/dump.rdb /tmp/migration-prod/redis-dump.rdb

# C. Конфиги prod
cp /etc/nginx/sites-available/default           /tmp/migration-prod/configs/nginx-default
cp /etc/nginx/.htpasswd                         /tmp/migration-prod/configs/.htpasswd
cp /etc/pgbouncer/pgbouncer.ini                 /tmp/migration-prod/configs/pgbouncer.ini
cp /etc/pgbouncer/userlist.txt                  /tmp/migration-prod/configs/userlist.txt
cp /etc/php/8.3/fpm/pool.d/partizap-prod.conf   /tmp/migration-prod/configs/partizap-prod.conf
cp /etc/logrotate.d/partizap                    /tmp/migration-prod/configs/logrotate-partizap
cp /etc/systemd/system/partizap-worker-prod.service /tmp/migration-prod/configs/

# D. Код prod
tar czf /tmp/migration-prod/backend-prod.tar.gz \
  -C /var/www/partizap production
tar czf /tmp/migration-prod/frontend-prod.tar.gz \
  -C /var/www/partizap-frontend production
cp /var/www/partizap-frontend/ecosystem.config.cjs /tmp/migration-prod/configs/

# E. Let's Encrypt
tar czf /tmp/migration-prod/letsencrypt.tar.gz -C /etc letsencrypt

# F. Centrifugo prod config
tar czf /tmp/migration-prod/centrifugo-prod.tar.gz \
  -C /var/www/partizap/production deploy/centrifugo/prod

# G. Backup system
cp /usr/local/bin/backup-hourly.sh              /tmp/migration-prod/configs/
cp /etc/cron.d/backup-hourly                    /tmp/migration-prod/configs/
cp /etc/logrotate.d/backup-hourly               /tmp/migration-prod/configs/

# H. Архив prod
tar czf /tmp/migration-prod.tar.gz -C /tmp migration-prod

# ===== DEVOPS =====

# A. PostgreSQL dev
sudo -u postgres pg_dump -Fc partizap_dev > /tmp/migration-devops/partizap_dev.dump
cp /tmp/migration-prod/pg_roles.sql /tmp/migration-devops/pg_roles.sql

# B. Redis (dev DB 1, 3, 4 — отдельный дамп не критичен, кэш пересоберётся)

# C. Конфиги dev
cp /etc/php/8.3/fpm/pool.d/partizap-dev.conf    /tmp/migration-devops/configs/partizap-dev.conf
cp /etc/systemd/system/partizap-worker-dev.service /tmp/migration-devops/configs/

# D. Код dev
tar czf /tmp/migration-devops/backend-dev.tar.gz \
  -C /var/www/partizap development
tar czf /tmp/migration-devops/frontend-dev.tar.gz \
  -C /var/www/partizap-frontend development

# E. Centrifugo dev config
tar czf /tmp/migration-devops/centrifugo-dev.tar.gz \
  -C /var/www/partizap/development deploy/centrifugo/dev

# F. GitLab
tar czf /tmp/migration-devops/gitlab-config.tar.gz -C /etc/gitlab .
# GitLab backup (официальный метод):
sudo gitlab-backup create STRATEGY=copy
# Файл бэкапа: /var/opt/gitlab/backups/*_gitlab_backup.tar
cp /var/opt/gitlab/backups/*_gitlab_backup.tar /tmp/migration-devops/
# Секреты GitLab (обязательны для восстановления!)
cp /etc/gitlab/gitlab-secrets.json /tmp/migration-devops/configs/

# G. YouTrack
docker stop youtrack
tar czf /tmp/migration-devops/youtrack-data.tar.gz \
  -C / opt/youtrack/data opt/youtrack/conf opt/youtrack/logs opt/youtrack/backups
docker start youtrack

# H. Nginx конфиг (для dev + gitlab + youtrack vhosts)
cp /etc/nginx/sites-available/default           /tmp/migration-devops/configs/nginx-default
cp /etc/nginx/.htpasswd                         /tmp/migration-devops/configs/.htpasswd

# I. Архив devops
tar czf /tmp/migration-devops.tar.gz -C /tmp migration-devops

Phase 4 — Трансфер

bash
# Со старого VPS:
scp /tmp/migration-prod.tar.gz    root@PROD_VPS_IP:/tmp/
scp /tmp/migration-devops.tar.gz  root@DEVOPS_VPS_IP:/tmp/

# На каждом новом VPS:
cd /tmp && tar xzf migration-prod.tar.gz     # VPS 1
cd /tmp && tar xzf migration-devops.tar.gz   # VPS 2

Phase 5 — Восстановление на VPS 1 (Production)

bash
# --- A. PostgreSQL ---
sudo -u postgres psql < /tmp/migration-prod/pg_roles.sql
sudo -u postgres createdb partizap_prod
sudo -u postgres pg_restore -d partizap_prod /tmp/migration-prod/partizap_prod.dump

# --- B. Redis ---
# Скопировать дамп (содержит все DB, но на проде будут использоваться только 0 и 5)
systemctl stop redis-server
cp /tmp/migration-prod/redis-dump.rdb /var/lib/redis/dump.rdb
chown redis:redis /var/lib/redis/dump.rdb
systemctl start redis-server
# Очистить ненужные dev-ключи (если попали из дампа):
redis-cli -n 1 FLUSHDB
redis-cli -n 3 FLUSHDB
redis-cli -n 4 FLUSHDB

# --- C. PgBouncer ---
cp /tmp/migration-prod/configs/pgbouncer.ini /etc/pgbouncer/pgbouncer.ini
cp /tmp/migration-prod/configs/userlist.txt  /etc/pgbouncer/userlist.txt
chown postgres:postgres /etc/pgbouncer/userlist.txt
systemctl restart pgbouncer

# --- D. PHP-FPM ---
cp /tmp/migration-prod/configs/partizap-prod.conf /etc/php/8.3/fpm/pool.d/
# Удалить дефолтный pool если есть:
rm -f /etc/php/8.3/fpm/pool.d/www.conf
systemctl restart php8.3-fpm

# --- E. Код приложения ---
tar xzf /tmp/migration-prod/backend-prod.tar.gz -C /var/www/partizap/
tar xzf /tmp/migration-prod/frontend-prod.tar.gz -C /var/www/partizap-frontend/
chown -R www-data:www-data /var/www/partizap /var/www/partizap-frontend
# Установить зависимости:
cd /var/www/partizap/production && composer install --no-dev --optimize-autoloader
cd /var/www/partizap-frontend/production && npm ci

# --- F. Nginx ---
# Создать nginx конфиг для prod (только partizap.ru, без dev/gitlab/youtrack vhosts)
# Скопировать .htpasswd если нужен basic auth на проде
cp /tmp/migration-prod/configs/.htpasswd /etc/nginx/.htpasswd
# Сертификаты — выпустить новые после DNS:
# certbot --nginx -d partizap.ru -d www.partizap.ru
nginx -t && systemctl restart nginx

# --- G. Centrifugo ---
tar xzf /tmp/migration-prod/centrifugo-prod.tar.gz -C /var/www/partizap/production/
cd /var/www/partizap/production/deploy/centrifugo/prod && docker compose up -d

# --- H. Symfony Messenger worker ---
cp /tmp/migration-prod/configs/partizap-worker-prod.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable partizap-worker-prod
systemctl start partizap-worker-prod

# --- I. PM2 (Nuxt frontend) ---
cp /tmp/migration-prod/configs/ecosystem.config.cjs /var/www/partizap-frontend/
cd /var/www/partizap-frontend && pm2 start ecosystem.config.cjs --only partizap-prod
pm2 save && pm2 startup

# --- J. Logrotate ---
cp /tmp/migration-prod/configs/logrotate-partizap /etc/logrotate.d/partizap

# --- K. Backup system ---
cp /tmp/migration-prod/configs/backup-hourly.sh /usr/local/bin/backup-hourly.sh
chmod +x /usr/local/bin/backup-hourly.sh
cp /tmp/migration-prod/configs/backup-hourly /etc/cron.d/backup-hourly
cp /tmp/migration-prod/configs/backup-hourly /etc/logrotate.d/backup-hourly
mkdir -p /var/backup/{logs,staging}
# ВАЖНО: отредактировать backup-hourly.sh — убрать gitlab-config, gitlab-data,
# home-serpens (они теперь на VPS 2). Оставить только:
#   /etc/postgresql/ → postgresql/config
#   pg_dumpall → postgresql/pg_dumpall.sql
#   /var/www/ → www
#   /etc/nginx/ → nginx
#   /etc/letsencrypt/ → letsencrypt
#   /root/ → root

Phase 6 — Восстановление на VPS 2 (DevOps)

bash
# --- A. PostgreSQL ---
sudo -u postgres psql < /tmp/migration-devops/pg_roles.sql
sudo -u postgres createdb partizap_dev
sudo -u postgres pg_restore -d partizap_dev /tmp/migration-devops/partizap_dev.dump

# --- B. Redis ---
# Dev Redis — свежий старт, кэш пересоберётся при первом обращении
# Не нужно копировать дамп

# --- C. PHP-FPM ---
cp /tmp/migration-devops/configs/partizap-dev.conf /etc/php/8.3/fpm/pool.d/
rm -f /etc/php/8.3/fpm/pool.d/www.conf
systemctl restart php8.3-fpm

# --- D. Код приложения (dev) ---
tar xzf /tmp/migration-devops/backend-dev.tar.gz -C /var/www/partizap/
tar xzf /tmp/migration-devops/frontend-dev.tar.gz -C /var/www/partizap-frontend/
chown -R www-data:www-data /var/www/partizap /var/www/partizap-frontend
cd /var/www/partizap/development && composer install
cd /var/www/partizap-frontend/development && npm ci

# --- E. Centrifugo (dev) ---
tar xzf /tmp/migration-devops/centrifugo-dev.tar.gz -C /var/www/partizap/development/
cd /var/www/partizap/development/deploy/centrifugo/dev && docker compose up -d

# --- F. Symfony Messenger worker (dev) ---
cp /tmp/migration-devops/configs/partizap-worker-dev.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable partizap-worker-dev
systemctl start partizap-worker-dev

# --- G. PM2 (Nuxt dev) ---
cd /var/www/partizap-frontend && pm2 start ecosystem.config.cjs --only partizap-dev
pm2 save && pm2 startup

# --- H. GitLab ---
# Восстановить конфиг:
tar xzf /tmp/migration-devops/gitlab-config.tar.gz -C /etc/gitlab/
cp /tmp/migration-devops/configs/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json
gitlab-ctl reconfigure
# Восстановить данные:
cp /tmp/migration-devops/*_gitlab_backup.tar /var/opt/gitlab/backups/
chown git:git /var/opt/gitlab/backups/*_gitlab_backup.tar
gitlab-backup restore BACKUP=<timestamp>
# (timestamp — часть имени файла до _gitlab_backup.tar)
gitlab-ctl restart

# --- I. YouTrack ---
tar xzf /tmp/migration-devops/youtrack-data.tar.gz -C /
docker run -d --name youtrack \
  -p 8080:443 \
  --restart unless-stopped \
  -v /opt/youtrack/data:/opt/youtrack/data \
  -v /opt/youtrack/conf:/opt/youtrack/conf \
  -v /opt/youtrack/logs:/opt/youtrack/logs \
  -v /opt/youtrack/backups:/opt/youtrack/backups \
  jetbrains/youtrack:2025.3.104432

# --- J. Nginx ---
# Создать nginx конфиг с vhosts:
#   - dev.partizap.ru → PHP-FPM dev + Nuxt dev
#   - gitlab.partizap.ru → proxy_pass 127.0.0.1:8081
#   - youtrack.partizap.ru → proxy_pass 127.0.0.1:8080
cp /tmp/migration-devops/configs/.htpasswd /etc/nginx/.htpasswd
nginx -t && systemctl restart nginx

# --- K. Backup system (для DevOps VPS) ---
# Создать отдельный backup-hourly.sh с источниками:
#   /etc/gitlab/ → gitlab-config
#   /var/opt/gitlab/ → gitlab-data
#   /var/www/ → www
#   /etc/nginx/ → nginx
#   /etc/letsencrypt/ → letsencrypt
#   /home/serpens/ → home-serpens
#   pg_dumpall → postgresql/pg_dumpall.sql

Phase 7 — Пост-миграционный чеклист

VPS 1 — Production

#ЗадачаКоманда / Место
1Обновить DNS partizap.ru → IP VPS 1DNS-провайдер
2Выпустить SSL-сертификатcertbot --nginx -d partizap.ru
3Проверить .env prod (хосты БД = 127.0.0.1)/var/www/partizap/production/.env
4Не настраивать https_proxyСтарый VPS имел прокси — на новом не нужен
5Проверить health endpointcurl https://partizap.ru/api/health
6Проверить фронтендcurl https://partizap.ru
7Проверить Centrifugo WebSocketcurl http://127.0.0.1:8002/health
8Проверить Redisredis-cli ping
9Проверить PgBouncerpsql -h 127.0.0.1 -p 6432 -U partizap_prod partizap_prod -c 'SELECT 1'
10Проверить Messenger workersystemctl status partizap-worker-prod
11Проверить PM2pm2 status
12Проверить backup croncat /etc/cron.d/backup-hourly
13Подождать 1 час, проверить снэпшотls -la /var/backup/hourly.0/

VPS 2 — DevOps

#ЗадачаКоманда / Место
1Обновить DNS dev.partizap.ru → IP VPS 2DNS-провайдер
2Обновить DNS gitlab.partizap.ru → IP VPS 2DNS-провайдер
3Обновить DNS youtrack.partizap.ru → IP VPS 2DNS-провайдер
4Выпустить SSL-сертификатыcertbot --nginx -d dev.partizap.ru -d gitlab.partizap.ru
5Проверить .env dev/var/www/partizap/development/.env
6Проверить dev healthcurl --user $PARTIZAP_BASIC_AUTH_USER:$PARTIZAP_BASIC_AUTH_PASS https://dev.partizap.ru/api/health
7Проверить GitLab UIhttps://gitlab.partizap.ru
8Проверить YouTrack UIhttps://youtrack.partizap.ru
9Обновить GitLab CI: VPS_HOST → IP VPS 1 (prod deploy target)GitLab > Settings > CI/CD > Variables
10Добавить SSH-ключ VPS 2 в authorized_keys на VPS 1Для CI/CD деплоя на прод
11Добавить GITLAB_TOKEN в ~/.bashrc на VPS 2echo 'export GITLAB_TOKEN=...' >> ~/.bashrc
12Проверить git push из dev → GitLabcd /var/www/partizap/development && git remote -v
13Обновить git remote origin во всех рабочих копияхЕсли IP GitLab изменился
14Проверить Centrifugo devcurl http://127.0.0.1:8000/health
15Проверить PM2 devpm2 status

Общее

#Задача
1Обновить docs/dev-prod-infrastructure.md — новые IP, разделение на два VPS
2Обновить server/CLAUDE.md — новые адреса и пути деплоя
3Очистить архивы миграции на всех трёх серверах: rm -rf /tmp/migration-*
4Убедиться что старый VPS можно выключить (подождать 24–48 ч после переключения DNS)

Справочник: отличия Ubuntu 24.04 от Debian 12

АспектDebian 12 (старый)Ubuntu 24.04 (новый)
PHP 8.3Sury: deb [signed-by=...] https://packages.sury.org/php/PPA: add-apt-repository ppa:ondrej/php
PostgreSQL 16Одинаково: PGDG apt repoОдинаково
Redis 7apt install redis-serverОдинаково
Dockercurl -fsSL https://get.docker.com | shОдинаково
Node.jsNodeSource scriptОдинаково
GitLab CEGitLab Debian repoGitLab Ubuntu repo (автоматически через script.deb.sh)
Firewallufw (установить вручную)ufw (предустановлен)
Системный менеджерsystemdsystemd
Дефолтная оболочкаbashdash (рекомендуется: dpkg-reconfigure dash → No для bash)

Порядок переключения (минимальный даунтайм)

  1. Подготовить оба VPS (Phase 1–2)
  2. Экспортировать данные со старого VPS (Phase 3)
  3. Перенести и восстановить (Phase 4–6)
  4. Проверить всё на новых VPS по IP (без DNS)
  5. Переключить DNS (Phase 7) — TTL рекомендуется заранее снизить до 300 сек
  6. Подождать 24–48 ч, убедиться что трафик идёт на новые VPS
  7. Выключить старый VPS