Skip to main content
Technical Guide

Odoo Backup and Recovery: Complete Guide

Master Odoo backup and restore procedures. Learn pg_dump commands, automated backup scripts, off-site storage integration, and disaster recovery planning to protect your business data.

15-20 min read
Updated December 2024
PostgreSQL + Filestore

Why Backups Matter for Odoo

Your Odoo database contains everything critical to your business: customer data, financial records, inventory, sales history, and operational configurations. A robust backup strategy is not optional - it is essential for business continuity. Whether you're running Odoo in Docker or a native installation, proper backups protect against data loss.

Hardware Failure

Disk failures, server crashes, and infrastructure issues can happen without warning. Backups ensure data survives hardware disasters.

Security Threats

Ransomware attacks and data breaches are increasingly common. Off-site backups provide recovery options when systems are compromised.

Human Error

Accidental deletions, failed updates, or configuration mistakes happen. Backups allow you to roll back to a known good state.

Data Loss Statistics

According to industry research, 60% of companies that lose their data shut down within 6 months. Regular, tested backups are your insurance policy against catastrophic data loss.

Types of Odoo Backups

A complete Odoo backup consists of two components: the PostgreSQL database and the filestore. Understanding backup types helps you choose the right strategy for your needs.

Full Database Dump (pg_dump)

The most common backup method. Creates a complete snapshot of your PostgreSQL database including all tables, data, and schema.

Advantages

  • Simple to create and restore
  • Consistent point-in-time snapshot
  • Portable across servers

Best For

  • - Daily scheduled backups
  • - Migration between servers
  • - Creating staging environments

Incremental Backups (WAL Archiving)

PostgreSQL Write-Ahead Logging captures every change since the last backup. Enables point-in-time recovery to any moment.

Advantages

  • Minimal data loss (seconds, not hours)
  • Smaller backup files
  • Point-in-time recovery

Best For

  • - High-transaction environments
  • - Strict RPO requirements
  • - Large databases

Filestore Backup

The filestore contains all attachments, uploaded documents, product images, and session data. It must be backed up alongside the database.

Location

  • /opt/odoo/.local/share/Odoo/filestore/
  • Docker: /var/lib/odoo/filestore/

Backup Methods

  • - rsync for incremental file sync
  • - tar/gzip for compressed archives
  • - Cloud sync tools (rclone)

Manual Backup Guide

Learn the essential commands for creating manual Odoo backups. These commands work for both native installations and Docker deployments.

Native Installation Backup

database_backup.shbash
# Set variables
DB_NAME="odoo_production"
BACKUP_DIR="/opt/odoo/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database with pg_dump (compressed)
sudo -u postgres pg_dump -Fc $DB_NAME > $BACKUP_DIR/db_$DATE.dump

# Alternative: SQL format (larger but human-readable)
sudo -u postgres pg_dump $DB_NAME | gzip > $BACKUP_DIR/db_$DATE.sql.gz

# Verify backup was created
ls -lh $BACKUP_DIR/db_$DATE.*

Backup Filestore

filestore_backup.shbash
# Set variables
DB_NAME="odoo_production"
FILESTORE_DIR="/opt/odoo/.local/share/Odoo/filestore/$DB_NAME"
BACKUP_DIR="/opt/odoo/backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)

# Create compressed archive of filestore
tar -czf $BACKUP_DIR/filestore_$DATE.tar.gz -C $FILESTORE_DIR .

# Alternative: rsync for incremental backup
rsync -avz --delete $FILESTORE_DIR/ $BACKUP_DIR/filestore_latest/

# Verify backup
ls -lh $BACKUP_DIR/filestore_$DATE.tar.gz

Docker Installation Backup

docker_backup.shbash
# Set variables
DB_CONTAINER="odoo-db"
ODOO_CONTAINER="odoo"
DB_USER="odoo"
BACKUP_DIR="./backups"
DATE=$(date +%Y-%m-%d_%H-%M-%S)

# Create backup directory
mkdir -p $BACKUP_DIR

