Skip to main content
Backup and Recovery

Automated Odoo Backups to S3: 7 Storage Options

Learn how to automate Odoo database and filestore backups to AWS S3, Cloudflare R2, Backblaze B2, MinIO, and more. Complete scripts, retention policies, and disaster recovery procedures.

Odoo.sh Backup Limitations

Odoo.sh restricts manual backups to 5 per day and retains them for only 7 days. Shell access is limited, preventing direct pg_dump usage. Staging databases are not automatically backed up.

20-25 min read
Updated January 2026
Odoo 16.0 - 18.0

1Why Cloud Backups for Odoo?

Storing Odoo backups in cloud object storage provides enterprise-grade durability, geographic redundancy, and automated lifecycle management. Whether you're running Odoo with Docker or a traditional deployment, cloud backups are essential in 2026:

Disaster Recovery

Recover from server failures, ransomware, or data corruption with off-site backups

Compliance Requirements

Meet GDPR, SOC 2, and industry regulations requiring data retention and backup policies

Geographic Redundancy

Store backups in multiple regions to protect against regional outages

Long-term Retention

Keep yearly backups indefinitely with cost-effective cold storage tiers

Cost Efficiency

Pay only for storage used with automatic tiering to reduce costs

Automation

Set-and-forget with scheduled backups and automatic retention management

Learn More

For complete disaster recovery procedures and restoration guides, see our Backup and Recovery Guide.

2Storage Options Comparison

OEC.sh supports 7 backup destinations. Choose based on your budget, compliance needs, and existing infrastructure:

AWS S3

~$0.023/GB storage + egress

Industry standard, enterprise-grade object storage

Pros

  • Widest integration support
  • 99.999999999% durability
  • Advanced security features

Cons

  • Egress fees can add up
  • Complex pricing structure

Best for: Enterprise, AWS ecosystem

Cloudflare R2

$0.015/GB storage, $0 egress

S3-compatible storage with zero egress fees

Pros

  • No egress fees
  • S3-compatible API
  • Global edge network

Cons

  • Newer service
  • Fewer regions than S3

Best for: High-download workloads

Backblaze B2

$0.006/GB storage

Lowest cost cloud storage option

Pros

  • Lowest storage cost
  • Simple pricing
  • S3-compatible API

Cons

  • Lower egress cap
  • Fewer features

Best for: Budget-conscious, archival

MinIO

Free (infrastructure costs)

Self-hosted S3-compatible object storage

Pros

  • Self-hosted control
  • No vendor lock-in
  • S3-compatible

Cons

  • Requires infrastructure
  • Self-managed

Best for: On-premise, compliance

FTP/SFTP

Varies by provider

Traditional file transfer protocol

Pros

  • Simple setup
  • Works anywhere
  • No special client

Cons

  • Less scalable
  • Manual management

Best for: Legacy systems, simple needs

WebDAV

Varies by provider

Web-based file access protocol

Pros

  • HTTP-based
  • Easy firewall traversal
  • Wide support

Cons

  • Slower than native protocols
  • Variable performance

Best for: Web-integrated workflows

ProviderStorage/GBEgress/GB100GB/mo
AWS S3 Standard$0.023$0.09$2.30
Cloudflare R2$0.015$0.00$1.50
Backblaze B2$0.006$0.01$0.60
MinIO (Self-hosted)Infra costInfra costVariable

All OEC.sh plans include automated backups to your choice of cloud storage. Compare pricing plans to find the right fit for your backup needs.

3What to Backup

A complete Odoo backup requires multiple components. Missing any of these can result in an incomplete or unusable restore:

PostgreSQL Database

The core database containing all Odoo data: users, products, orders, accounting, etc. Use pg_dump for reliable backups.

Typical size: 1GB - 50GB depending on usage

Filestore (Attachments)

Binary files stored on disk: email attachments, uploaded documents, product images, reports. Located in ~/.local/share/Odoo/filestore/.

