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.
| Item | Contents |
|---|---|
| Full PostgreSQL dump | User 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.
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 thedist/directory with700. - 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개 보존
Before an image upgrade or major configuration change, run bash bin/backup.sh once.
Installing Automatic Backups (Recommended)
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
Recommended Operational Cycle
| Period | Task |
|---|---|
| Daily | Automatic backup (cron) — retain 14 days |
| Weekly | Copy one latest backup to another server or medium (maintain permissions) |
| Monthly | Check dist/ size and disk space |
| Quarterly | Run a DRYRUN=1 restore rehearsal — see below |
| Before upgrades | 1 manual backup |
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
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.
- Validate the archive structure (check dump and file archive presence)
- Automatically set aside the current file state as
dist/pre-restore-<date>.tar.gz - Stop the stack
- Restore the data directory → restore the database
- 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
- Install the stack on the new server with the same version (Installation or Air-gapped Installation).
- Copy
.envfrom the old server to the new one (maintain600permissions). - Copy the backup archive to
dist/on the new server (maintain600permissions). - 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 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_KEEPvalue. - 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).
Related Documents
- Installation · Air-gapped Installation
- Secrets Management — principles to keep keys out of backups
- Troubleshooting