Odoo Backup: Automate Database and Filestore Backups

By 

Updated on

8 min read

Automated Odoo database and filestore backup workflow

An Odoo backup is only useful when it contains both parts of the installation: the PostgreSQL database and the filestore. A database dump without its matching filestore can leave documents, product images, and other attachments missing after a restore.

Odoo 19 includes a command-line database tool that creates a ZIP archive containing the database dump, filestore, and backup metadata. This guide explains how to use that tool in a shell script, schedule daily backups with cron, remove expired archives, and test the restore process.

The examples use the paths from our Odoo 19 on Ubuntu 24.04 installation guide . Adjust the Odoo user, configuration file, Python environment, and source directory if your installation uses different paths.

Quick Reference

Replace CONFIG with your Odoo configuration file and DB with the database name. On a source install, odoo-bin runs through the virtualenv Python shown in the steps below.

TaskCommand
List databasessudo -u postgres psql -l
Manual backup (database + filestore)odoo-bin db -c CONFIG dump DB out.zip
Verify an archiveunzip -t out.zip
Run the backup scriptsudo -u odoo19 /usr/local/sbin/backup-odoo
Schedule daily at 1:30 AM30 1 * * * flock -n /run/lock/odoo-backup.lock runuser -u odoo19 -- /usr/local/sbin/backup-odoo
Restore to a new databaseodoo-bin db -c CONFIG load --neutralize DB_restore out.zip

Before You Begin

You need shell access to a self-hosted Odoo server and an account with sudo privileges. The automated method in this guide is intended for an Odoo 19 source installation.

Install unzip, which the backup script uses to check each archive:

Terminal
sudo apt update
sudo apt install unzip

Find the database name if you do not already know it:

Terminal
sudo -u postgres psql -l

The database name appears in the first column. In the examples below, it is odoo19.

Create the Backup Directory

Store local Odoo backups in a directory that is not accessible to regular users:

Terminal
sudo install -d -m 750 -o odoo19 -g odoo19 /var/backups/odoo

The Odoo service account owns this directory because the backup command runs as that user. The 750 mode allows access only to the owner and group.

Local backups are the first layer of protection, not the final destination. Later in the guide, we will cover why the archives must also be copied off the Odoo server.

Test an Odoo Backup

Before creating the automation script, run one backup manually. The following command uses Odoo’s db dump tool to create a ZIP archive with the database and filestore:

Terminal
sudo -u odoo19 /opt/odoo19/odoo-venv/bin/python3 \
    /opt/odoo19/odoo/odoo-bin db \
    -c /etc/odoo19.conf \
    dump odoo19 /var/backups/odoo/odoo19-test.zip

The important arguments are:

  • db - Opens Odoo’s command-line database manager.
  • -c /etc/odoo19.conf - Loads the database connection and data directory settings from the Odoo configuration file.
  • dump odoo19 - Creates a backup of the odoo19 database.
  • /var/backups/odoo/odoo19-test.zip - Sets the output archive path.

Check that Odoo created the file:

Terminal
sudo ls -lh /var/backups/odoo/odoo19-test.zip

Test the ZIP structure before relying on it:

Terminal
sudo unzip -t /var/backups/odoo/odoo19-test.zip

A valid Odoo ZIP backup contains dump.sql, manifest.json, and a filestore/ directory when the database has a filestore. The final output line should report that no errors were detected.

Remove the test archive after verification:

Terminal
sudo rm /var/backups/odoo/odoo19-test.zip

Create the Automatic Odoo Backup Script

Create the backup script in /usr/local/sbin:

Terminal
sudo nano /usr/local/sbin/backup-odoo

Add the following script:

/usr/local/sbin/backup-odoosh
#!/usr/bin/env bash

set -Eeuo pipefail
umask 077

BACKUP_DIR="/var/backups/odoo"
DATABASE="odoo19"
ODOO_PYTHON="/opt/odoo19/odoo-venv/bin/python3"
ODOO_BIN="/opt/odoo19/odoo/odoo-bin"
ODOO_CONFIG="/etc/odoo19.conf"
RETENTION_DAYS=7

TIMESTAMP=$(date -u +%Y-%m-%d_%H-%M-%S)
BACKUP_FILE="${BACKUP_DIR}/${DATABASE}_${TIMESTAMP}.zip"
TEMP_FILE="${BACKUP_FILE}.tmp"

cleanup() {
    rm -f "$TEMP_FILE"
}
trap cleanup EXIT

"$ODOO_PYTHON" "$ODOO_BIN" db \
    -c "$ODOO_CONFIG" \
    dump "$DATABASE" "$TEMP_FILE"

test -s "$TEMP_FILE"
unzip -tq "$TEMP_FILE"
mv "$TEMP_FILE" "$BACKUP_FILE"

find "$BACKUP_DIR" \
    -type f \
    -name "${DATABASE}_*.zip" \
    -mtime "+${RETENTION_DAYS}" \
    -delete

printf 'Odoo backup created: %s\n' "$BACKUP_FILE"