Typical size: 5GB - 200GB+ depending on attachments

Custom Modules (Git-controlled)

Your custom Odoo modules should be version-controlled in Git. Include them in deployment, not necessarily in daily backups.

Best practice: Store in Git repository with tags for each deployment

Configuration Files

Odoo configuration (odoo.conf), nginx config, systemd units. Critical for restoring the exact server state.

Typical size: A few KB - best kept in version control

4Complete Backup Scripts

Copy-paste ready scripts for backing up Odoo to various cloud storage providers. Each script includes database backup, filestore archiving, and upload.

Complete Backup Script (pg_dump + Filestore)

odoo-backup.shbash
1#!/bin/bash
2# Odoo Backup Script - Database + Filestore
3# Usage: ./odoo-backup.sh database_name
4
5set -e
6
7# Configuration
8DB_NAME="${1:-odoo}"
9BACKUP_DIR="/var/backups/odoo"
10FILESTORE_PATH="/opt/odoo/.local/share/Odoo/filestore/${DB_NAME}"
11TIMESTAMP=$(date +%Y%m%d_%H%M%S)
12BACKUP_NAME="odoo_${DB_NAME}_${TIMESTAMP}"
13
14# Create backup directory
15mkdir -p "${BACKUP_DIR}"
16
17echo "Starting backup for database: ${DB_NAME}"
18
19# Backup PostgreSQL database
20echo "Backing up PostgreSQL database..."
21pg_dump -Fc -f "${BACKUP_DIR}/${BACKUP_NAME}.dump" "${DB_NAME}"
22
23# Backup filestore
24echo "Backing up filestore..."
25tar -czf "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" -C "${FILESTORE_PATH}" .
26
27# Create manifest file
28echo "Creating manifest..."
29cat > "${BACKUP_DIR}/${BACKUP_NAME}_manifest.json" << EOF
30{
31 "database": "${DB_NAME}",
32 "timestamp": "${TIMESTAMP}",
33 "odoo_version": "$(odoo --version 2>/dev/null || echo 'unknown')",
34 "db_size": "$(du -h ${BACKUP_DIR}/${BACKUP_NAME}.dump | cut -f1)",
35 "filestore_size": "$(du -h ${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz | cut -f1)"
36}
37EOF
38
39echo "Backup completed: ${BACKUP_DIR}/${BACKUP_NAME}"
40echo "Database: ${BACKUP_DIR}/${BACKUP_NAME}.dump"
41echo "Filestore: ${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz"

Upload to AWS S3

upload-to-s3.shbash
#!/bin/bash
# Upload Odoo backup to AWS S3
S3_BUCKET="your-odoo-backups"
S3_PATH="backups/production"
BACKUP_DIR="/var/backups/odoo"
BACKUP_NAME="$1"
# Install AWS CLI if not present
# pip3 install awscli
# Configure AWS credentials (run once)
# aws configure
# Upload backup files
echo "Uploading to S3..."
aws s3 cp "${BACKUP_DIR}/${BACKUP_NAME}.dump" "s3://${S3_BUCKET}/${S3_PATH}/" --storage-class STANDARD_IA
aws s3 cp "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" "s3://${S3_BUCKET}/${S3_PATH}/" --storage-class STANDARD_IA
aws s3 cp "${BACKUP_DIR}/${BACKUP_NAME}_manifest.json" "s3://${S3_BUCKET}/${S3_PATH}/"
# Verify upload
aws s3 ls "s3://${S3_BUCKET}/${S3_PATH}/${BACKUP_NAME}"
echo "Upload complete!"

Upload to Cloudflare R2 with rclone

