Deploy Odoo 19 on Ubuntu 24.04 with PostgreSQL, Nginx, and DeployHQ

Devops & Infrastructure, Open Source, Python, and Tutorials

Deploy Odoo 19 on Ubuntu 24.04 with PostgreSQL, Nginx, and DeployHQ

This detailed guide will walk you through the complete process of deploying Odoo 19 on Ubuntu Server 24.04 LTS with Nginx and PostgreSQL 16, using DeployHQ for automated, zero-downtime deployments.

Why this version stack? Ubuntu 20.04 reached the end of standard support in May 2025, and PostgreSQL 12 went EOL in November 2024 — neither receives security patches without an Ubuntu Pro subscription. Ubuntu 24.04 LTS ships Python 3.12 and PostgreSQL 16 by default, both inside Odoo 19's supported range (Python 3.10-3.14, PostgreSQL ≥13). If you are still on Odoo 18 or Ubuntu 22.04, the steps below work with minor path adjustments (use /etc/postgresql/14/main/ for the 22.04 default).

1. Prerequisites

Before starting the deployment, make sure you have:

  • Ubuntu Server 24.04 LTS on the VPS of your choice
  • Root or sudo access (for installing dependencies and managing services)
  • A domain name pointed to your server's IP
  • Minimum 4 GB RAM and 2 CPU cores
  • 20 GB storage (more if you plan to host attachments and filestore backups locally)
  • A DeployHQ account for automated Git-based deployments

2. Initial Server Setup

First, update your system and install required dependencies:

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install Odoo's build and runtime dependencies
sudo apt install -y git python3-pip python3-dev python3-venv \
    build-essential wget python3-setuptools nodejs npm \
    python3-wheel libxslt-dev libzip-dev libldap2-dev libsasl2-dev \
    node-less libjpeg-dev zlib1g-dev libpq-dev \
    libxslt1-dev libxml2-dev python3-lxml

Ubuntu 24.04 ships Python 3.12 and Node.js 20, both of which work with Odoo 19. Always cross-check the official Odoo 19 source-install documentation for the latest dependency list in case Odoo adjusts the package set between minor releases.

3. PostgreSQL Installation and Configuration

Install and configure PostgreSQL for Odoo. Ubuntu 24.04's default postgresql package installs PostgreSQL 16, which is Odoo 19's recommended major version:

# Install PostgreSQL 16 (default on Ubuntu 24.04)
sudo apt install postgresql postgresql-contrib -y

# Create a database role for Odoo
sudo -u postgres createuser -s odoo
sudo -u postgres psql
ALTER USER odoo WITH PASSWORD 'your_secure_password';
\q

# Create the production database
sudo -u postgres createdb odoo_prod --owner=odoo

# Tune PostgreSQL for Odoo workloads
sudo nano /etc/postgresql/16/main/postgresql.conf

Add or modify these lines in postgresql.conf:

listen_addresses = '*'
max_connections = 100
shared_buffers = 256MB

Configure client authentication:

sudo nano /etc/postgresql/16/main/pg_hba.conf

Add these lines for local and loopback connections:

local   all             all                                     md5
host    all             all             127.0.0.1/32            md5
host    all             all             ::1/128                 md5

Restart PostgreSQL:

sudo systemctl restart postgresql

Looking after the database long-term? Schema migrations are where most Odoo deployments break. Our guide to safely orchestrating database deployments covers backup-before-migrate hooks, transactional rollback, and how to wire schema changes into a Git workflow.

4. Install and Configure Nginx

# Install Nginx
sudo apt install nginx -y

# Create the Nginx site configuration
sudo nano /etc/nginx/sites-available/odoo

Add the following configuration:

upstream odoo {
    server 127.0.0.1:8069;
}

upstream odoochat {
    server 127.0.0.1:8072;
}

