For AI agents: a documentation index is available at /llms.txt. A markdown version of this page is available at /guide/community/operate/backup-and-restore.md.

CommunityOperate

Backup and restore

What to back up, how to automate it, and how to prove a restore actually works.

A Community install holds two things you cannot regenerate: the PostgreSQL database and the attachment files. Back up both, or your restore will be half a system.

An untested backup is not a backup

Restore into a scratch instance at least once. Most backup failures are discovered during the first real restore, which is the worst time.

#What to back up

ItemDocker locationManual location
Databaseorangescrum-postgres-data volumeYour PostgreSQL data directory
Attachmentsorangescrum-app-files volumewebroot/files
Configurationorangescrum-app-config volumeconfig/

The config volume is small but holds the generated database configuration โ€” including it saves a fiddly manual step on restore.

#Backing up (Docker)

bash
#!/usr/bin/env bash
set -euo pipefail

STAMP=$(date +%F-%H%M)
DEST=/backups/orangescrum
mkdir -p "$DEST"

# Database โ€” custom format compresses and restores selectively.
docker compose exec -T orangescrum-postgres \
  pg_dump -U orangescrum -Fc orangescrum > "$DEST/db-$STAMP.dump"

# Attachments.
docker run --rm \
  -v orangescrum_orangescrum-app-files:/files:ro \
  -v "$DEST":/backup alpine \
  tar czf "/backup/files-$STAMP.tar.gz" -C /files .

# Configuration.
docker run --rm \
  -v orangescrum_orangescrum-app-config:/config:ro \
  -v "$DEST":/backup alpine \
  tar czf "/backup/config-$STAMP.tar.gz" -C /config .

# Keep 30 days.
find "$DEST" -type f -mtime +30 -delete

Check your volume prefix

Compose prefixes volume names with the project name โ€” orangescrum-oss in the shipped file. Confirm with docker volume ls and adjust the script.

Schedule it nightly:

lua
0 2 * * * /usr/local/bin/orangescrum-backup.sh >> /var/log/orangescrum-backup.log 2>&1

#Backing up (manual install)

bash
pg_dump -U orangescrum -Fc orangescrum > db-$(date +%F).dump
tar czf files-$(date +%F).tar.gz -C /var/www/orangescrum/webroot files
tar czf config-$(date +%F).tar.gz -C /var/www/orangescrum config

#Restoring

  1. Stop the application

    bash
    docker compose stop orangescrum-app
    

    Restoring underneath a running app produces inconsistent state.

  2. Restore the database

    bash
    docker compose exec -T orangescrum-postgres \
      dropdb -U orangescrum --if-exists orangescrum
    
    docker compose exec -T orangescrum-postgres \
      createdb -U orangescrum orangescrum
    
    docker compose exec -T orangescrum-postgres \
      pg_restore -U orangescrum -d orangescrum < /backups/orangescrum/db-2026-08-01-0200.dump
    
  3. Restore attachments

    bash
    docker run --rm \
      -v orangescrum_orangescrum-app-files:/files \
      -v /backups/orangescrum:/backup alpine \
      sh -c "rm -rf /files/* && tar xzf /backup/files-2026-08-01-0200.tar.gz -C /files"
    
  4. Start and clear caches

    bash
    docker compose start orangescrum-app
    docker compose exec orangescrum-app php bin/cake.php cache clear_all
    
  5. Verify

    Sign in, open a project, open a task with an attachment, and download it. A database-only restore looks fine until someone clicks a file.

#Testing the restore

Quarterly, restore into a throwaway instance on a different port:

bash
docker compose -p orangescrum-test up -d

Then run the restore against that project name. It costs an hour and tells you whether your backups are real.

#What to watch

๐Ÿ“ˆBackup size

A sudden drop usually means the dump failed and wrote a near-empty file. Alert on it.

๐Ÿ’พAttachment volume growth

This is what fills the disk. Track it before it stops the app.

โ˜๏ธOff-machine copies

A backup on the same host does not survive losing the host.

๐Ÿ”Encryption

Dumps contain everything. Encrypt them at rest.

๐Ÿ”งTroubleshooting

Common failures and how to read the logs.