upload-to-r2.shbash
#!/bin/bash
# Upload Odoo backup to Cloudflare R2 using rclone
# First, configure rclone for R2 (run once):
# rclone config
# Choose: New remote -> name: r2 -> type: s3
# Provider: Cloudflare
# Access Key ID: <your R2 access key>
# Secret Access Key: <your R2 secret>
# Endpoint: https://<account-id>.r2.cloudflarestorage.com
R2_REMOTE="r2:odoo-backups"
BACKUP_DIR="/var/backups/odoo"
BACKUP_NAME="$1"
echo "Uploading to Cloudflare R2..."
rclone copy "${BACKUP_DIR}/${BACKUP_NAME}.dump" "${R2_REMOTE}/backups/"
rclone copy "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" "${R2_REMOTE}/backups/"
rclone copy "${BACKUP_DIR}/${BACKUP_NAME}_manifest.json" "${R2_REMOTE}/backups/"
# Verify
rclone ls "${R2_REMOTE}/backups/" | grep "${BACKUP_NAME}"
echo "R2 upload complete!"

Upload to Backblaze B2

upload-to-b2.shbash
#!/bin/bash
# Upload Odoo backup to Backblaze B2
# Install B2 CLI: pip3 install b2
# Authorize: b2 authorize-account <applicationKeyId> <applicationKey>
B2_BUCKET="odoo-backups"
BACKUP_DIR="/var/backups/odoo"
BACKUP_NAME="$1"
echo "Uploading to Backblaze B2..."
b2 upload-file "${B2_BUCKET}" "${BACKUP_DIR}/${BACKUP_NAME}.dump" "backups/${BACKUP_NAME}.dump"
b2 upload-file "${B2_BUCKET}" "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" "backups/${BACKUP_NAME}_filestore.tar.gz"
b2 upload-file "${B2_BUCKET}" "${BACKUP_DIR}/${BACKUP_NAME}_manifest.json" "backups/${BACKUP_NAME}_manifest.json"
# List recent uploads
b2 ls "${B2_BUCKET}" backups/ | tail -5
echo "B2 upload complete!"

All-in-One Script (Backup + Upload)

odoo-backup-full.shbash
1#!/bin/bash
2# Complete Odoo Backup Script with S3 Upload
3# Run daily via cron
4
5set -e
6
7# Configuration
8DB_NAME="odoo_production"
9BACKUP_DIR="/var/backups/odoo"
10FILESTORE_PATH="/opt/odoo/.local/share/Odoo/filestore/${DB_NAME}"
11S3_BUCKET="your-odoo-backups"
12S3_PATH="backups/production"
13RETENTION_DAYS=7
14TIMESTAMP=$(date +%Y%m%d_%H%M%S)
15BACKUP_NAME="odoo_${DB_NAME}_${TIMESTAMP}"
16
17# Create backup directory
18mkdir -p "${BACKUP_DIR}"
19
20# Start backup
21echo "[$(date)] Starting Odoo backup..."
22
23# 1. Backup database
24echo "Step 1/4: Backing up PostgreSQL..."
25pg_dump -Fc -f "${BACKUP_DIR}/${BACKUP_NAME}.dump" "${DB_NAME}"
26
27# 2. Backup filestore
28echo "Step 2/4: Backing up filestore..."
29tar -czf "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" -C "${FILESTORE_PATH}" .
30
31# 3. Upload to S3
32echo "Step 3/4: Uploading to S3..."
33aws s3 cp "${BACKUP_DIR}/${BACKUP_NAME}.dump" "s3://${S3_BUCKET}/${S3_PATH}/" --storage-class STANDARD_IA
34aws s3 cp "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" "s3://${S3_BUCKET}/${S3_PATH}/" --storage-class STANDARD_IA
35
36# 4. Clean up local backups older than retention period
37echo "Step 4/4: Cleaning up old local backups..."
38find "${BACKUP_DIR}" -name "odoo_*.dump" -mtime +${RETENTION_DAYS} -delete
39find "${BACKUP_DIR}" -name "odoo_*_filestore.tar.gz" -mtime +${RETENTION_DAYS} -delete
40
41echo "[$(date)] Backup completed successfully!"
42echo "Backup size: $(du -h ${BACKUP_DIR}/${BACKUP_NAME}.dump | cut -f1) (DB) + $(du -h ${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz | cut -f1) (Filestore)"

