Skip to content

Backup & Restore

This page covers on-premises installations.

This guide covers database backups, Docker volume management, and disaster recovery procedures.

What to Back Up

Component Default Location Contains
PostgreSQL database Docker volume sentrikat_postgres_data (or ${STORAGE_ROOT}/postgres with storage override) All application data
Application data Docker volume sentrikat_sentrikat_data (or ${STORAGE_ROOT}/data with storage override) Uploads, encryption key
Backup files ${BACKUP_DIR} (or ${STORAGE_ROOT}/backups) .sql.gz database dumps
.env file SentriKat install directory Configuration and secrets
Certificates ./certs/ directory, and ./ssl/ if you enabled HTTPS with the bundled proxy (see TLS Setup) SSL/TLS and SAML certificates
License file .env or Settings → License Your signed license key

Custom storage paths

If you use STORAGE_ROOT with docker-compose.storage.yml, your database files live at ${STORAGE_ROOT}/postgres and backups at ${STORAGE_ROOT}/backups. See Configuration, Storage Paths.

Warning

The ENCRYPTION_KEY in your .env is required to decrypt sensitive data (API keys, LDAP passwords). If you lose this key, encrypted fields cannot be recovered. Back up .env too, but keep that copy in a different place, with different access, from the database dumps: a dump stored together with its encryption key can be read by whoever gets the backup.

Application backup (built-in, portable)

SentriKat ships a built-in backup for everything you configured, independent of the database layer and portable across installs.

Create: Settings → Admin Guide, then the backup card, Download backup (super admin; included in every edition, Community too). You get a JSON file containing organizations, users (never their passwords), products, settings, SLA policies, risk exceptions and product aliases. Encrypted secrets are excluded by design.

Restore: on the target install, Settings → Admin Guide, backup card offers two modes:

  • Restore settings: settings only, nothing else touched
  • Full Restore: organizations, users, products, SLA policies, risk exceptions, aliases. Merge semantics: existing records are detected and skipped, never overwritten or deleted; product references (risk exceptions, aliases) are re-linked by product identity, so IDs may change but relationships survive. A restored local user gets a random password that nobody sees. Each one sets a new password with Forgot Password on the login page, which needs email to be configured. Running the same restore twice is a no-op.

Backup export and restore are in every edition. Scheduled backups and standard-format exports are part of Professional.

Vulnerability data is intentionally NOT in the backup. It re-syncs from the feeds (or via the offline bundle on air-gapped installs).

When to use which

Scenario Use
Move config to a fresh install / disaster recovery without DB access Application backup + Full Restore
Full-fidelity recovery of everything incl. history pg_dump (below)
Both, scheduled pg_dump nightly + application backup after config changes

Database Backup

Encrypt and restrict permissions on dumps

A database dump contains user data and configuration. Encrypt it and restrict permissions on it (for example mode 600, owned by the backup user) before it leaves the server, and keep it away from the .env file that holds the encryption key.

Manual Backup

# Create a SQL dump
docker compose exec -T sentrikat-db pg_dump -U sentrikat sentrikat > backup_$(date +%Y%m%d_%H%M%S).sql

# Compressed backup
docker compose exec -T sentrikat-db pg_dump -U sentrikat -Fc sentrikat > backup_$(date +%Y%m%d_%H%M%S).dump

Automated Daily Backups

Add a backup service to your docker-compose.yml:

services:
  backup:
    image: prodrigestivill/postgres-backup-local   # pin a specific version tag you have reviewed
    environment:
      POSTGRES_HOST: sentrikat-db
      POSTGRES_DB: sentrikat
      POSTGRES_USER: sentrikat
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      SCHEDULE: "@daily"
      BACKUP_KEEP_DAYS: 7
      BACKUP_KEEP_WEEKS: 4
      BACKUP_KEEP_MONTHS: 6
      HEALTHCHECK_PORT: 8080
    volumes:
      - ./backups:/backups
    depends_on:
      - sentrikat-db

Start the backup service:

docker compose up -d backup

Backups are stored in ./backups/ by default, with automatic rotation. If you use STORAGE_ROOT, the built-in scripts/backup_database.sh writes to ${BACKUP_DIR} (derived from ${STORAGE_ROOT}/backups by docker-entrypoint.sh).

Redirect backups to a network share

BACKUP_DIR=/mnt/nfs-backup/sentrikat

Cron-Based Backup

Alternatively, use a system cron job:

# Add to crontab (crontab -e)
0 2 * * * cd /opt/sentrikat && docker compose exec -T sentrikat-db pg_dump -U sentrikat -Fc sentrikat > /opt/sentrikat/backups/backup_$(date +\%Y\%m\%d).dump 2>&1

Tip

Use the -Fc (custom format) flag for pg_dump to enable selective restore and compression. Custom-format dumps are significantly smaller than plain SQL.

Database Restore

From SQL Dump

# Stop the application (keep database running)
docker compose stop sentrikat

