Skip to content

Odoo High Availability Setup: Failover & Redundancy Guide (2026)

DeployMonkey Team · March 23, 2026 12 min read

What is High Availability for Odoo?

High availability (HA) means your Odoo system survives server failures without downtime. In a standard deployment, if your server dies, Odoo is offline until you restore it — potentially hours of lost productivity and revenue. With HA, a standby server takes over automatically within seconds.

HA is essential for businesses where Odoo downtime means lost sales (e-commerce), halted manufacturing, or regulatory compliance issues.

HA Architecture

                    Floating IP
                        ↓
              ┌─────────┼─────────┐
              ↓                   ↓
         Active Node         Standby Node
         ┌────────┐         ┌────────┐
         │ nginx  │         │ nginx  │
         │ Odoo   │         │ Odoo   │
         │ PG Pri │────────→│ PG Rep │
         └────────┘  stream └────────┘
                    replication

         Keepalived monitors health and
         moves floating IP on failure

Components

ComponentPurposeTool
Floating IPSingle entry point that moves between serversCloud provider API or Keepalived
Health monitoringDetect failures and trigger failoverKeepalived, HAProxy
Database replicationKeep standby DB in syncPostgreSQL streaming replication
Filestore syncKeep attachments in synclsyncd, rsync, or S3
Automatic promotionPromote replica to primary on failurePatroni, repmgr, or custom scripts

Step 1: Set Up PostgreSQL Replication

# On PRIMARY server
sudo -u postgres psql
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'rep_password';

# postgresql.conf
wal_level = replica
max_wal_senders = 5
wal_keep_size = 2048
synchronous_standby_names = 'standby1'

# pg_hba.conf
host replication replicator STANDBY_IP/32 scram-sha-256

sudo systemctl restart postgresql
# On STANDBY server
sudo systemctl stop postgresql
sudo -u postgres rm -rf /var/lib/postgresql/16/main/*
sudo -u postgres pg_basebackup -h PRIMARY_IP -U replicator \
  -D /var/lib/postgresql/16/main -P -R

# The -R flag creates standby.signal and configures primary_conninfo
sudo systemctl start postgresql

Step 2: Install Patroni for Automatic Failover

Patroni manages PostgreSQL HA with automatic failover, leader election, and cluster management:

# Install on both nodes
pip install patroni[etcd]

# patroni.yml (primary)
scope: odoo-cluster
name: node1

restapi:
  listen: 0.0.0.0:8008
  connect_address: PRIMARY_IP:8008

etcd:
  hosts: ETCD_HOST:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_level: replica
        max_wal_senders: 5
        max_replication_slots: 5

postgresql:
  listen: 0.0.0.0:5432
  connect_address: PRIMARY_IP:5432
  data_dir: /var/lib/postgresql/16/main
  authentication:
    superuser:
      username: postgres
      password: pg_password
    replication:
      username: replicator
      password: rep_password

Step 3: Configure Keepalived for Floating IP

# On primary node: /etc/keepalived/keepalived.conf
vrrp_script check_odoo {
    script "/usr/bin/curl -s -o /dev/null -w '%{http_code}' http://localhost:8069/web/health | grep -q 200"
    interval 5
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass secret123
    }
    virtual_ipaddress {
        FLOATING_IP/32
    }
    track_script {
        check_odoo
    }
    notify_master "/opt/scripts/promote.sh"
}

# On standby node: same config but
# state BACKUP, priority 90

Step 4: Filestore Synchronization

# Option A: lsyncd (real-time sync)
apt install lsyncd

# /etc/lsyncd.conf
settings {
    logfile = "/var/log/lsyncd.log",
    statusFile = "/var/log/lsyncd-status.log",
}
sync {
    default.rsync,
    source = "/opt/odoo/data/filestore",
    target = "standby:/opt/odoo/data/filestore",
    delay = 5,
    rsync = {
        archive = true,
        compress = true,
    }
}

# Option B: S3 (shared object storage)
# Both nodes use S3 for filestore — no sync needed

Step 5: Failover Promotion Script

#!/bin/bash
# /opt/scripts/promote.sh
# Called by Keepalived when this node becomes MASTER

logger "Odoo HA: Promoting standby to primary"

# Promote PostgreSQL (if using manual replication, not Patroni)
sudo -u postgres pg_ctl promote -D /var/lib/postgresql/16/main

# Start Odoo if not running
sudo systemctl start odoo

# Notify team
curl -X POST https://hooks.slack.com/services/xxx \
  -d '{"text": "Odoo failover completed. Standby promoted to primary."}'

Testing Failover

Regularly test your HA setup:

  1. Simulate failure: stop Odoo on the primary node
  2. Verify Keepalived detects failure within 15 seconds
  3. Verify floating IP moves to standby
  4. Verify standby PostgreSQL is promoted
  5. Verify users can continue working with minimal disruption
  6. Restore original primary and test failback

RTO and RPO

MetricNo HABasic HAFull HA (Patroni)
Recovery Time (RTO)1-4 hours30-60 seconds10-30 seconds
Data Loss (RPO)Last backupSeconds (async)Zero (sync replication)
Annual downtimeHoursMinutesSeconds

DeployMonkey + High Availability

DeployMonkey offers HA configurations for business-critical Odoo deployments. Automatic failover, database replication, and health monitoring are handled transparently.