Skip to Content

Odoo 18 database and filestore backups

scripts/backup/backup_odoo18_dbs.sh selects its databases and paths from /srv/pmiverse/_pmiregistry/config/pmiverse.conf. It does not contain a production database list. The default selector is the machine's short hostname. Unknown hosts and ambiguous selections fail before database access or backup writes.

Registries

PMIVERSE_DB_REGISTRY remains the six-column database/restore registry. PMIVERSE_INSTANCE_REGISTRY connects database aliases to an instance, using nine comma-separated fields:

instance_id,host,version,filestore_base,backup_root,pg_host,pg_port,pg_user,database_aliases

Instance IDs must be unique. Paths are absolute, and database aliases are separated by |. Each alias must resolve uniquely to a database with the same Odoo version. Empty PostgreSQL fields retain libpq defaults; nonempty PGHOST, PGPORT, and PGUSER environment values override registry connection settings. Use the service account's existing PostgreSQL authentication; do not store credentials in either registry.

Instance IDs, host names, and alias membership belong to /srv/pmiverse/_pmiregistry/config/pmiverse.conf. The registry's host field is the OS short hostname returned by hostname -s. PMIS_BACKUP_REMOTE_HOSTS selects SSH sources for laptop synchronization; these may be SSH configuration aliases that differ from OS hostnames. --host overrides the registry host selector; it does not initiate SSH access. An instance record supplies paths and membership, while the host list selects sources to pull.

For multiple Odoo 18 instances on one host, add distinct instance IDs and use --instance for each scheduled job. Configure separate filestore paths and PostgreSQL endpoints as needed. Instances with unique database names can share the host backup root and its latest index; the root lock requires their jobs to run sequentially. Use distinct roots for instances with overlapping database names. The flat laptop latest index requires globally unique database names; separate-root instances require separately configured synchronization runs and destinations. This producer deliberately selects only version 18 records.

Preview and invocation

scripts/backup/backup_odoo18_dbs.sh --host backup-a --dry-run
scripts/backup/backup_odoo18_dbs.sh --host backup-b --instance backup-b-18 --dry-run
scripts/backup/backup_odoo18_dbs.sh --help

--dry-run validates and prints the plan without contacting PostgreSQL, creating directories, taking locks, or running the latest updater. Config is trusted executable shell, so inspect alternate --config FILE inputs first. Run without --dry-run only as an authorized backup operation.

CLI selectors override PMIVERSE_CONF, PMIS_BACKUP_HOST, and PMIS_BACKUP_INSTANCE respectively. Nonempty BACKUP_ROOT, FILESTORE_BASE, newline-delimited PMIS_BACKUP_DATABASES, BACKUP_TIMESTAMP, and LATEST_UPDATER remain supported. Supplying the first three together without a host or instance selector supports an explicitly configured unregistered instance. Database names must be safe path components; duplicates, latest, path traversal, and option-like names are rejected. Timestamps use YYYYMMDD_HHMMSS.

Deployment-specific Odoo 18 backup launchers live in /srv/pmiverse/_pmiregistry/scripts/backup/. They delegate to this producer; see the deployment notes. The examples above use synthetic hosts and instance IDs.

Archives and paths

Each remote server continues to write under /srv/pmiverse/_pmisuite18/data/backups/:

  • <database>/<timestamp>.<database>.dump.zip contains a custom-format PostgreSQL dump at ZIP root and, when present, <database>/ filestore files.
  • latest/<database>_latest.zip is a relative symlink to the newest archive.
  • Each database retains ten conventionally named regular archives by default. Set PMIS_BACKUP_RETENTION in the active configuration to override individual databases, using actual database names rather than registry aliases:
PMIS_BACKUP_RETENTION='demo.example,30
staging.example,3'

Counts must be decimal integers from 1 through 999999999, without leading zeros. Unlisted databases keep ten; zero is rejected. Blank lines and # comment lines are ignored. Duplicate database entries and malformed rows fail before database access or backup writes, including during --dry-run. Entries for other hosts are allowed; explicit database selections use the same settings. --dry-run displays each selected database's retention count. After each successful publication, archives beyond the configured count are removed in descending modification-time order (filename breaks ties). Lowering a count takes effect on that database's next successful backup.

The canonical ZIP layout contains:

  • One timestamped custom-format PostgreSQL dump at the archive root, named <timestamp>.<db_name>.dump.
  • When the filestore exists, a <db_name>/... directory at the archive root with relative paths.

The producer validates ZIP integrity, publishes without overwriting, and uses one nonblocking lock per canonical backup root. Failures return nonzero while allowing other databases to finish; successfully published archives survive. Missing filestores produce a warning and a dump-only archive. Database and filestore reads are not a coordinated transactional snapshot.

Required tools include Bash, PostgreSQL pg_dump, zip, unzip, flock, and GNU core utilities (realpath, stat, ln, etc.). The service account needs database access, filestore read access, and write access to its backup root.

Synchronization and rollout

The installation's full-history rsync services live in /srv/pmiverse/_pmiregistry/templates/systemd/rsync/. They pull from the remote root into separate directories on the local restore server. Synthetic examples:

Remote source Local destination
backup-a:/srv/pmiverse/_pmisuite18/data/backups/ /srv/pmiverse/_pmisuite18/data/backups/backup-a/
backup-b:/srv/pmiverse/_pmisuite18/data/backups/ /srv/pmiverse/_pmisuite18/data/backups/backup-b/

Their --delete is limited to each host's local tree. The database registry's restore source names include the local host subdirectory. For a restore run directly on a remote producer, use --source to select its database directory under the unchanged remote root.

Laptop synchronization still reads backups/latest/ on each remote host and publishes a flat local latest set. Laptop restore uses the final source-directory component as the original database name.

Only the local full-history mirror paths change. Editing templates does not install them or move existing archives; remote archives need no migration:

  1. Preview each server's selection and confirm its hostname or configure PMIS_BACKUP_HOST in its service environment.
  2. Plan retention of existing local mirrors under the old backups/ and backups-main/ trees. Local history is not automatically relocated. Restore those copies with an explicit --source until local history has been migrated through a separately approved operation. Remote history remains in place and continues to use the producer's existing retention.
  3. Deploy the producer, helper, and shared config together on each server. Update the scheduled service environment if required. For multiple local instances, the backup_odoo18_dbs@.service template passes %i as the instance ID; install and schedule each instance explicitly, adapting the service account when needed.
  4. Update the local restore registry and full-history rsync services together. Pre-create local mirror destinations with appropriate ownership before starting rsync. Laptop synchronization keeps its existing remote source paths. Avoid overlapping producer jobs that share one backup root.

Standalone pmis-backup-latest uses the same instance selection by default; its --backup-root/BACKUP_ROOT overrides remain available. On a multi-instance host its service needs PMIS_BACKUP_INSTANCE or an explicit root.

No live backup, migration, synchronization, or unit installation is part of source validation. Run bash tests/test_backup_registry.sh and bash tests/test_backup_locking.sh for isolated fixture coverage.

Odoo 12 scripts and units remain legacy assets outside this workflow. See generic restore and the laptop workflow.