Skip to Content

How to Install Odoo 19 on Ubuntu 24.04: A Production-Ready Guide

Source install, PostgreSQL, systemd, nginx, SSL, workers and backups, step by step
October 14, 2026 by
How to Install Odoo 19 on Ubuntu 24.04: A Production-Ready Guide
Bundo Tech

Odoo Online and Odoo.sh are the easiest ways to run Odoo, but many companies prefer to self-host: full control over the server, custom modules without restrictions, and predictable hosting cost. This guide shows how we at Bundo Tech set up a clean, production-ready Odoo 19 server on Ubuntu 24.04. It takes about 45 minutes.

What you need: a VPS with Ubuntu 24.04, at least 2 vCPU and 4 GB RAM (8 GB for more than 20 users), a domain pointing to the server's IP, and root or sudo access.

1. Update the server and create the odoo user

sudo apt update && sudo apt upgrade -y
sudo adduser --system --group --home /opt/odoo --shell /bin/bash odoo

Running Odoo as its own system user (never root) limits the damage if anything goes wrong.

2. Install PostgreSQL

sudo apt install -y postgresql
sudo -u postgres createuser --createdb odoo

The database role has the same name as the Linux user, so Odoo connects through the local socket with no password needed.

3. Install system dependencies

sudo apt install -y git python3-venv python3-dev build-essential \
  libpq-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \
  libjpeg-dev zlib1g-dev libffi-dev nodejs npm
sudo npm install -g rtlcss

For PDF reports (invoices, quotations) Odoo needs wkhtmltopdf 0.12.6 with patched Qt. The version in Ubuntu's own repository is not the patched build and produces reports without headers and footers, so download the patched .deb from the wkhtmltopdf GitHub releases page and install it with sudo apt install ./wkhtmltox_*.deb.

4. Download Odoo 19 and create a virtual environment

sudo su - odoo
git clone https://github.com/odoo/odoo.git --depth 1 --branch 19.0 /opt/odoo/odoo
python3 -m venv /opt/odoo/venv
/opt/odoo/venv/bin/pip install wheel
/opt/odoo/venv/bin/pip install -r /opt/odoo/odoo/requirements.txt
mkdir /opt/odoo/custom-addons
exit

Keep your own modules in /opt/odoo/custom-addons, never inside the Odoo source folder. Updating Odoo then never touches your code.

5. Write the configuration file

Create /etc/odoo.conf:

[options]
admin_passwd = CHANGE_THIS_TO_A_LONG_RANDOM_STRING
db_user = odoo
addons_path = /opt/odoo/odoo/addons,/opt/odoo/custom-addons
data_dir = /opt/odoo/.local/share/Odoo
logfile = /var/log/odoo/odoo.log
proxy_mode = True
http_interface = 127.0.0.1
list_db = False

; performance
workers = 5
max_cron_threads = 1
limit_memory_soft = 2147483648
limit_memory_hard = 2684354560
limit_time_cpu = 600
limit_time_real = 1200
sudo mkdir /var/log/odoo && sudo chown odoo: /var/log/odoo
sudo chown odoo: /etc/odoo.conf && sudo chmod 640 /etc/odoo.conf

How many workers? A common rule is (CPU cores x 2) + 1, then check that RAM allows it: each worker uses roughly 150 to 300 MB. list_db = False hides the database manager from the internet, and http_interface = 127.0.0.1 makes sure only nginx can reach Odoo.

6. Run Odoo as a systemd service

Create /etc/systemd/system/odoo.service:

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

[Service]
Type=simple
User=odoo
Group=odoo
ExecStart=/opt/odoo/venv/bin/python3 /opt/odoo/odoo/odoo-bin -c /etc/odoo.conf
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now odoo
sudo systemctl status odoo

7. Put nginx in front with free SSL

Create /etc/nginx/sites-available/odoo (replace erp.example.com):

upstream odoo     { server 127.0.0.1:8069; }
upstream odoochat { server 127.0.0.1:8072; }

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

server {
  listen 80;
  server_name erp.example.com;
  client_max_body_size 100m;
  proxy_read_timeout 720s;

  location /websocket {
    proxy_pass http://odoochat;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    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;
  }

  location / {
    proxy_pass http://odoo;
    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;
  }

  gzip on;
  gzip_types text/css text/plain application/javascript application/json image/svg+xml;
}
sudo apt install -y nginx certbot python3-certbot-nginx
sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d erp.example.com

The /websocket block matters: with workers enabled, live chat, notifications and Discuss go through port 8072. Without it, users see a "connection lost" banner.

8. Set up daily backups

A server without tested backups is not production-ready. Back up both the database and the filestore (attachments live there, not in PostgreSQL):

#!/bin/bash
# /opt/odoo/backup.sh  (run as the odoo user from cron)
DB=mydb
DEST=/opt/odoo/backups
STAMP=$(date +%F)
mkdir -p $DEST
pg_dump -Fc $DB > $DEST/$DB-$STAMP.dump
tar -czf $DEST/$DB-filestore-$STAMP.tar.gz -C /opt/odoo/.local/share/Odoo/filestore $DB
find $DEST -type f -mtime +14 -delete

Schedule it with crontab -e as the odoo user (for example 30 2 * * * /opt/odoo/backup.sh) and copy the files off the server (S3, Backblaze or another VPS). Restore one backup to a test database every month to prove it works.

9. Security checklist

  • Enable the firewall and allow only SSH, HTTP and HTTPS: sudo ufw allow OpenSSH && sudo ufw allow 'Nginx Full' && sudo ufw enable
  • Use a long random admin_passwd and keep list_db = False.
  • Disable SSH password login and use keys.
  • Install fail2ban and keep Ubuntu security updates on.
  • Pull Odoo source updates regularly with git pull in /opt/odoo/odoo, then restart the service.

Common problems

  • 502 Bad Gateway: Odoo is not running. Check sudo journalctl -u odoo -n 50 and /var/log/odoo/odoo.log.
  • PDF without header or footer: the unpatched wkhtmltopdf is installed. Install the patched 0.12.6 build.
  • Workers killed / timeouts on big imports: raise limit_time_real and limit_memory_hard, or run the import from the command line.
  • Wrong URLs (http instead of https) in emails: make sure proxy_mode = True and nginx sends X-Forwarded-Proto.

Need it done for you?

Bundo Tech is an Official Odoo Partner. We set up, harden and maintain self-hosted Odoo servers, migrate existing databases and provide ongoing support. See our Odoo deployment and managed Odoo hosting services, or contact us for a free consultation.

How to Create a Custom Module in Odoo 19: Step-by-Step Tutorial
Build a working module with a model, list and form views, security, a menu and a computed field