server {
    listen 80;
    server_name your_domain.com;

    # Proxy timeouts (long Odoo requests are common)
    proxy_read_timeout 720s;
    proxy_connect_timeout 720s;
    proxy_send_timeout 720s;

    # Forward headers so Odoo sees the real client
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;

    # Log files
    access_log /var/log/nginx/odoo.access.log;
    error_log /var/log/nginx/odoo.error.log;

    # SSL parameters (Certbot will manage these from Step 8 onwards)
    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;
    ssl_session_timeout 30m;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # Application traffic
    location / {
        proxy_pass http://odoo;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    }

    location /longpolling {
        proxy_pass http://odoochat;
    }

    # Cache static assets
    location ~* /web/static/ {
        proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
        proxy_buffering on;
        proxy_cache odoo_cache;
        proxy_cache_valid 200 60m;
        proxy_cache_valid 404 10m;
        proxy_cache_key $request_uri;
        proxy_cache_lock on;
        proxy_cache_lock_timeout 5s;
        proxy_cache_methods GET HEAD;
        proxy_cache_revalidate on;
        proxy_cache_min_uses 1;
        expires 24h;
        add_header Cache-Control "public, no-transform";
    }
}

Enable the configuration:

sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx

5. Install Odoo

# Create the Odoo system user
sudo useradd -m -d /opt/odoo -U -r -s /bin/bash odoo

# Clone Odoo 19 from GitHub (swap 19.0 for 18.0 if you need to stay on the previous LTS)
sudo git clone --depth 1 --branch 19.0 https://github.com/odoo/odoo /opt/odoo/odoo-server

# Install Python dependencies
cd /opt/odoo/odoo-server
sudo pip3 install -r requirements.txt

# Create the custom addons directory
sudo mkdir /opt/odoo/custom-addons
sudo chown odoo:odoo /opt/odoo/custom-addons

If pip3 install complains about a managed Python environment on Ubuntu 24.04 (PEP 668), use a virtualenv: python3 -m venv /opt/odoo/odoo-server/env && /opt/odoo/odoo-server/env/bin/pip install -r requirements.txt.

6. Configure Odoo

Create the configuration file:

sudo mkdir /etc/odoo
sudo nano /etc/odoo/odoo.conf

Add the following configuration:

[options]
; General Settings
admin_passwd = your_admin_password
db_host = False
db_port = 5432
db_user = odoo
db_password = your_secure_password
addons_path = /opt/odoo/odoo-server/addons,/opt/odoo/custom-addons
default_productivity_apps = True

; HTTP Settings
http_port = 8069
http_enable = True
proxy_mode = True

; Logging Settings
logfile = /var/log/odoo/odoo-server.log
log_level = info

; Performance Tuning
workers = 4
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_request = 8192
limit_time_cpu = 600
limit_time_real = 1200

; Security Settings
list_db = False

Set proper permissions:

sudo chown odoo:odoo /etc/odoo/odoo.conf
sudo chmod 640 /etc/odoo/odoo.conf

# Create log directory
sudo mkdir /var/log/odoo
sudo chown odoo:odoo /var/log/odoo

Running Odoo for multiple clients? Agencies and consultancies typically run a separate Odoo instance per client with shared deployment tooling. Our agency deployment platform gives you per-project access controls and shared SSH keys across hundreds of servers without juggling Jenkins or homegrown scripts.

7. Create a Systemd Service

sudo nano /etc/systemd/system/odoo.service

Add the following content:

[Unit]
Description=Odoo
Requires=postgresql.service
After=network.target postgresql.service

[Service]
Type=simple
SyslogIdentifier=odoo
PermissionsStartOnly=true
User=odoo
Group=odoo
ExecStart=/opt/odoo/odoo-server/odoo-bin -c /etc/odoo/odoo.conf
StandardOutput=journal+console
Environment=PATH=/opt/odoo/odoo-server/env/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable odoo
sudo systemctl start odoo

8. SSL Configuration with Certbot

# Install Certbot
sudo apt install certbot python3-certbot-nginx -y

# Obtain an SSL certificate
sudo certbot --nginx -d your_domain.com

9. Security Hardening

Configure UFW firewall:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Install and configure Fail2ban:

sudo apt install fail2ban -y
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local

Add an Odoo-specific jail:

[odoo]
enabled = true
port = 8069,8072
filter = odoo
logpath = /var/log/odoo/odoo-server.log
maxretry = 5
findtime = 600
bantime = 3600

10. Backup Configuration

Create the backup script:

sudo nano /opt/odoo/backup.sh

Add the following:

#!/bin/bash
BACKUP_DIR="/var/backups/odoo"
DATABASE="odoo_prod"
BACKUP_DAYS=7

# Create backup directory
mkdir -p ${BACKUP_DIR}

# Backup database
sudo -u postgres pg_dump ${DATABASE} | gzip > "${BACKUP_DIR}/odoo_db_$(date +%Y%m%d_%H%M%S).gz"

# Backup filestore
tar -zcf "${BACKUP_DIR}/odoo_filestore_$(date +%Y%m%d_%H%M%S).tar.gz" /opt/odoo/.local/share/Odoo/filestore/${DATABASE}

# Remove old backups
find ${BACKUP_DIR} -type f -mtime +${BACKUP_DAYS} -delete

Make the script executable and schedule a nightly cron:

sudo chmod +x /opt/odoo/backup.sh
sudo crontab -e

Add a daily backup at 2 AM:

0 2 * * * /opt/odoo/backup.sh

This is a single-server backup pattern. For production Odoo deployments serving paying customers, follow the 3-2-1 rule — three copies of your data, on two different media, with one off-site. Pipe the gzipped dumps to S3/Backblaze/your cloud provider of choice, and periodically test a restore on a staging environment before you actually need it.

11. Monitoring and Maintenance

Install monitoring tools:

sudo apt install htop iotop nethogs -y

Configure log rotation:

sudo nano /etc/logrotate.d/odoo

Add configuration:

/var/log/odoo/*.log {
    weekly
    rotate 4
    compress
    missingok
    notifempty
    copytruncate
}

12. Automated Deployments with DeployHQ

12.1 Initial DeployHQ Setup

  1. Create a DeployHQ account and a new project.
  2. Connect your Git repository (GitHub, GitLab, or Bitbucket).
  3. Add your server as a deployment target:
# Create the deployment user
sudo useradd -m -s /bin/bash deployhq
sudo usermod -aG odoo deployhq

# Set up SSH key authentication
sudo mkdir -p /home/deployhq/.ssh
sudo nano /home/deployhq/.ssh/authorized_keys

# Paste DeployHQ's public SSH key
sudo chown -R deployhq:deployhq /home/deployhq/.ssh
sudo chmod 700 /home/deployhq/.ssh
sudo chmod 600 /home/deployhq/.ssh/authorized_keys

If your Odoo project uses multiple environments — development, staging, and production — connect each server to the same DeployHQ project so a single Git commit can promote through environments. See managing dev, staging, and production environments in DeployHQ for the recommended workflow.

12.2 Configure Deployment Settings

Create the deployment configuration in DeployHQ:

  1. Repository Settings:
Branch: main
Repository Type: Git
  1. Server Configuration:
Protocol: SSH
Hostname: your_server_ip
Port: 22
Username: deployhq
Authentication: SSH Key
Deploy Path: /opt/odoo

If your VPS is freshly provisioned and you don't have any deployment tooling yet, the Git-based deployment on a VPS walkthrough covers the SSH key exchange end-to-end.

12.3 Create Deployment Scripts

Create a deployment script file in your repository:

# deploy.sh
#!/bin/bash

# Update custom addons
cd /opt/odoo/custom-addons
git pull origin main

# Install/update Python dependencies
cd /opt/odoo/odoo-server
pip3 install -r requirements.txt

# Update Odoo database (optional — run during scheduled maintenance windows)
python3 odoo-bin -c /etc/odoo/odoo.conf -d odoo_prod -u all

# Set proper permissions
sudo chown -R odoo:odoo /opt/odoo/custom-addons
sudo chmod -R 755 /opt/odoo/custom-addons

# Restart Odoo service
sudo systemctl restart odoo

12.4 Configure DeployHQ Deployment Commands

Add these commands in DeployHQ's deployment configuration:

# Pre-deployment commands
chmod +x deploy.sh

# Deployment commands
./deploy.sh

# Post-deployment commands
curl -X POST https://your_monitoring_service/webhook/deployment

For more complex flows — running pip install only when requirements.txt changes, generating asset bundles, sending Slack notifications conditionally — wire them into a DeployHQ build pipeline so the work runs on the DeployHQ servers and the build artefact is rsync'd into place atomically.

12.5 Set Up Deployment Hooks

Create a webhook URL in your repository settings:

https://deployhq.com/projects/your-project/deployments/webhook

12.6 Configure Automatic Deployments

In DeployHQ, set up automatic deployments:

  1. Enable automatic deployments in project settings.
  2. Configure branch rules:
Branch: main
Environment: production
Automatic: true

12.7 Security Considerations

Limit the deployhq user's sudo rights to only the commands needed for the deploy script:

sudo visudo

Add these lines:

deployhq ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart odoo
deployhq ALL=(ALL) NOPASSWD: /usr/bin/chown -R odoo\:odoo /opt/odoo/custom-addons
deployhq ALL=(ALL) NOPASSWD: /usr/bin/chmod -R 755 /opt/odoo/custom-addons

12.8 Deployment Monitoring

Set up deployment notifications:

  1. Email notifications:
Notification Type: Email
Recipients: your-team@company.com
Events:
  - Deployment Started
  - Deployment Completed
  - Deployment Failed
  1. Slack integration:
Webhook URL: https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
Channel: #deployments
Username: DeployHQ Bot

12.9 Rollback Strategy

Define your RPO (Recovery Point Objective) — how much data you can afford to lose — and your RTO (Recovery Time Objective) — how long you can be down. For an Odoo production server hosting live transactions, an RPO measured in minutes and an RTO measured in single-digit minutes are typical. That means you need both a fast code rollback path and a recent database backup.

For the code path, a manual rollback script looks like this:

# rollback.sh
#!/bin/bash

# Specify the previous working commit
PREVIOUS_COMMIT=$1

# Rollback custom addons
cd /opt/odoo/custom-addons
git reset --hard $PREVIOUS_COMMIT

# Restart Odoo
sudo systemctl restart odoo

# Notify team
curl -X POST https://your_notification_service/webhook/rollback

DeployHQ also ships one-click rollback for code — the previous release stays on the server, so reverting is a symlink swap rather than a redeploy. For broader recovery patterns including database state, our guide to rolling back deployments safely walks through the trade-offs.

12.10 Deployment Verification

Add post-deployment checks:

# verify_deployment.sh
#!/bin/bash

# Check Odoo service status
systemctl is-active --quiet odoo
if [ $? -ne 0 ]; then
    echo "Odoo service is not running"
    exit 1
fi

# Check the web application
curl -f -s -S https://your_domain.com/web/health
if [ $? -ne 0 ]; then
    echo "Web application is not responding"
    exit 1
fi

echo "Deployment verification successful"

Remember to replace placeholder values (your_domain.com, your-team@company.com, etc.) with your actual values before running anything.

Final Steps and Verification

  1. Check service status:
sudo systemctl status odoo
sudo systemctl status nginx
sudo systemctl status postgresql
  1. Verify logs:
sudo tail -f /var/log/odoo/odoo-server.log
sudo tail -f /var/log/nginx/odoo.error.log
  1. Test the installation by accessing:
  • https://your_domain.com

Once Odoo is live, the deployment patterns above let you push code changes without taking the site down — combine them with zero-downtime deployment workflows so your users never see a 502 while you ship a bug fix.

Remember to:

  • Replace placeholder values (your_domain.com, passwords)
  • Keep your system updated regularly
  • Monitor system resources
  • Maintain regular backups and verify restores periodically
  • Review logs to catch errors early
  • Renew SSL certificates before expiration (Certbot handles this on a timer)

This guide gives you a production-ready Odoo 19 installation on Ubuntu 24.04 with security hardening, automated backups, and a clean DeployHQ deployment pipeline. Adjust the configuration values based on your server's resources, your team's RPO/RTO targets, and any compliance requirements specific to your industry.

Ready to automate your own Odoo deployments? Start a free DeployHQ trial and connect your first repository in a few minutes.


Questions or stuck on a step? Email us at support@deployhq.com or ping @deployhq on X — we read every message.