Skip to content

Auto-Restart Odoo on Crash: Systemd, Monit & Watchdog

DeployMonkey Team · March 23, 2026 8 min read

Why Odoo Crashes

Odoo can crash from OOM kills, uncaught exceptions, worker timeouts, or resource exhaustion. A production server must automatically recover from crashes without manual intervention. Multiple strategies ensure high availability.

Systemd Auto-Restart

# /etc/systemd/system/odoo.service
[Service]
Restart=on-failure
RestartSec=5
StartLimitBurst=5
StartLimitIntervalSec=300

# Restart policies:
# on-failure: restart on non-zero exit, signal, timeout
# always: restart regardless of exit status
# on-abnormal: restart on signal, timeout, watchdog
# on-abort: restart on signal only

# Recommended: on-failure
# Restarts on crash but not on clean 'systemctl stop'

# StartLimitBurst/Interval:
# Max 5 restarts in 300 seconds
# After that, service enters 'failed' state
# Manual intervention needed

Systemd Watchdog

# Built-in systemd watchdog:
[Service]
Type=notify
WatchdogSec=30

# Odoo must send sd_notify("WATCHDOG=1") periodically
# If not received within 30s, systemd kills and restarts

# For Odoo (which doesn't natively support sd_notify),
# use a wrapper script:

# /opt/odoo/watchdog.sh
#!/bin/bash
/opt/odoo/venv/bin/python3 /opt/odoo/odoo-server/odoo-bin \
  --config=/etc/odoo.conf &
ODOO_PID=$!
while kill -0 $ODOO_PID 2>/dev/null; do
  if curl -sf http://localhost:8069/web/health > /dev/null; then
    systemd-notify WATCHDOG=1
  fi
  sleep 10
done

Monit Process Monitor

# Install Monit
sudo apt install -y monit

# /etc/monit/conf.d/odoo
check process odoo with pidfile /var/run/odoo.pid
  start program = "/usr/bin/systemctl start odoo"
  stop program = "/usr/bin/systemctl stop odoo"
  if failed host 127.0.0.1 port 8069
    protocol http request "/web/health"
    with timeout 15 seconds
    for 3 cycles
    then restart
  if cpu > 90% for 5 cycles then restart
  if memory > 80% for 3 cycles then restart
  if 5 restarts within 5 cycles then alert

# Enable Monit
sudo systemctl enable --now monit
sudo monit reload

Health Check Script

# /opt/odoo/healthcheck.sh
#!/bin/bash
MAX_FAILURES=3
FAILURES=0

while true; do
  HTTP_CODE=$(curl -so /dev/null -w "%{http_code}" \
    --max-time 10 http://localhost:8069/web/health 2>/dev/null)

  if [ "$HTTP_CODE" != "200" ]; then
    FAILURES=$((FAILURES + 1))
    logger -t odoo-health "Health check failed ($FAILURES/$MAX_FAILURES)"

    if [ $FAILURES -ge $MAX_FAILURES ]; then
      logger -t odoo-health "Restarting Odoo after $MAX_FAILURES failures"
      systemctl restart odoo
      FAILURES=0
      sleep 30  # Wait for startup
    fi
  else
    FAILURES=0
  fi
  sleep 15
done

# Run as systemd service:
# /etc/systemd/system/odoo-health.service

Crash Notifications

# Systemd email on failure:
# /etc/systemd/system/odoo.service.d/notify.conf
[Unit]
OnFailure=odoo-notify@%n.service

# /etc/systemd/system/[email protected]
[Unit]
Description=Crash notification for %i

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c '\
  echo "Service %i crashed at $(date)" | \
  mail -s "ALERT: %i crashed" [email protected]'

# Or use webhook:
ExecStart=/usr/bin/curl -X POST \
  -d '{"text":"Odoo crashed and restarted"}' \
  https://hooks.slack.com/services/XXXX

OOM Kill Prevention

# Adjust OOM score for Odoo
# Lower score = less likely to be killed
echo -500 | sudo tee /proc/$(pgrep -f odoo-bin)/oom_score_adj

# Permanent via systemd:
[Service]
OOMScoreAdjust=-500

# Combined with swap and memory limits:
MemoryMax=4G
MemoryHigh=3G

DeployMonkey

DeployMonkey monitors every Odoo instance with health checks and automatic restart. Crash notifications are sent via the control panel with no manual setup required.