# Backup database from Docker container
docker exec $DB_CONTAINER pg_dump -U $DB_USER -Fc postgres \
  > $BACKUP_DIR/db_$DATE.dump

# Alternative: compressed SQL format
docker exec $DB_CONTAINER pg_dumpall -U $DB_USER | gzip \
  > $BACKUP_DIR/db_$DATE.sql.gz

# Backup filestore from Docker volume
docker run --rm \
  -v odoo-docker_odoo-data:/data:ro \
  -v $(pwd)/$BACKUP_DIR:/backup \
  alpine tar czf /backup/filestore_$DATE.tar.gz -C /data/filestore .

# List backups
ls -lh $BACKUP_DIR/

pg_dump Format Options

  • -Fc (custom format): Compressed, allows selective restore, recommended for most cases
  • -Fp (plain SQL): Human-readable, larger files, useful for debugging
  • -Fd (directory): Parallel dump/restore, best for very large databases

Automated Backup Strategy

Manual backups are prone to being forgotten. Set up automated backups with cron jobs and scripts to ensure consistent protection.

Complete Backup Script

/opt/odoo/scripts/backup.shbash
#!/bin/bash
#
# Odoo Automated Backup Script
# Run via cron: 0 2 * * * /opt/odoo/scripts/backup.sh
#

set -e

# Configuration
DB_NAME="odoo_production"
DB_USER="odoo"
FILESTORE_DIR="/opt/odoo/.local/share/Odoo/filestore/$DB_NAME"
BACKUP_DIR="/opt/odoo/backups"
LOG_FILE="/var/log/odoo/backup.log"
RETENTION_DAYS=30
DATE=$(date +%Y-%m-%d_%H-%M-%S)

# Logging function
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

# Create backup directory
mkdir -p $BACKUP_DIR

log "Starting backup for database: $DB_NAME"

# Backup database
log "Backing up PostgreSQL database..."
sudo -u postgres pg_dump -Fc $DB_NAME > $BACKUP_DIR/db_$DATE.dump
if [ $? -eq 0 ]; then
    log "Database backup successful: db_$DATE.dump"
else
    log "ERROR: Database backup failed!"
    exit 1
fi

# Backup filestore
log "Backing up filestore..."
tar -czf $BACKUP_DIR/filestore_$DATE.tar.gz -C $FILESTORE_DIR .
if [ $? -eq 0 ]; then
    log "Filestore backup successful: filestore_$DATE.tar.gz"
else
    log "ERROR: Filestore backup failed!"
    exit 1
fi

# Create combined backup archive
log "Creating combined backup archive..."
tar -cf $BACKUP_DIR/full_backup_$DATE.tar \
    -C $BACKUP_DIR db_$DATE.dump filestore_$DATE.tar.gz
gzip $BACKUP_DIR/full_backup_$DATE.tar

# Clean up individual files
rm $BACKUP_DIR/db_$DATE.dump
rm $BACKUP_DIR/filestore_$DATE.tar.gz

# Calculate backup size
BACKUP_SIZE=$(ls -lh $BACKUP_DIR/full_backup_$DATE.tar.gz | awk '{print $5}')
log "Combined backup created: full_backup_$DATE.tar.gz ($BACKUP_SIZE)"

