Skip to Content

Odoo Backup: Automate Database and Filestore Backups

June 25, 2026 by
Odoo Backup: Automate Database and Filestore Backups
DigitalMind

Automate Database and Filestore Backups


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.

 

 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:

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.

Need support at less then 50% market price 

Contact Us






Start writing here...

Odoo Backup: Automate Database and Filestore Backups
DigitalMind June 25, 2026
Share this post
Tags
Archive