Skip to main content

Backup and Recovery

PlantPulse Studio handles complete state through one backup script and one recovery script. All commands run from the installation directory (/opt/kopens/plantpulse-studio-docker).


What gets backed up

A single backup file (dist/backup-<date>.tar.gz) contains all of the following.

TargetContents
Full PostgreSQL dumpUser accounts · conversation history · watchers · alarm read status · skills · deployment history · audit logs
Workspace (workspaces/)Actual source code per project · chat attachments
Build artifacts (builds/)Each version of deployed apps (needed for rollback)
State directory (state/)settings.json (configuration) · audit and usage logs · custom templates · branding logos

PostgreSQL's data directory itself is excluded from the archive — it is replaced by an SQL dump.

Backup files contain sensitive data

The archive contains entire workspaces for all users, and if migrated from a previous installation, settings.json may contain leftover API keys.

  • The script creates the backup file with 600 (owner read-only) and the dist/ directory with 700.
  • Preserve these permissions when moving to external media or other servers. (Use permission-preserving options like scp -p, rsync -a, tar -p)
  • If exporting outside the organization, separate encryption is recommended.

Run backup

cd /opt/kopens/plantpulse-studio-docker
bash bin/backup.sh
▶ PostgreSQL 덤프
▶ 파일 상태 아카이브(postgres 데이터 제외 — 덤프로 대체)
-rw------- 1 root root 78M ... dist/backup-20260728-031501.tar.gz
✅ 백업 완료 (보존 14개)
  • Output: dist/backup-<YYYYMMDD-HHMMSS>.tar.gz
  • Retention policy: Only the latest 14 backups are kept; older files are deleted automatically (adjust with BACKUP_KEEP).
  • If using bundled PostgreSQL, the stack must be running to dump the database.
BACKUP_KEEP=30 bash bin/backup.sh # 이번 실행부터 30개 보존
Always do a manual backup before updates

Run bash bin/backup.sh once before image upgrades or major configuration changes.


Install a cron job to run backup daily at 03:30. Requires root privileges.

sudo bash bin/install-backup-cron.sh
[backup-cron] 설치 완료 — 스케줄: '30 3 * * *', 보존 14개, 로그: dist/backup.log

To change the time or retention count,

sudo BACKUP_CRON="0 4 * * *" BACKUP_KEEP=30 bash bin/install-backup-cron.sh

To remove it,

sudo bash bin/install-backup-cron.sh remove

Check operation status in the logs.

tail -50 /opt/kopens/plantpulse-studio-docker/dist/backup.log
ls -lh /opt/kopens/plantpulse-studio-docker/dist/backup-*.tar.gz

IntervalTask
DailyAutomatic backup (cron) — keep 14 days
WeeklyCopy the latest backup to another server or media (preserve permissions)
MonthlyCheck dist/ size and available disk space
QuarterlyDRYRUN=1 recovery drill — see below
Before upgradeOne manual backup
A backup is only a backup if you can recover from it

Even if backup files accumulate daily, you cannot know if they actually recover until you try. Run a quarterly drill. It is non-destructive, so it is safe to run during operations.


Recovery drill (non-destructive)

Checks archive structure and database reachability only; changes nothing.

DRYRUN=1 bash bin/restore.sh # 최신 백업 대상
DRYRUN=1 bash bin/restore.sh dist/backup-20260712-191858.tar.gz
▶ 아카이브 검증
ppstudio.sql 12M · files.tar.gz 66M
▶ DRYRUN — DB 도달성만 확인
✅ DB 도달 OK
✅ DRYRUN 통과 — 실제 복구는 DRYRUN 없이 실행

Run recovery

Recovery is destructive

It overwrites the current database contents and entire data directory to the backup point in time. Projects, conversations, and deployments created after recovery will be lost.

cd /opt/kopens/plantpulse-studio-docker

bash bin/restore.sh # 최신 백업으로 복구
bash bin/restore.sh dist/backup-20260712-191858.tar.gz # 특정 시점으로 복구

You must enter restore at the confirmation prompt to proceed.

⚠ 현재 DB 와 /var/lib/pp-studio 파일 상태를 이 백업으로 덮어씁니다: dist/backup-...
계속하려면 'restore' 를 입력하세요:

The script performs the following steps:

  1. Validate archive structure (confirm dump and file archive exist)
  2. Automatically backup current file state to dist/pre-restore-<date>.tar.gz
  3. Stop the stack
  4. Restore data directory → restore database
  5. Start the stack → health check

To run without a prompt inside an automation script,

FORCE=1 bash bin/restore.sh dist/backup-20260712-191858.tar.gz

Health check fails after recovery

bash bin/logs.sh # 서버 로그 확인
bash bin/status.sh

To revert, recover again from the backup created in step 2. Note that the backup contains file state only (database is not included).

bash bin/restore.sh dist/pre-restore-20260728-104233.tar.gz

Migrate to another server

  1. Install the stack on the new server with the same version (installation or air-gapped installation).
  2. Copy .env from the existing server to the new server (preserve permissions 600).
  3. Copy the backup archive to dist/ on the new server (preserve permissions 600).
  4. Run recovery.
cd /opt/kopens/plantpulse-studio-docker
DRYRUN=1 bash bin/restore.sh dist/backup-20260728-031501.tar.gz # 먼저 리허설
bash bin/restore.sh dist/backup-20260728-031501.tar.gz
If the domain changes

If the access address changes after migration, all users must log out and log back in once — login cookies are host-specific at issue time, so leaving them unchanged causes 401 errors on data requests. See Domain and reverse proxy for details.


Disk management

Backups include entire workspaces and build artifacts, so they grow as projects increase.

du -sh /opt/kopens/plantpulse-studio-docker/dist
du -sh /var/lib/pp-studio/*
df -h /var/lib/pp-studio
  • To reduce the retention count, reinstall cron with BACKUP_KEEP value.
  • Older versions of deployed apps are kept to a maximum of 10 per project by default, with excess cleaned up automatically (the currently deployed version is always retained).