← Documentation

This walkthrough uses the standard directory layout generated by ocms init my-site: a binary beside my-site, with .env, data/ocms.db, uploads and custom inside the site. The commands are tested with oCMS v0.30.0 in Bash and Zsh. You need the SQLite command-line tool, tar, and either sha256sum or shasum.

If your configuration uses external data, upload or theme paths, include those actual files too. Use a test machine matching the backed-up binary's operating system and architecture.

Jump to preparation, backup, verification, restore, or the rehearsal.

1. Stop writes and choose a new backup directory

Stop the oCMS process for this site before taking the complete backup. For the local quick start, press Ctrl+C in its terminal; on a server use your service manager. Keep it stopped until the database and site files are captured, so uploads and database references belong to the same point in time.

Run these snippets in the same Bash or Zsh session from the directory containing ocms and my-site. Adjust the two source paths to your installation. The backup directory must be new.

set -euo pipefail
umask 077
SITE_DIR="$(pwd)/my-site"
OCMS_BINARY="$(pwd)/ocms"
BACKUP_DIR="$(pwd)/backups/ocms-$(date -u +%Y%m%dT%H%M%SZ)"
test -f "$SITE_DIR/.env"
test -f "$SITE_DIR/data/ocms.db"
test -d "$SITE_DIR/uploads"
test -d "$SITE_DIR/custom"
test -x "$OCMS_BINARY"
mkdir -p "$(dirname "$BACKUP_DIR")"
mkdir "$BACKUP_DIR"

2. Capture the database, site files and binary

SQLite's .backup command creates a consistent database file, including committed data that may be in the write-ahead log. Keep the matching binary as well: a restore should first run the version that created the backup, including any compiled custom modules.

(
  cd "$BACKUP_DIR"
  sqlite3 "$SITE_DIR/data/ocms.db" '.backup ocms.db'
  test "$(sqlite3 ocms.db 'PRAGMA integrity_check;')" = ok
  tar -czf site-files.tar.gz -C "$SITE_DIR" .env custom uploads
  cp -p "$OCMS_BINARY" ./ocms
  ./ocms -version > version.txt
)

The archive includes the original OCMS_SESSION_SECRET and OCMS_MFA_KEY in .env. Preserve their values; generating replacements during a restore invalidates sessions or prevents existing MFA secrets from being decrypted. Treat the database and configuration archive as private credentials.

3. Check the archive and record checksums

(
  cd "$BACKUP_DIR"
  tar -tzf site-files.tar.gz
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum ocms.db site-files.tar.gz ocms version.txt > SHA256SUMS
  else
    shasum -a 256 ocms.db site-files.tar.gz ocms version.txt > SHA256SUMS
  fi
)

Check that the listing contains your configuration, custom themes and expected uploaded files. The original site can now be restarted. Keep another protected copy off this machine; checksums detect later changes but do not replace a trusted backup destination.

4. Restore into a separate, empty directory

Verify the backup before using it. Leave the original site and the backup untouched.

(
  cd "$BACKUP_DIR"
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum -c SHA256SUMS
  else
    shasum -a 256 -c SHA256SUMS
  fi
)
RESTORE_ROOT="$(pwd)/restore-test"
mkdir "$RESTORE_ROOT"
cp -p "$BACKUP_DIR/ocms" "$RESTORE_ROOT/ocms"
mkdir "$RESTORE_ROOT/my-site"
tar -xzf "$BACKUP_DIR/site-files.tar.gz" -C "$RESTORE_ROOT/my-site"
mkdir "$RESTORE_ROOT/my-site/data"
cp "$BACKUP_DIR/ocms.db" "$RESTORE_ROOT/my-site/data/ocms.db"
test "$(sqlite3 "$RESTORE_ROOT/my-site/data/ocms.db" 'PRAGMA integrity_check;')" = ok

mkdir deliberately fails if restore-test already exists. Choose a fresh destination for another rehearsal. Do not copy a database over a running site's SQLite files or mix it with that site's old WAL/SHM files.

5. Start and inspect the restored copy

For a real production backup, use an isolated test machine or container with outbound network access blocked: a copied database and configuration can contain active integrations or scheduled jobs. Bind the rehearsal to loopback on a separate port. The original session and MFA keys stay in the copied configuration.

cd "$RESTORE_ROOT/my-site"
OCMS_ENV=development \
OCMS_SERVER_HOST=127.0.0.1 \
OCMS_SERVER_PORT=8087 \
OCMS_SITE_URL=http://localhost:8087 \
OCMS_DO_SEED=false \
../ocms serve

In another terminal, check health:

curl --fail --silent --show-error http://localhost:8087/health

Open the restored homepage and admin panel. Check a known page, an uploaded image and the active custom theme. Sign in normally and verify MFA if the source site uses it. Stop this test process with Ctrl+C when finished.

Before restoring production

Complete the rehearsal first. Stop the affected production site, restore the verified set into a clean destination, apply the correct service-user ownership and permissions, and use the matching binary before any upgrade. Keep the previous site directory available until the restored service passes health and content checks.

See the SQLite CLI reference, deployment guide, and release upgrade requirements. The theme gallery explains bundled-theme activation.