# Remove old backups
log "Removing backups older than $RETENTION_DAYS days..."
DELETED=$(find $BACKUP_DIR -name "full_backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete -print | wc -l)
log "Deleted $DELETED old backup(s)"

# Verify backup integrity
log "Verifying backup integrity..."
gzip -t $BACKUP_DIR/full_backup_$DATE.tar.gz
if [ $? -eq 0 ]; then
    log "Backup integrity verified"
else
    log "ERROR: Backup integrity check failed!"
    exit 1
fi

log "Backup completed successfully"
exit 0

Schedule with Cron

# Make script executable
sudo chmod +x /opt/odoo/scripts/backup.sh

# Edit crontab
sudo crontab -e

# Add these entries:
# Daily backup at 2 AM
0 2 * * * /opt/odoo/scripts/backup.sh

# Weekly full backup on Sunday at 3 AM
0 3 * * 0 /opt/odoo/scripts/backup.sh --full

# Verify cron is scheduled
sudo crontab -l

Docker Compose with Backup Service

docker-compose.ymlyaml
version: '3.8'

services:
  odoo:
    image: odoo:17.0
    # ... other config ...

  db:
    image: postgres:15
    # ... other config ...

  backup:
    image: postgres:15
    volumes:
      - ./backups:/backups
      - ./scripts:/scripts:ro
    environment:
      - PGHOST=db
      - PGUSER=odoo
      - PGPASSWORD=${POSTGRES_PASSWORD}
    entrypoint: /bin/sh
    command: >
      -c "while true; do
        sleep 86400;
        pg_dump -Fc postgres > /backups/db_$$(date +%Y%m%d).dump;
        find /backups -name '*.dump' -mtime +30 -delete;
      done"
    depends_on:
      - db
    networks:
      - odoo-network

Off-site Backup Storage

Local backups protect against accidental deletion, but off-site storage is essential for disaster recovery. Store backups in a different geographic location using cloud storage providers. For detailed AWS S3 integration, see our complete S3 backup guide.

AWS S3 Integration

s3_upload.shbash
#!/bin/bash
# AWS S3 backup upload script

# Configuration
S3_BUCKET="s3://your-company-odoo-backups"
BACKUP_DIR="/opt/odoo/backups"
AWS_PROFILE="odoo-backup"

# Upload latest backup to S3
LATEST_BACKUP=$(ls -t $BACKUP_DIR/full_backup_*.tar.gz | head -1)

if [ -n "$LATEST_BACKUP" ]; then
    echo "Uploading $LATEST_BACKUP to S3..."
    aws s3 cp $LATEST_BACKUP $S3_BUCKET/ --profile $AWS_PROFILE

    # Verify upload
    aws s3 ls $S3_BUCKET/$(basename $LATEST_BACKUP) --profile $AWS_PROFILE

    echo "Upload complete"
else
    echo "No backup file found"
    exit 1
fi

# Apply S3 lifecycle policy for retention
# (Configure in AWS Console or via aws cli)

Cloudflare R2 Integration

r2_upload.shbash
#!/bin/bash
# Cloudflare R2 backup upload using rclone

# First, configure rclone:
# rclone config
# - Name: r2
# - Type: s3
# - Provider: Cloudflare
# - Access Key ID: (from R2 dashboard)
# - Secret Access Key: (from R2 dashboard)
# - Endpoint: https://<account-id>.r2.cloudflarestorage.com

BACKUP_DIR="/opt/odoo/backups"
R2_BUCKET="r2:odoo-backups"

# Upload latest backup
LATEST_BACKUP=$(ls -t $BACKUP_DIR/full_backup_*.tar.gz | head -1)

if [ -n "$LATEST_BACKUP" ]; then
    echo "Uploading to Cloudflare R2..."
    rclone copy $LATEST_BACKUP $R2_BUCKET/ --progress

    # List remote backups
    rclone ls $R2_BUCKET/

    # Clean up old remote backups (keep 30 days)
    rclone delete $R2_BUCKET/ --min-age 30d
fi

Backblaze B2 Integration

b2_upload.shbash
#!/bin/bash
# Backblaze B2 backup upload

# Install B2 CLI: pip install b2
# Authorize: b2 authorize-account <applicationKeyId> <applicationKey>

BACKUP_DIR="/opt/odoo/backups"
B2_BUCKET="odoo-backups"

# Upload latest backup
LATEST_BACKUP=$(ls -t $BACKUP_DIR/full_backup_*.tar.gz | head -1)

if [ -n "$LATEST_BACKUP" ]; then
    echo "Uploading to Backblaze B2..."
    b2 upload-file $B2_BUCKET $LATEST_BACKUP backups/$(basename $LATEST_BACKUP)

    # List files in bucket
    b2 ls $B2_BUCKET/backups/
fi

# B2 Lifecycle rules can be configured in the web console
# to automatically delete old backups

AWS S3

Industry standard, global availability, Glacier for archives

Cloudflare R2

Zero egress fees, S3-compatible API, great for frequent restores

Backblaze B2

Lowest cost per GB, simple pricing, good for large backups

Encrypt Your Backups

Always encrypt backups before uploading to cloud storage. Your Odoo database contains sensitive business data. Use GPG or openssl to encrypt backup files before transfer.
# Encrypt backup before upload
gpg --symmetric --cipher-algo AES256 full_backup_2024-01-15.tar.gz

# Decrypt when needed
gpg --decrypt full_backup_2024-01-15.tar.gz.gpg > full_backup_2024-01-15.tar.gz

Restore Process

A backup is only valuable if you can restore it. Follow this step-by-step guide to restore your Odoo database and filestore.

Test Restores Regularly

Do not wait for a disaster to test your restore procedure. Schedule monthly test restores to a staging environment to verify your backups work correctly.

Step 1: Stop Odoo Service

# Native installation
sudo systemctl stop odoo

# Docker installation
docker compose stop odoo

# Verify Odoo is stopped
sudo systemctl status odoo  # or docker compose ps

Step 2: Prepare Database

# Drop existing database (CAREFUL - this deletes all data!)
sudo -u postgres dropdb odoo_production

# Create fresh database
sudo -u postgres createdb -O odoo odoo_production

# For Docker:
docker exec odoo-db dropdb -U odoo postgres
docker exec odoo-db createdb -U odoo -O odoo postgres

Step 3: Restore Database

restore_database.shbash
# Extract combined backup first
tar -xzf full_backup_2024-01-15.tar.gz

# Restore from custom format (.dump)
sudo -u postgres pg_restore -d odoo_production db_2024-01-15.dump

# OR restore from SQL format (.sql.gz)
gunzip -c db_2024-01-15.sql.gz | sudo -u postgres psql odoo_production

# For Docker:
cat db_2024-01-15.dump | docker exec -i odoo-db pg_restore -U odoo -d postgres

# Verify restore
sudo -u postgres psql -d odoo_production -c "SELECT COUNT(*) FROM res_users;"

Step 4: Restore Filestore

restore_filestore.shbash
# Set variables
DB_NAME="odoo_production"
FILESTORE_DIR="/opt/odoo/.local/share/Odoo/filestore/$DB_NAME"

# Clear existing filestore (optional, for clean restore)
rm -rf $FILESTORE_DIR/*

# Extract filestore backup
tar -xzf filestore_2024-01-15.tar.gz -C $FILESTORE_DIR

# Fix ownership and permissions
sudo chown -R odoo:odoo $FILESTORE_DIR
sudo chmod -R 755 $FILESTORE_DIR

# For Docker:
docker run --rm \
  -v odoo-docker_odoo-data:/data \
  -v $(pwd):/backup:ro \
  alpine sh -c "rm -rf /data/filestore/* && tar xzf /backup/filestore_2024-01-15.tar.gz -C /data/filestore"

Step 5: Start and Verify

# Start Odoo
sudo systemctl start odoo

# Or for Docker
docker compose up -d odoo

# Check logs for errors
sudo tail -f /var/log/odoo/odoo.log

# Verify service is running
sudo systemctl status odoo

# Test access via browser
curl -I https://your-domain.com/web/login

Restore Checklist

  • - Database restored and accessible
  • - All users can log in
  • - Attachments and documents are visible
  • - Recent transactions are present
  • - Custom modules are working

Disaster Recovery Planning

A disaster recovery plan goes beyond backups. It defines how your organization will respond to and recover from major incidents.

Understanding RTO and RPO

RPO - Recovery Point Objective

Maximum acceptable amount of data loss measured in time. If your RPO is 1 hour, you need backups at least every hour.

24 hoursDaily backups
4 hours4x daily backups
1 hourHourly + WAL
MinutesStreaming replication

RTO - Recovery Time Objective

Maximum acceptable downtime. If your RTO is 4 hours, you must be able to restore and be operational within that time.

24 hoursManual restore
4 hoursScripted restore
1 hourWarm standby
MinutesHot standby/failover

DR Checklist

1

Document Recovery Procedures

Create step-by-step runbooks that anyone on your team can follow under pressure.

2

Identify Critical Systems

Know which Odoo modules and data are most critical to business operations.

3

Test Regularly

Schedule quarterly DR drills. Time your restore process and identify bottlenecks.

4

Multi-Region Backups

Store backups in at least two geographic regions to protect against regional disasters.

5

Communication Plan

Define who gets notified, how, and what information they need during an incident.

6

Vendor Contact List

Maintain current contact information for hosting providers, support teams, and consultants.

OEC.sh Backup Features

Managing backups manually requires constant attention and expertise. With OEC.sh, backup and disaster recovery is built-in and fully automated.

Automated Daily Backups

Database and filestore backed up every day automatically

30-Day Retention

Access any backup from the past 30 days

One-Click Restore

Restore any backup with a single click from the dashboard

Off-site Storage

Backups stored in multiple geographic regions

Backup Downloads

Download backups anytime for local storage

Encrypted at Rest

All backups encrypted with AES-256

Migrating from Self-Hosted?

If you are currently managing your own Odoo backups and want to migrate to a managed solution, we make it easy. Import your existing database and filestore with our migration tools.

Learn about migration

Frequently Asked Questions

How often should I backup Odoo?

For production systems, daily backups are the minimum recommendation. High-transaction environments should consider backing up every 4-6 hours. Critical systems may require continuous replication or point-in-time recovery capabilities. Always test your backup frequency against your RPO (Recovery Point Objective) requirements.

What's the best way to backup Odoo?

The best backup strategy uses pg_dump for database backups and tar or rsync for filestore backups, stored both locally and off-site. Automate backups with cron jobs and upload to cloud storage like AWS S3, Cloudflare R2, or Backblaze B2. OEC.sh provides automated daily backups with 30-day retention and multi-region storage built-in.

How do I restore an Odoo backup?

To restore: (1) Stop Odoo service, (2) Drop and recreate the database, (3) Use pg_restore or psql to restore the database dump, (4) Extract filestore backup to the data directory, (5) Fix file permissions, (6) Restart Odoo and verify. Always test restores in a staging environment first before applying to production.

Should I backup filestore separately?

Yes, always backup both the database and filestore. The PostgreSQL database contains all transactional data, but the filestore contains attachments, documents, images, and session files. A database backup without the filestore will result in missing attachments when restored. Use pg_dump for the database and rsync or tar for the filestore.

What's the best cloud storage for Odoo backups?

Popular options include AWS S3 (industry standard, Glacier for archives), Cloudflare R2 (zero egress fees, great for frequent restores), and Backblaze B2 (lowest cost per GB). All support S3-compatible APIs. For security, always encrypt backups before uploading. Store in multiple geographic regions for disaster recovery.

How long should I keep Odoo backups?

A common retention strategy is: daily backups for 30 days, weekly backups for 3 months, and monthly backups for 1 year. Financial or regulated industries may require longer retention periods. Always keep at least one backup off-site in a different geographic region for disaster recovery protection.

Can I backup Odoo while users are working?

Yes, pg_dump creates a consistent snapshot without locking the database. Users can continue working during backups. However, for large databases (100GB+), consider scheduling backups during low-usage periods to minimize performance impact. The filestore can be backed up with rsync while Odoo is running.

How do I verify my Odoo backups are working?

Regular restore testing is essential. At minimum, perform a monthly test restore to a staging environment. Verify the database loads correctly, check that attachments are accessible, and confirm critical business data is intact. Automated verification scripts can check backup file integrity and size consistency.

Stop Worrying About Backups

With OEC.sh, automated daily backups, off-site storage, and one-click restore are included. Focus on your business, not backup scripts.