Skip to content

Austin JDX Backup & Restore

Production backup and restore procedures specific to austinjdx.com.


Production Environment

Component Value
RDS Host db.austinjdx.com
RDS Port 5432
Database User austinjdx
Database Name production
PostgreSQL Version 15.14
Filestore Path /var/lib/odoo/.local/share/Odoo/filestore/production

pg_dump vs psql

Critical: Use pg_dump, NOT psql

psql is for running queries. It will NOT create a valid backup.

# WRONG - Don't do this
psql -h db.austinjdx.com -U austinjdx -d production > backup.sql

# CORRECT - Use pg_dump
pg_dump -h db.austinjdx.com -U austinjdx -d production > backup.sql

Backup Commands

Basic Backup

pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production > backup-$(date +%Y%m%d).sql
pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production | gzip > backup-$(date +%Y%m%d).sql.gz

Fastest - Parallel Custom Format

pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production -Fc -j 4 -f backup-$(date +%Y%m%d).dump

For Cross-Environment Restore (Production → Docker)

Use --no-owner to avoid role errors when restoring to Docker:

pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production --no-owner --no-acl | gzip > backup-noowner-$(date +%Y%m%d).sql.gz

Without --no-owner, you'll see:

ERROR: role "naturalfare" does not exist
ERROR: role "austinjdx" does not exist

Filestore Backup

sudo tar -czvf filestore-$(date +%Y%m%d).tar.gz -C /var/lib/odoo/.local/share/Odoo/filestore production

Download to Local Machine

If you have SSH configured with an alias (e.g., ssh austinjdx), you can use the same alias with scp.

Create Backup on Production Server

# SSH to production and create database backup
ssh austinjdx "pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production --no-owner --no-acl | gzip > /home/ubuntu/backup-$(date +%Y%m%d).sql.gz"

# Filestore backup (run on production server)
ssh austinjdx "sudo tar -czvf /home/ubuntu/filestore-$(date +%Y%m%d).tar.gz -C /var/lib/odoo/.local/share/Odoo/filestore production"

Download Files

# List available backups
ssh austinjdx "ls -lh /home/ubuntu/*.gz"

# Download database backup
scp austinjdx:/home/ubuntu/backup-$(date +%Y%m%d).sql.gz .

# Download filestore (typically 500-700MB)
scp austinjdx:/home/ubuntu/filestore-$(date +%Y%m%d).tar.gz .

One-Step Database Dump (Alternative)

Stream directly to local machine without storing on server:

ssh austinjdx "pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production --no-owner --no-acl" | gzip > backup-$(date +%Y%m%d).sql.gz

Restore to Docker

Step 1: Stop Odoo

docker compose stop odoo

Step 2: Drop and Recreate Database

docker compose exec db psql -U odoo -d postgres -c "DROP DATABASE IF EXISTS odoo_test;"
docker compose exec db psql -U odoo -d postgres -c "CREATE DATABASE odoo_test OWNER odoo;"

Step 3: Restore Backup

# From compressed file
gunzip -c backup-noowner-$(date +%Y%m%d).sql.gz | docker compose exec -T db psql -U odoo -d odoo_test

# From uncompressed file
cat backup.sql | docker compose exec -T db psql -U odoo -d odoo_test

Step 4: Restore Filestore

# Remove old filestore
sudo rm -rf odoo-data/filestore/odoo_test

# Extract production filestore
sudo tar -xzvf /path/to/filestore-YYYYMMDD.tar.gz -C odoo-data/filestore/

# Rename to match database name
sudo mv odoo-data/filestore/production odoo-data/filestore/odoo_test

# Fix permissions (101 is the odoo user inside container)
sudo chown -R 101:101 odoo-data/filestore/odoo_test

Step 5: Start Odoo

docker compose start odoo

Auto Backup Module

Production uses the auto_backup Odoo module which requires paramiko.

Error After Restore

ImportError: This module needs paramiko to automatically write backups to the FTP through SFTP.

Fix

# Add to odoo/requirements.txt
echo "paramiko>=3.0.0" >> odoo/requirements.txt

# Rebuild and restart
docker compose build odoo
docker compose up -d odoo

The paramiko dependency is already included in odoo/requirements.txt:

# auto_backup module
paramiko>=3.0.0

Module Schema Sync

When restoring production to Docker, schema mismatches occur if modules differ between environments.

Common Errors

psycopg2.errors.UndefinedColumn: column res_company.sale_order_prefix does not exist
psycopg2.errors.UndefinedTable: relation "helpdesk_ticket_assign_wizard" does not exist
ERROR: Some modules are not loaded: ['sync_google_contact']

Fix: Upgrade Modules

Step 1: Upgrade stock module first (required for jdx_core_data):

docker compose stop odoo

docker compose run --rm odoo odoo -d odoo_test -u stock --stop-after-init

Step 2: Then upgrade custom modules:

docker compose run --rm odoo odoo -d odoo_test \
  -u bi_product_dimension,jdx_sale_order_photos,jdx_service_signature,jdx_field_service_automation,helpdesk,restapi \
  --stop-after-init

docker compose start odoo

stock.route Error

If you see KeyError: 'stock.route' when installing modules, upgrade the stock module first:

docker compose run --rm odoo odoo -d odoo_test -u stock --stop-after-init

Uninstall Missing Modules

If a module exists in database but not in addons (e.g., sync_google_contact):

docker compose exec db psql -U odoo -d odoo_test -c "
UPDATE ir_module_module SET state = 'uninstalled' WHERE name = 'sync_google_contact';
DELETE FROM ir_model_data WHERE module = 'sync_google_contact';
"