5Retention Policies

A good retention policy balances recovery flexibility with storage costs. Here is our recommended policy:

D

Daily Backups

Keep for 7 days

One backup per day, typically run at night during low-traffic hours.

W

Weekly Backups

Keep for 4 weeks

Sunday backup promoted to weekly. Useful for recovering from issues discovered late.

M

Monthly Backups

Keep for 12 months

First backup of each month. Critical for compliance and long-term recovery.

Y

Yearly Backups

Keep forever

January 1st backup archived to cold storage. Essential for legal and audit purposes.

S3 Lifecycle Policy

s3-lifecycle-policy.jsonjson
{
"Rules": [
{
"ID": "DailyBackupRetention",
"Filter": { "Prefix": "backups/daily/" },
"Status": "Enabled",
"Expiration": { "Days": 7 }
},
{
"ID": "WeeklyBackupRetention",
"Filter": { "Prefix": "backups/weekly/" },
"Status": "Enabled",
"Expiration": { "Days": 30 }
},
{
"ID": "MonthlyBackupToGlacier",
"Filter": { "Prefix": "backups/monthly/" },
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "GLACIER" }
],
"Expiration": { "Days": 365 }
},
{
"ID": "YearlyToDeepArchive",
"Filter": { "Prefix": "backups/yearly/" },
"Status": "Enabled",
"Transitions": [
{ "Days": 30, "StorageClass": "DEEP_ARCHIVE" }
]
}
]
}

Apply this policy with: aws s3api put-bucket-lifecycle-configuration --bucket your-bucket --lifecycle-configuration file://s3-lifecycle-policy.json

6Automation

Automate backups using cron, systemd timers, or OEC.sh built-in scheduling. Never rely on manual backups for production.

Cron Job Setup

Setup cron for daily backupsbash
# Edit crontab for the odoo user
sudo crontab -u odoo -e
# Add these lines:
# Daily backup at 2:00 AM
0 2 * * * /opt/odoo/scripts/odoo-backup-full.sh >> /var/log/odoo-backup.log 2>&1
# Weekly backup on Sunday at 3:00 AM (promoted to weekly folder)
0 3 * * 0 /opt/odoo/scripts/odoo-backup-weekly.sh >> /var/log/odoo-backup.log 2>&1
# Monthly backup on 1st of month at 4:00 AM
0 4 1 * * /opt/odoo/scripts/odoo-backup-monthly.sh >> /var/log/odoo-backup.log 2>&1

Systemd Timer (Recommended)

/etc/systemd/system/odoo-backup.timerini
[Unit]
Description=Daily Odoo Backup Timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
/etc/systemd/system/odoo-backup.serviceini
[Unit]
Description=Odoo Backup Service
After=postgresql.service
[Service]
Type=oneshot
User=odoo
ExecStart=/opt/odoo/scripts/odoo-backup-full.sh
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
Enable the timerbash
# Enable and start the timer
sudo systemctl daemon-reload
sudo systemctl enable odoo-backup.timer
sudo systemctl start odoo-backup.timer
# Check timer status
sudo systemctl list-timers | grep odoo
# View backup logs
sudo journalctl -u odoo-backup.service

OEC.sh Built-in Scheduling

OEC.sh provides built-in backup scheduling with no manual configuration required:

  • Schedule backups every 15 minutes, hourly, or daily
  • Configure retention policies via dashboard
  • Email notifications on backup success/failure
  • One-click restore to any environment

7Testing Restores

Critical: A backup that cannot be restored is worthless

Schedule monthly restore tests to a staging environment. Document and time the entire process.

Complete Restore Script

