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
- Create a DeployHQ account and a new project.
- Connect your Git repository (GitHub, GitLab, or Bitbucket).
- 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:
- Repository Settings:
Branch: main
Repository Type: Git
- 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:
- Enable automatic deployments in project settings.
- 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:
- Email notifications:
Notification Type: Email
Recipients: your-team@company.com
Events:
- Deployment Started
- Deployment Completed
- Deployment Failed
- 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
- Check service status:
sudo systemctl status odoo
sudo systemctl status nginx
sudo systemctl status postgresql
- Verify logs:
sudo tail -f /var/log/odoo/odoo-server.log
sudo tail -f /var/log/nginx/odoo.error.log
- 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.