Skip to main content

Backup and Recovery

PlantPulse Studio handles the full state with one backup script and one restore script. Run all commands 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.

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

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

Backup files are sensitive material

The archive contains entire workspaces of all users, and if you migrated from a previous installation, settings.json may still hold API keys.

  • The script creates the backup file with 600(owner-only read), and the dist/ directory with 700.
  • Maintain these permissions even when copying to external media or another server. (Use permission-preserving options like scp -p, rsync -a, tar -p.)
  • If you take it off-site, we recommend additional encryption.

Running a 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 are kept; older files are deleted automatically (adjustable via BACKUP_KEEP).
  • You must be able to reach the external PostgreSQL to take a dump.
BACKUP_KEEP=30 bash bin/backup.sh # 이번 실행부터 30개 보존
Always run a manual backup before an update

Before an image upgrade or major configuration change, run bash bin/backup.sh once.


Installs a cron job to run backups daily at 03:30. Root privileges are required.

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,

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

Check operation via logs.

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

PeriodTask
DailyAutomatic backup (cron) — retain 14 days
WeeklyCopy one latest backup to another server or medium (maintain permissions)
MonthlyCheck dist/ size and disk space
QuarterlyRun a DRYRUN=1 restore rehearsal — see below
Before upgrades1 manual backup
A backup is only a backup once you've verified it restores

Even if backup files are accumulating daily, you can't know whether they actually restore until you try. Run a rehearsal every quarter. It is non-destructive, so it is safe to run during production.


Restore Rehearsal (Non-destructive)​

Checks only the archive structure and database reachability; it 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 없이 실행

Running a Restore​

Restore is destructive

It overwrites the current database contents and the entire data directory with the state at backup time. Projects, conversations, and deployments created after the backup 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 the archive structure (check dump and file archive presence)
  2. Automatically set aside the current file state as dist/pre-restore-<date>.tar.gz
  3. Stop the stack
  4. Restore the data directory → restore the database
  5. Start the stack → check health

To run without a prompt from within an automation script,

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

If Health Doesn't Come Up Right After a Restore​

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

To roll back, restore again from the set-aside copy created in step 2. Note that the set-aside copy only contains the file state (it does not include the database).

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

Migrating 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 old server to the new one (maintain 600 permissions).
  3. Copy the backup archive to dist/ on the new server (maintain 600 permissions).
  4. Run the restore.
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, every user must log out and log in again — the login cookie is host-specific at issuance time, so if left as-is, data requests will return 401. For details, see Domains and Reverse Proxy.


Disk Management​

Because backups contain the entire workspace and build artifacts, 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 the BACKUP_KEEP value.
  • For past versions of deployed apps, up to 10 are kept per project by default; excess is automatically cleaned up (the currently served version is always retained).