Если нужно перенести только обновленные статьи и сохранить пользователей сервера, перейдите к разделу «Обновить только документацию и сохранить пользователей сервера» ниже. Полный перенос по первым шагам этой статьи заменяет всю БД, включая аккаунты.
Эта инструкция переносит БД и изображения из локального make dev на один VPS, где приложение уже успешно развёрнуто. Все шаги — от создания дампа на Mac до проверки сайта — приведены ниже.
Результат: на сервере появятся записи, настройки контента и аккаунты из локальной БД. Войти нужно будет с локальным логином и паролем. Серверные ключи, домены и настройки Docker останутся прежними.
Импорт заменяет данные сервера, а не объединяет две базы. Для новой пустой установки дополнительная копия сервера не обязательна. Если сервер уже содержит нужные данные, в шаге 5 есть команды их сохранения.
Перед началом
- На VPS уже успешно завершились
provisionи первыйdeploy. Снова выполнять их ради импорта не нужно. Не импортируйте дамп между ними: для первой установки control ожидает новую БД. - Dev и сервер используют одинаковую структуру БД и набор миграций. Если модель менялась после серверного релиза, сначала выпустите актуальный код обычным способом.
- Изображения хранятся в Local files. Здесь переносится их папка целиком. Для S3 эта последовательность не подходит.
example_project ниже — техническое имя проекта, production — имя серверного окружения. Замените их своими, если они отличаются. IP 203.0.113.10 также замените адресом VPS. Для другого компьютера разработки или prod-local есть отдельная инструкция.
1. На Mac: остановите приложение и найдите dev-БД
Остановите make dev через Ctrl+C в терминале, где он работает. Это нужно, чтобы приложение не меняло записи и изображения во время копирования. Остановите и свои фоновые задачи, если они пишут в эту БД.
В терминале Mac перейдите в папку сгенерированного проекта:
cd /path/to/example-project
make up
make wait-db
docker ps --format 'table {{.Names}}\t{{.Image}}'
make up запускает PostgreSQL без backend и интерфейса, а make wait-db ждёт готовности БД. Найдите контейнер PostgreSQL именно dev-проекта. Его имя понадобится в следующем блоке.
umask 077
DEV_POSTGRES=example_project-postgres-1
DEV_MEDIA="$HOME/.local/share/example_project/media"
TRANSFER_DIR="$HOME/example-transfer-$(date +%Y%m%d-%H%M%S)"
mkdir -m 700 "$TRANSFER_DIR"
Замените DEV_POSTGRES фактическим именем контейнера. DEV_MEDIA — папка изображений на Mac; если запускали backend с другим MEDIA_ROOT, укажите тот путь. TRANSFER_DIR — новая папка для двух файлов переноса, вне репозитория.
До отправки файлов работайте в этом же терминале: он хранит заданные переменные.
2. На Mac: сохраните БД и изображения
Сначала создайте дамп:
docker exec "$DEV_POSTGRES" sh -c \
'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
> "$TRANSFER_DIR/database.dump"
Команда берёт имя БД и пользователя из dev-контейнера. -Fc создаёт архив PostgreSQL для последующего pg_restore. Дамп содержит таблицы, записи и аккаунты, но не файлы изображений.
Если команда прошла без ошибки, упакуйте изображения:
COPYFILE_DISABLE=1 tar -czf "$TRANSFER_DIR/media.tar.gz" -C "$DEV_MEDIA" .
В архив попадёт содержимое медиапапки, включая подготовленные размеры. COPYFILE_DISABLE=1 исключает служебные метаданные macOS. Он соответствует именно этому дампу: до окончания обеих команд не возобновляйте запись в dev.
Если в БД никогда не было изображений, архив не нужен: дальше пропустите шаги с media.tar.gz, поиском медиапапки и изменением её привязки. Если изображения были, а папки нет, сначала найдите её или прежнюю копию — из одного дампа картинки не восстановить.
3. На Mac: отправьте файлы на VPS
Укажите пользователя и IP, с которыми обычно входите на сервер:
VPS=deploy@203.0.113.10
ssh "$VPS" 'umask 077; mkdir -p "$HOME/example-transfer"'
scp "$TRANSFER_DIR/database.dump" "$TRANSFER_DIR/media.tar.gz" \
"$VPS:example-transfer/"
Если переносите только БД, уберите "$TRANSFER_DIR/media.tar.gz" из команды scp.
Файлы окажутся в домашней папке пользователя SSH: для deploy это /home/deploy/example-transfer, для root — /root/example-transfer. Если SSH требует отдельный ключ, добавьте привычный -i /путь/к/ключу к ssh и scp.
После успешного создания и отправки копии можно снова запустить локальный make dev. Новые локальные изменения в уже созданный дамп не попадут.
4. На VPS: остановите приложение
Дальше нужен терминал VPS под root: предстоит менять владельца файлов. Подключитесь привычным способом; если вошли пользователем с sudo, выполните sudo -i. Если sudo не настроен, используйте root-доступ из панели VPS.
Посмотрите имена контейнеров:
docker ps -a --format 'table {{.Names}}\t{{.Status}}'
Укажите фактические имена backend, frontend и PostgreSQL своего окружения. Не выбирайте контейнеры другого проекта или другого окружения.
umask 077
TRANSFER_DIR=/home/deploy/example-transfer
TARGET_BACKEND=example_project-production-backend-1
TARGET_FRONTEND=example_project-production-frontend-1
TARGET_POSTGRES=example_project-production-postgres-1
TARGET_DB=app
Если отправляли файлы пользователю root, поменяйте TRANSFER_DIR на /root/example-transfer. app — БД обычной первой установки. Если ранее выполняли штатный restore, активная БД могла смениться: этот пример рассчитан на первый импорт после первого deploy, а не на такое окружение.
Остановите frontend и backend, оставив PostgreSQL запущенным:
docker stop "$TARGET_FRONTEND" "$TARGET_BACKEND"
С этого момента приложение недоступно до шага 8. Свои фоновые процессы записи тоже остановите. Все следующие серверные блоки выполняйте в этом же терминале, чтобы переменные сохранились.
5. На VPS: найдите медиапапку и при необходимости сохраните прежние данные
Путь изображений на VPS может отличаться от пути на Mac. Возьмём его из настройки уже созданного контейнера:
export BACKEND_MEDIA=$(docker inspect "$TARGET_BACKEND" \
--format '{{range .Config.Env}}{{println .}}{{end}}' \
| sed -n 's/^MEDIA_ROOT=//p')
TARGET_MEDIA=$(docker inspect "$TARGET_BACKEND" \
| jq -er --arg path "$BACKEND_MEDIA" \
'.[0].Mounts[] | select(.Destination == $path and .Type == "bind") | .Source')
test -n "$BACKEND_MEDIA" && test -d "$TARGET_MEDIA"
BACKEND_MEDIA — путь, который видит backend внутри контейнера. TARGET_MEDIA — папка файлов на VPS. Последняя команда при успехе ничего не выводит. Если путь не найден или команда завершилась ошибкой, не переходите к распаковке: проверьте имя backend-контейнера и Local-хранилище.
Если сервер пустой и его данные не нужны, сразу переходите к шагу 6. Если нужно сохранить нынешние данные, выполните перед импортом:
docker exec "$TARGET_POSTGRES" \
pg_dump -U postgres -d "$TARGET_DB" -Fc \
> "$TRANSFER_DIR/server-before.dump"
tar -czf "$TRANSFER_DIR/server-media-before.tar.gz" -C "$TARGET_MEDIA" .
Это отдельная ручная копия прежней БД и файлов. Она не требует включённого backup или S3. Выполняйте вторую команду только при наличии медиапапки; проверьте, что сохранение завершилось без ошибки.
6. На VPS: восстановите БД и файлы
Сначала восстановите БД:
docker exec -i "$TARGET_POSTGRES" \
pg_restore -U postgres -d "$TARGET_DB" \
--clean --if-exists --no-owner --no-privileges --single-transaction \
< "$TRANSFER_DIR/database.dump"
--clean --if-exists заменяет существующие объекты, которые содержатся в дампе. Это не слияние записей: таблицы приложения и их данные будут восстановлены из dev. --no-owner --no-privileges не переносит локальные назначения владельцев и прав. --single-transaction отменит изменения БД при ошибке восстановления.
Дождитесь успешного завершения. Если возникла ошибка, не продолжайте импорт; сохраните её текст. Если всё прошло, распакуйте изображения:
tar -xzf "$TRANSFER_DIR/media.tar.gz" -C "$TARGET_MEDIA"
chown -R 10001:10001 "$TARGET_MEDIA"
Первая команда восстанавливает файлы. Вторая передаёт их пользователю backend в контейнере, чтобы он мог читать изображения и сохранять новые. Архив распаковывается прямо в медиапапку: дополнительную вложенную папку media создавать не нужно. Старые лишние файлы на диске не удаляются, но записей о них в импортированной БД не появится.
7. На VPS: привяжите изображения к новому пути
В импортированной БД пока записан путь хранилища с Mac. Если просто включить backend, он может остановиться с media storage cannot change while assets exist.
Следующий блок обновляет привязку на путь серверного backend. Он нужен после копирования файлов, а не вместо него. На VPS должен быть установлен Python 3 (он входит в подготовку сервера). Скопируйте блок целиком; значения вручную вычислять не надо:
MEDIA_ID=$(python3 - <<'PYTHON'
import hashlib, os, posixpath
root = os.environ['BACKEND_MEDIA']
assert root.startswith('/') and root != '/', 'Проверьте BACKEND_MEDIA'
print(hashlib.sha256(b'local\0' + posixpath.normpath(root).encode() + b'\0').hexdigest())
PYTHON
)
docker exec -i "$TARGET_POSTGRES" \
psql -U postgres -d "$TARGET_DB" \
-v ON_ERROR_STOP=1 -v media_id="$MEDIA_ID" <<'SQL'
BEGIN;
SELECT pg_advisory_xact_lock(731947120);
INSERT INTO admingen_media.store_identity (singleton, identity)
VALUES (true, :'media_id')
ON CONFLICT (singleton) DO UPDATE SET identity = EXCLUDED.identity;
COMMIT;
SQL
Блок рассчитан на обычное Local-хранилище сгенерированного deployment, без символических ссылок в пути. Если изображений никогда не было и архив не переносили, пропустите этот шаг.
8. На VPS: запустите приложение и проверьте результат
docker start "$TARGET_BACKEND"
docker logs --tail 50 "$TARGET_BACKEND"
docker exec "$TARGET_BACKEND" migrate --verify
Проверьте, что backend не завершился с ошибкой, а проверка миграций прошла. Затем включите frontend:
docker start "$TARGET_FRONTEND"
Откройте https://admin.example.com, заменив домен своим. Войдите с аккаунтом из локальной БД. Аккаунт, созданный на пустом сервере до импорта, заменён данными из дампа; создавать суперадминистратора повторно не требуется.
Откройте несколько записей и изображений. Если используется отдельный сайт, проверьте, что он получает контент. Серверные ключи авторизации не переносились с Mac, поэтому в браузере может потребоваться заново войти.
Пересборка образов, provision и новый deploy для этого импорта не нужны: код уже запущенного релиза не менялся. Сохраните дамп и архив до окончания проверки.
Обновить только документацию и сохранить пользователей сервера
Полный дамп БД заменяет и контент, и аккаунты. Если на сервере уже созданы администраторы, а вам нужно перенести только статьи, не восстанавливайте весь dev-дамп.
В проекте этого сайта для такой задачи добавлены два custom-скрипта: deploy/custom/export-docs.py и deploy/custom/import-docs.sh. Это инструменты переноса документации именно данного проекта, не универсальная команда генератора. Они обновляют DocArticle и нужные DocSection по slug, добавляют новые статьи, но не удаляют серверные записи и не затрагивают пользователей, роли, изображения или остальной контент. Существующие серверные ID сохраняются; заголовок, текст, порядок и статус публикации выбранных статей берутся из локальной БД.
1. Экспортируйте статьи на своем компьютере
Из корня локального проекта системы администрирования, например ~/projects/example-project:
python3 deploy/custom/export-docs.py --output docs-update.sql
Для экспорта должны работать Docker и PostgreSQL локального dev-проекта. Скрипт обращается к его контейнеру; для другого имени можно добавить --container ИМЯ_КОНТЕЙНЕРА. Команда читает локальную dev-БД и создает SQL-файл для переноса всей документации. Она не меняет БД. Если docs-update.sql уже существует, выберите новое имя через --output: скрипт не перезаписывает готовый файл. Если нужны отдельные статьи, укажите их slug:
python3 deploy/custom/export-docs.py --output docs-update.sql \
--slugs docker-images disk-cleanup
Замените slug нужными значениями из документации. Файл содержит текст статей, а не дамп аккаунтов. Получатель импортирует его в следующем шаге.
2. Передайте файл и скрипт на VPS
С компьютера, из того же корня локального проекта:
scp docs-update.sql deploy/custom/import-docs.sh \
deploy@203.0.113.10:/home/deploy/
Замените IP и пользователя своими. Если используете отдельный SSH-ключ, добавьте -i /путь/к/ключу к scp. Скопируются SQL-файл и скрипт импорта. Для переноса текстов git pull, сборка и новый релиз не нужны. Сами custom-скрипты можно сохранить в Git для дальнейшей работы; SQL публиковать в Git не требуется.
3. Импортируйте на сервере
На VPS:
bash /home/deploy/import-docs.sh \
/home/deploy/docs-update.sql \
/srv/admingen/example_project/production
Первый аргумент — переданный SQL, второй — runtime directory окружения, а не каталог исходников. Его значение смотрите в профиле Deployment. Выполняйте от пользователя с доступом к Docker и файлам этого окружения.
Импорт обновляет только документацию одной транзакцией. Если возникает ошибка, изменения транзакции не сохраняются. Пересборка, новый релиз и перезапуск контейнеров для текстов не нужны. Откройте статью на сайте; если для API включен кэш, дождитесь TTL, например до 30 секунд при таком значении в настройках. Серверные аккаунты администраторов останутся на месте.