Change DATABASE and the Odoo paths to match your installation. RETENTION_DAYS=7 keeps one week of local daily backups.

The script writes the backup to a temporary filename first. It checks that the file is not empty and uses unzip -tq to test the archive. Only after both checks pass does it move the file to its final name and delete expired backups. If the Odoo command fails, the script exits without rotating valid archives.

Set the script owner and permissions:

Terminal
sudo chown root:root /usr/local/sbin/backup-odoo
sudo chmod 755 /usr/local/sbin/backup-odoo

The script does not contain the Odoo master password. It reads the database connection settings from /etc/odoo19.conf and runs as the Odoo service account.

Test the complete script:

Terminal
sudo -u odoo19 /usr/local/sbin/backup-odoo

List the resulting archive:

Terminal
sudo ls -lh /var/backups/odoo

Do not schedule the script until this manual run completes successfully.

Schedule the Backup with Cron

Open the root crontab:

Terminal
sudo crontab -e

Add this entry to run the backup every day at 1:30 AM:

cron
30 1 * * * /usr/bin/flock -n /run/lock/odoo-backup.lock /usr/sbin/runuser -u odoo19 -- /usr/local/sbin/backup-odoo >> /var/log/odoo-backup.log 2>&1

The cron job uses flock to prevent two backup processes from running at the same time. This matters when a large database takes longer than expected to archive. Standard output and errors are written to /var/log/odoo-backup.log.

After the first scheduled run, inspect the log and backup directory:

Terminal
sudo tail -n 20 /var/log/odoo-backup.log
sudo ls -lh /var/backups/odoo

Copy Backups Off the Odoo Server

A local archive does not protect you if the server disk fails, the host is deleted, or an attacker removes both the application and its backups. Copy every successful backup to separate storage.

Good destinations include:

  • A backup server that pulls files from the Odoo host
  • Object storage with versioning or retention lock enabled
  • A separate server account restricted to creating new backup files

A pull-based design is preferable because the Odoo server does not hold credentials that can delete the remote copies. If you push backups with rsync , restrict the remote SSH key and account so they cannot remove or overwrite older archives.

Keep more than one retention window. For example, you can keep seven daily backups locally while the remote system retains weekly and monthly copies.

Restore and Test an Odoo Backup

Backups should be restored regularly on a test system. A successful archive check confirms that the ZIP file is readable, but only a restore confirms that Odoo can load the database and filestore.

Copy the selected archive to the test server, then stop the test Odoo service:

Terminal
sudo systemctl stop odoo19

Restore the archive under a new database name:

Terminal
sudo -u odoo19 /opt/odoo19/odoo-venv/bin/python3 \
    /opt/odoo19/odoo/odoo-bin db \
    -c /etc/odoo19.conf \
    load --neutralize odoo19_restore \
    /var/backups/odoo/odoo19_2026-06-15_01-30-00.zip

Replace the archive name with the backup you are testing. The target database must not already exist. The --neutralize option disables scheduled actions and outgoing integrations that should not run from a copied production database.

Start Odoo and open the restored database:

Terminal
sudo systemctl start odoo19

Check several records with attachments or product images. This verifies that both the PostgreSQL data and filestore were restored.

Warning
Test restores on an isolated server or database. Do not use the --force option against a production database because it allows Odoo to delete an existing target before loading the backup.

Manual Backup from the Database Manager

Odoo also provides a web database manager at:

txt
https://odoo.example.com/web/database/manager

Select the database, choose Backup, enter the master password, and keep the ZIP format so the archive includes the filestore.

This interface is suitable for an occasional manual backup on a private or development installation. Odoo recommends disabling database listing and management pages on internet-facing production systems by setting list_db = False. The command-line backup method still works with database management disabled.

Never send the master password over plain HTTP. Restrict access to the database manager at the reverse proxy or firewall when the page must remain enabled.

Troubleshooting

The backup command reports a permission error
Confirm that the command runs as the same operating-system user as Odoo and that this user can write to /var/backups/odoo. Check the directory with sudo ls -ld /var/backups/odoo.

Odoo cannot find the database
Verify the DATABASE value and the db_host, db_port, db_user, and db_password settings in /etc/odoo19.conf. List available databases with sudo -u postgres psql -l.

The ZIP archive does not contain a filestore directory
Confirm that Odoo is using the same data directory when the backup script runs. If your service uses a custom data_dir, define it in the configuration file loaded with -c.

The cron job works manually but not on schedule
Use absolute paths in the script and cron entry, then inspect /var/log/odoo-backup.log. Also confirm that the root crontab contains the entry with sudo crontab -l.

Old backups are not removed
find -mtime +7 removes files after they have passed seven complete 24-hour periods. Run the find command without -delete first if you change the filename pattern or retention period.

Conclusion

The Odoo command-line database tool creates a single archive containing the database and filestore, while the script adds validation, retention, logging, and overlap protection. Keep copies away from the Odoo server and perform scheduled restore tests, because the real measure of a backup is whether you can restore it.

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page