Clean Up Invalid Views

After removing modules, orphaned views cause 500 errors:

Field "middle_name" does not exist in model "res.partner"
Field "module_google_contacts" does not exist in model "res.config.settings"

Fix:

docker compose exec db psql -U odoo -d odoo_test -c "
DELETE FROM ir_ui_view
WHERE arch_db LIKE '%middle_name%'
   OR arch_db LIKE '%module_google_contacts%'
   OR arch_db LIKE '%remove_token%';
"

Clean Up Orphaned Models

If you see warnings like Model google.contacts is declared but cannot be loaded:

docker compose exec db psql -U odoo -d odoo_test -c "
DELETE FROM ir_model WHERE model IN ('google.contacts', 'google.details', 'google.groups');
DELETE FROM ir_model_fields WHERE model IN ('google.contacts', 'google.details', 'google.groups');
"

Troubleshooting Checklist

500 Error After Restore

  1. Check logs:

    docker compose logs odoo --tail 50
    

  2. Look for: UndefinedColumn, UndefinedTable, missing module errors

Missing Column Errors

Option A: Run module upgrade (recommended)

docker compose run --rm odoo odoo -d odoo_test -u base --stop-after-init

Option B: Manually add column

docker compose exec db psql -U odoo -d odoo_test -c "
ALTER TABLE res_company ADD COLUMN IF NOT EXISTS sale_order_prefix VARCHAR(10);
ALTER TABLE res_company ADD COLUMN IF NOT EXISTS sale_order_next_number INTEGER DEFAULT 1;
"

Missing Module Errors

Uninstall from database:

docker compose exec db psql -U odoo -d odoo_test -c "
UPDATE ir_module_module SET state = 'uninstalled' WHERE name = 'module_name';
DELETE FROM ir_model_data WHERE module = 'module_name';
"

Transaction Errors (InFailedSqlTransaction)

# Restart to clear stuck transactions
docker compose restart odoo

If persists, check earlier log entries for root cause.


PostgreSQL Version Check

Environment Version
Production RDS 15.14
Docker 15.15

Both use PostgreSQL 15.x - fully compatible.

# Check Production
psql -h db.austinjdx.com -p 5432 -U austinjdx -d production -c "SELECT version();"

# Check Docker
docker compose exec db psql -U odoo -d postgres -c "SELECT version();"

Quick Reference

Full Backup & Restore to Docker

# 1. Backup from production (--no-owner avoids role errors on restore)
ssh austinjdx "pg_dump -h db.austinjdx.com -p 5432 -U austinjdx -d production --no-owner --no-acl | gzip > /home/ubuntu/backup.sql.gz"
ssh austinjdx "sudo tar -czvf /home/ubuntu/filestore.tar.gz -C /var/lib/odoo/.local/share/Odoo/filestore production"

# 2. Download to local
scp austinjdx:/home/ubuntu/backup.sql.gz .
scp austinjdx:/home/ubuntu/filestore.tar.gz .

# 3. Stop Odoo
docker compose stop odoo

# 4. Recreate database
docker compose exec db psql -U odoo -d postgres -c "DROP DATABASE IF EXISTS odoo_test;"
docker compose exec db psql -U odoo -d postgres -c "CREATE DATABASE odoo_test OWNER odoo;"

# 5. Restore database
gunzip -c backup.sql.gz | docker compose exec -T db psql -U odoo -d odoo_test

# 6. Restore filestore
sudo rm -rf odoo-data/filestore/odoo_test
sudo tar -xzvf filestore.tar.gz -C odoo-data/filestore/
sudo mv odoo-data/filestore/production odoo-data/filestore/odoo_test
sudo chown -R 101:101 odoo-data/filestore/odoo_test

# 7. Uninstall missing sync_google_contact module
docker compose exec db psql -U odoo -d odoo_test -c "
UPDATE ir_module_module SET state = 'uninstalled' WHERE name = 'sync_google_contact';
DELETE FROM ir_model_data WHERE module = 'sync_google_contact';
"

# 8. Upgrade purchase and stock modules
docker compose run --rm odoo odoo -d odoo_test -u purchase,stock --stop-after-init

# 9. Upgrade custom modules (includes restapi binary fix)
docker compose run --rm odoo odoo -d odoo_test -u bi_product_dimension,jdx_sale_order_photos,jdx_service_signature,jdx_field_service_automation,helpdesk,restapi --stop-after-init

# 10. Clean up invalid views from removed modules
docker compose exec db psql -U odoo -d odoo_test -c "
DELETE FROM ir_ui_view
WHERE arch_db LIKE '%middle_name%'
   OR arch_db LIKE '%module_google_contacts%'
   OR arch_db LIKE '%remove_token%';
"

# 11. Clear assets cache
docker compose exec db psql -U odoo -d odoo_test -c "DELETE FROM ir_attachment WHERE url LIKE '/web/assets/%';"

# 12. Start Odoo
docker compose start odoo

# 13. Test (clear browser cache first)
curl -s http://localhost:8016/web/login -o /dev/null -w "%{http_code}"
# Should return: 200

REST API Binary Fix

Step 9 upgrades the restapi module which includes a fix for binary attachment handling. Without this, creating attachments with images via REST API fails with UTF-8 decode errors. See Troubleshooting > REST API Issues for details.

View Conflict Fixed

The purchase_stock view conflict (Element '<xpath expr="//div[@t-elif='o.date_order']">' cannot be located) is now permanently fixed.

The bi_product_dimension module was restructured to use position="attributes" with display:none instead of position="replace". This preserves the original DOM structure that purchase_stock needs. No need to delete views manually - just upgrade purchase,stock together.