odoo-restore.shbash
1#!/bin/bash
2# Odoo Restore Script
3# Usage: ./odoo-restore.sh backup_name target_database
4
5set -e
6
7BACKUP_NAME="$1"
8TARGET_DB="${2:-odoo_restored}"
9BACKUP_DIR="/var/backups/odoo"
10FILESTORE_PATH="/opt/odoo/.local/share/Odoo/filestore"
11
12if [ -z "$BACKUP_NAME" ]; then
13 echo "Usage: ./odoo-restore.sh backup_name [target_database]"
14 exit 1
15fi
16
17echo "Restoring ${BACKUP_NAME} to database ${TARGET_DB}..."
18
19# 1. Stop Odoo service (for safety)
20echo "Step 1/5: Stopping Odoo service..."
21sudo systemctl stop odoo
22
23# 2. Create target database
24echo "Step 2/5: Creating target database..."
25sudo -u postgres dropdb --if-exists "${TARGET_DB}"
26sudo -u postgres createdb -O odoo "${TARGET_DB}"
27
28# 3. Restore database from pg_dump
29echo "Step 3/5: Restoring PostgreSQL database..."
30pg_restore -d "${TARGET_DB}" -O -x "${BACKUP_DIR}/${BACKUP_NAME}.dump"
31
32# 4. Restore filestore
33echo "Step 4/5: Restoring filestore..."
34mkdir -p "${FILESTORE_PATH}/${TARGET_DB}"
35tar -xzf "${BACKUP_DIR}/${BACKUP_NAME}_filestore.tar.gz" -C "${FILESTORE_PATH}/${TARGET_DB}/"
36chown -R odoo:odoo "${FILESTORE_PATH}/${TARGET_DB}"
37
38# 5. Restart Odoo
39echo "Step 5/5: Starting Odoo service..."
40sudo systemctl start odoo
41
42echo ""
43echo "Restore completed successfully!"
44echo "Database: ${TARGET_DB}"
45echo "Filestore: ${FILESTORE_PATH}/${TARGET_DB}"
46echo ""
47echo "Next steps:"
48echo "1. Update odoo.conf to use database: ${TARGET_DB}"
49echo "2. Test login and verify data integrity"
50echo "3. Check attachments and uploaded files"

Download from S3 and Restore

restore-from-s3.shbash
#!/bin/bash
# Download backup from S3 and restore
S3_BUCKET="your-odoo-backups"
S3_PATH="backups/production"
BACKUP_NAME="$1"
BACKUP_DIR="/var/backups/odoo"
# Download from S3
echo "Downloading backup from S3..."
aws s3 cp "s3://${S3_BUCKET}/${S3_PATH}/${BACKUP_NAME}.dump" "${BACKUP_DIR}/"
aws s3 cp "s3://${S3_BUCKET}/${S3_PATH}/${BACKUP_NAME}_filestore.tar.gz" "${BACKUP_DIR}/"
# Run restore script
./odoo-restore.sh "${BACKUP_NAME}"

Verification Checklist

1
Database restores without errors
2
Admin user can log in
3
Recent transactions are present
4
Attachments and images load correctly
5
Reports generate without errors
6
Email templates are intact
7
Custom modules load and function
8
Scheduled actions are present

OEC.sh Backup Features

Skip the manual configuration. OEC.sh provides enterprise-grade backup features out of the box. Explore all features:

7 Backup Destinations

  • AWS S3
  • Cloudflare R2
  • Backblaze B2
  • MinIO (self-hosted)
  • FTP/SFTP
  • WebDAV
  • Local storage

Scheduling Options

  • Every 15 minutes
  • Hourly backups
  • Daily backups
  • Weekly snapshots
  • Monthly archives
  • Custom schedules
  • End-to-end encryption for all backup data
  • One-click restore to production or staging
  • Point-in-time recovery with WAL archiving
  • Cross-region backup replication
  • Email/Slack notifications on backup events
  • Backup integrity verification

9Frequently Asked Questions

Related Guides

Ready for Automated Backups?

Skip the manual setup. Deploy Odoo with automated backups to 7 destinations using OEC.sh. Start free, scale as you grow.

7
Backup Destinations
15min
Minimum Frequency
1-Click
Restore