# Safety copy of the CURRENT database first: the next step destroys it
docker compose exec -T sentrikat-db pg_dump -U sentrikat -Fc sentrikat > before_restore_$(date +%Y%m%d_%H%M%S).dump

# Drop and recreate the database (connect to the 'postgres' database, not to the one being dropped)
docker compose exec sentrikat-db psql -U sentrikat -d postgres -c "DROP DATABASE sentrikat;"
docker compose exec sentrikat-db psql -U sentrikat -d postgres -c "CREATE DATABASE sentrikat;"

# Restore the backup
docker compose exec -T sentrikat-db psql -U sentrikat sentrikat < backup_20240101_020000.sql

# Start the application
docker compose up -d sentrikat

From Custom-Format Dump

# Stop the application
docker compose stop sentrikat

# Safety copy of the CURRENT database first
docker compose exec -T sentrikat-db pg_dump -U sentrikat -Fc sentrikat > before_restore_$(date +%Y%m%d_%H%M%S).dump

# Restore using pg_restore
docker compose exec -T sentrikat-db pg_restore -U sentrikat -d sentrikat --clean --if-exists < backup_20240101.dump

# Start the application
docker compose up -d sentrikat

Docker Volume Backup

For a full backup including the PostgreSQL data directory:

Export Volume

# Stop all services
docker compose down

# Back up the postgres volume
docker run --rm \
  -v sentrikat_postgres_data:/data \
  -v $(pwd)/backups:/backup \
  alpine tar czf /backup/postgres_volume_$(date +%Y%m%d).tar.gz -C /data .

Restore Volume

# Ensure services are stopped
docker compose down

# Recreate and restore the volume
docker volume create sentrikat_postgres_data
docker run --rm \
  -v sentrikat_postgres_data:/data \
  -v $(pwd)/backups:/backup \
  alpine tar xzf /backup/postgres_volume_20240101.tar.gz -C /data

# Start services
docker compose up -d

Full Disaster Recovery

Follow this procedure to restore SentriKat on a new server.

Step 1: Install Prerequisites

Install Docker Engine and the Compose plugin on the new server by following Docker's own installation guide for your distribution: docs.docker.com/engine/install.

Step 2: Restore Configuration

Copy the following from your backup to the new server:

  • The SentriKat installation directory (or re-download from the Customer Portal)
  • Your .env file with all secrets and the SENTRIKAT_LICENSE key
  • Certificate files from ./certs/ and, if you enabled HTTPS with the bundled proxy, ./ssl/ and your modified nginx/nginx.conf.template

Step 3: Restore Database

# Start only the database
docker compose up -d sentrikat-db

# Wait until PostgreSQL is healthy
docker compose ps sentrikat-db

# Restore the backup
docker compose exec -T sentrikat-db psql -U sentrikat sentrikat < backup.sql

# Start all services
docker compose up -d

Step 4: Verify

# All services healthy
docker compose ps

# The app answers (200, or a redirect to login). Run it on the server itself:
# from 1.4.0-beta, port 5000 answers only there. Right after a start it takes a few seconds,
# 000 means nothing answered within a minute.
for i in $(seq 1 30); do code=$(curl -s -o /dev/null --max-time 5 -w "%{http_code}" http://127.0.0.1:5000/); [ "$code" != 000 ] && break; sleep 2; done; echo "$code"

# Check the application logs: migrations apply automatically at boot
docker compose logs sentrikat | tail -50

Step 5: Rebind License (If Needed)

If the new server generates a different Installation ID:

  1. Go to Settings → License and copy the new Installation ID
  2. Log into portal.sentrikat.com
  3. Rebind your license to the new Installation ID
  4. Update SENTRIKAT_LICENSE in your .env and restart

See Licensing & Activation for details.

Backup Verification

Regularly test your backups by restoring to a staging environment, a second copy of the stack extracted into a separate directory on a non-production host:

# In the staging copy of the install directory (own .env, own volumes)
docker compose up -d

# Restore the backup into the staging database
docker compose exec -T sentrikat-db psql -U sentrikat sentrikat < backup.sql

# Verify: services healthy and the app answers
docker compose ps
# Run it on the staging server itself: from 1.4.0-beta, port 5000 answers only there.
# Right after a start the app takes a few seconds, 000 means nothing answered within a minute.
for i in $(seq 1 30); do code=$(curl -s -o /dev/null --max-time 5 -w "%{http_code}" http://127.0.0.1:5000/); [ "$code" != 000 ] && break; sleep 2; done; echo "$code"

Warning

Never test restores against your production database. Always use an isolated environment.

Backup Checklist

  • Database backups run daily
  • Backup retention policy covers at least 30 days
  • .env file is backed up securely (contains secrets), separately from the database dumps
  • Dumps are encrypted and their permissions restricted
  • Certificates are included in backups
  • Restore procedure tested at least quarterly
  • Backups stored off-server (network share, cloud storage, or tape)

Next Steps