How to Install Odoo 20 on Ubuntu 24.04

By 

•

Updated on

•

12 min read

Deploy Odoo 20 on Ubuntu 24.04

Odoo is a popular open-source suite of business apps that help companies manage and run their business. It includes a wide range of applications such as CRM, e-commerce, website builder, billing, accounting, manufacturing, warehouse, project management, inventory, and more, all integrated with each other.

Odoo can be installed in different ways, depending on the use case and available technologies. The easiest and quickest way to install Odoo is by using the official Odoo APT repositories.

Installing Odoo in a virtual environment, or deploying as a Docker container, gives you more control over the application and allows you to run multiple Odoo instances on the same system.

This guide walks you through how to install Odoo 20 on Ubuntu 24.04 inside a Python virtual environment. We will download Odoo from the official GitHub repository and use Nginx as a reverse proxy. You can also install Odoo 19 with the version changes below.

Prerequisites

Before you begin, make sure you have:

  • A server running Ubuntu 24.04 with at least 2GB of RAM
  • Python 3.12 or later
  • PostgreSQL 16 or later
  • wkhtmltopdf 0.12.6 (for PDF headers/footers)
  • A user with sudo privileges
  • A domain name pointing to your server (for TLS/SSL setup)

These minimum versions match Odoo 20 requirements and help avoid issues with database compatibility and PDF report rendering. Ubuntu 24.04 ships Python 3.12 and PostgreSQL 16, so the packages from the standard repositories are enough.

Installing Odoo 19 on Ubuntu 24.04

For a new Odoo 19 installation, follow the same steps below, replacing odoo20 with odoo19 in the system user, PostgreSQL role, directory paths, configuration filename, and service name. When you reach the Git clone step, use the 19.0 branch:

Terminal
git clone https://www.github.com/odoo/odoo --depth 1 --branch 19.0 /opt/odoo19/odoo

Ubuntu 24.04’s Python 3.12 and PostgreSQL 16 also meet Odoo 19 requirements. The configuration below explicitly binds Odoo to 127.0.0.1, so the SSH tunnel and Nginx setup work with either version. These instructions cover a new installation; upgrading an existing database requires a separate migration.

Installing Dependencies

The first step is to install Git, Pip, Node.js, and the development tools required to build Odoo dependencies:

Terminal
sudo apt update
sudo apt install git curl python3-venv python3-pip build-essential wget python3-dev \
    python3-wheel libfreetype6-dev libxml2-dev libzip-dev libldap2-dev libsasl2-dev \
    python3-setuptools libjpeg-dev zlib1g-dev libpq-dev \
    libxslt1-dev libtiff5-dev libjpeg8-dev libopenjp2-7-dev \
    liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev libxcb1-dev

Installing Node.js

Ubuntu 24.04 ships with an older version of Node.js. To get a supported LTS release, install Node.js from the NodeSource repository:

Terminal
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install nodejs

Install the rtlcss utility (used for right-to-left language support):

Terminal
sudo npm install -g rtlcss

Optionally, verify the installed versions:

Terminal
python3 --version
node --version
npm --version

Creating a System User

Running Odoo under the root user poses a great security risk. We will create a new system user and group with home directory /opt/odoo20 that will run the Odoo service:

Terminal
sudo useradd -m -d /opt/odoo20 -U -r -s /bin/bash odoo20

You can name the user anything you want, as long as you create a PostgreSQL user with the same name.

Installing and Configuring PostgreSQL

Odoo uses PostgreSQL as the database backend. Ubuntu 24.04 includes PostgreSQL 16 in the standard repositories, which is the minimum version Odoo 20 supports. Install it with:

Terminal
sudo apt install postgresql

Once the service is installed, create a PostgreSQL user with the same name as the previously created system user. The -d option allows database creation, while -R and -S deny role creation and superuser privileges:

Terminal
sudo su - postgres -c "createuser -R -S -d odoo20"

You do not need to create a database manually. Odoo will automatically create and initialize the database when you access the web interface for the first time.

Installing wkhtmltopdf

wkhtmltopdf is an open-source CLI tool for rendering HTML pages into PDF and images. Odoo uses it to generate PDF reports.

The wkhtmltopdf package in Ubuntu repositories is built without the patched Qt, which breaks headers and footers. Use the official 0.12.6 build from GitHub:

Terminal
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb

Install the downloaded package:

Terminal
sudo apt install ./wkhtmltox_0.12.6.1-3.jammy_amd64.deb
Info
If you encounter dependency issues, run sudo apt --fix-broken install to resolve them.

Installing and Configuring Odoo 20

We will install Odoo from the source inside an isolated Python virtual environment.

First, switch to the “odoo20” user:

Terminal
sudo su - odoo20

Clone the Odoo 20 source code from GitHub:

Terminal
git clone https://www.github.com/odoo/odoo --depth 1 --branch 20.0 /opt/odoo20/odoo

Create a new Python virtual environment for Odoo:

Terminal
cd /opt/odoo20
python3 -m venv odoo-venv

Activate the virtual environment:

Terminal
source odoo-venv/bin/activate

Odoo dependencies are specified in the requirements.txt file. Install all required Python modules with pip3:

Terminal
pip3 install wheel
pip3 install -r odoo/requirements.txt
Info
If you encounter any compilation errors during the installation, make sure all required dependencies listed in the “Installing Dependencies” section are installed.

Once done, deactivate the environment:

Terminal
deactivate

Create a separate directory for third-party addons:

Terminal
mkdir /opt/odoo20/odoo-custom-addons

Later we will add this directory to the addons_path parameter. This parameter defines a list of directories where Odoo searches for modules.

Switch back to your sudo user:

Terminal
exit

Create a configuration file:

Terminal
sudo nano /etc/odoo20.conf

Add the following content:

/etc/odoo20.confini
[options]
; This is the password that allows database operations:
admin_passwd = my_admin_passwd
db_host = False
db_port = False
db_user = odoo20
db_password = False
http_interface = 127.0.0.1
addons_path = /opt/odoo20/odoo/addons,/opt/odoo20/odoo-custom-addons
Warning
Change my_admin_passwd to a strong, secure password. This password is used to create, duplicate, and delete databases. Do not commit the configuration file containing this password to version control; add it to .gitignore if you keep a copy in a repository.

Creating the Systemd Service

A unit file is a configuration file that holds information about a service.

Create a file named odoo20.service:

Terminal
sudo nano /etc/systemd/system/odoo20.service

Add the following content:

/etc/systemd/system/odoo20.serviceini
[Unit]
Description=Odoo 20
Requires=postgresql.service
After=network.target postgresql.service

[Service]
Type=simple
SyslogIdentifier=odoo20
User=odoo20
Group=odoo20
ExecStart=/opt/odoo20/odoo-venv/bin/python3 /opt/odoo20/odoo/odoo-bin -c /etc/odoo20.conf
StandardOutput=journal+console

[Install]
WantedBy=multi-user.target

Reload systemd to recognize the new unit file:

Terminal
sudo systemctl daemon-reload

Start the Odoo service and enable it to start on boot:

Terminal
sudo systemctl enable --now odoo20

Verify that the service is running:

Terminal
sudo systemctl status odoo20

The output should show that the Odoo service is active and running:

output
● odoo20.service - Odoo 20
     Loaded: loaded (/etc/systemd/system/odoo20.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-10-25 10:00:00 UTC; 10s ago
...

To view the Odoo service logs using journalctl :

Terminal
sudo journalctl -u odoo20

Other useful commands to manage the Odoo service:

Terminal
sudo systemctl restart odoo20
sudo systemctl stop odoo20
sudo systemctl start odoo20

Testing the Installation

Odoo listens on 127.0.0.1:8069 on the server. To test it from your computer before configuring Nginx, open a separate terminal on your computer and create an SSH tunnel. Replace your_user with your SSH login and your_server_ip with the server address:

Terminal
ssh -N -L 18069:127.0.0.1:8069 your_user@your_server_ip

Keep this terminal open and visit http://127.0.0.1:18069 in your local browser. If the installation is successful, you will see the Odoo database creation screen where you can create your first database and start using Odoo. The SSH tunnel encrypts traffic between your computer and the server. Press Ctrl+C in the tunnel terminal when you finish testing.

Enabling Multiprocessing

By default, Odoo runs in multithreading mode. Before configuring Nginx, enable multiprocessing so Odoo starts the dedicated WebSocket worker on port 8072, which the reverse proxy configuration below uses.

To enable multiprocessing, edit the Odoo configuration and set a non-zero number of worker processes. The number of workers is calculated based on the number of CPU cores and available RAM.

According to the official Odoo documentation , use these formulas:

Worker number calculation:

  • Theoretical maximum workers = (system_cpus * 2) + 1
  • 1 worker can serve ~= 6 concurrent users
  • Cron workers also require CPU

RAM memory calculation:

  • Assume 20% of requests are heavy (1 GB RAM) and 80% are light (150 MB RAM)
  • Needed RAM = workers * ((0.8 * 150) + (0.2 * 1024))

To check the number of CPUs on your system:

Terminal
grep -c ^processor /proc/cpuinfo

For a system with 4 CPU cores, 8 GB of RAM, and 30 concurrent users:

  • 30 users / 6 = 5 workers needed
  • (4 * 2) + 1 = 9 maximum workers
  • Use 5 workers + 1 cron worker = 6 total workers
  • RAM needed: 6 * ((0.8 * 150) + (0.2 * 1024)) ~= 2 GB

Open the Odoo configuration file:

Terminal
sudo nano /etc/odoo20.conf

Under [options], add the following settings. This example is for the 4-core, 8 GB server above; reduce the worker count for a smaller server and leave RAM for PostgreSQL and the operating system. The memory limits apply to each worker, not the whole service.

/etc/odoo20.confconf
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_request = 8192
limit_time_cpu = 600
limit_time_real = 1200
max_cron_threads = 1
workers = 5

Restart the Odoo service:

Terminal
sudo systemctl restart odoo20

Configuring Nginx as a Reverse Proxy with TLS Termination

The default Odoo web server serves traffic over HTTP. To make the Odoo deployment more secure, we will configure Nginx as a reverse proxy with TLS termination to serve traffic over HTTPS.

TLS termination means Nginx processes and decrypts incoming TLS (HTTPS) connections, then forwards unencrypted HTTP requests to Odoo. The traffic between Nginx and Odoo will not be encrypted.

Using a reverse proxy provides benefits such as load balancing, TLS termination, caching, compression, and serving static content.

Before continuing, ensure you have:

  • A domain name pointing to your server. We will use example.com.
  • Nginx installed.
  • A TLS certificate for your domain (for example, a free Let’s Encrypt certificate).

Create the Nginx server block configuration:

Terminal
sudo nano /etc/nginx/sites-available/odoo.conf

Add the following configuration:

/etc/nginx/sites-available/odoo.confnginx
# Odoo servers
upstream odoo {
    server 127.0.0.1:8069;
}

upstream odoochat {
    server 127.0.0.1:8072;
}

# HTTP -> HTTPS redirect
server {
    listen 80;
    listen [::]:80;
    server_name www.example.com example.com;

    return 301 https://example.com$request_uri;
}

# WWW -> NON-WWW redirect
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name www.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    return 301 https://example.com$request_uri;
}

# Main server block
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name example.com;

    proxy_read_timeout 720s;
    proxy_connect_timeout 720s;
    proxy_send_timeout 720s;

    # Proxy headers
    proxy_set_header Host $host;
    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;

    # SSL parameters
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

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

    # Websocket (live chat)
    location /websocket {
        proxy_pass http://odoochat;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        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;
    }

    # Handle / requests
    location / {
        proxy_redirect off;
        proxy_pass http://odoo;
    }

    # Cache static files
    location ~* /web/static/ {
        proxy_cache_valid 200 90m;
        proxy_buffering on;
        expires 864000;
        proxy_pass http://odoo;
    }

    # Gzip compression
    gzip_types text/css text/less text/plain text/xml application/xml application/json application/javascript;
    gzip on;
}
Info
Replace example.com with your actual domain name and update the SSL certificate paths accordingly.

The /websocket location uses proxy_http_version 1.1 because WebSocket upgrades require HTTP/1.1, while Nginx 1.24 defaults to HTTP/1.0 for upstream connections. It also repeats the proxy headers from the server block. Nginx does not pass server-level proxy_set_header directives into a location that defines its own. Without the repeated headers, Odoo would not see the original host, client address, or protocol on WebSocket connections.

Ubuntu 24.04 ships Nginx 1.24, where HTTP/2 is enabled with the http2 parameter on the listen lines. The standalone http2 on; directive requires Nginx 1.25.1 or later and fails the configuration test on this version.

Enable the site by creating a symbolic link:

Terminal
sudo ln -s /etc/nginx/sites-available/odoo.conf /etc/nginx/sites-enabled/

Test the Nginx configuration:

Terminal
sudo nginx -t

If there are no errors, restart Nginx:

Terminal
sudo systemctl restart nginx

Next, tell Odoo to use the proxy. Open the configuration file and add the following line:

Terminal
sudo nano /etc/odoo20.conf
/etc/odoo20.confconf
proxy_mode = True

Restart the Odoo service:

Terminal
sudo systemctl restart odoo20

You can now access your Odoo instance at https://example.com.

Firewall Configuration (Optional)

If UFW is enabled, allow SSH and web traffic, and block direct access to Odoo’s port now that Nginx is configured:

Terminal
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw deny 8069/tcp

Troubleshooting

Missing PDF headers or footers
Make sure you are using the official wkhtmltopdf 0.12.6 build, not the distro package.

Database connection errors
Verify that the PostgreSQL role exists and that /etc/odoo20.conf uses the correct db_user.

Odoo is not reachable on port 8069 from another machine
Odoo 20 listens only on 127.0.0.1 by default. Earlier releases listened on all interfaces. Reach Odoo through Nginx or an SSH tunnel. If you need direct access on a trusted network, set http_interface = 0.0.0.0 in /etc/odoo20.conf and restart the service.

WebSocket errors or live chat does not update
The /websocket location sends traffic to port 8072, which Odoo opens only in multiprocessing mode. Confirm that workers is set to a non-zero value in /etc/odoo20.conf and that sudo ss -ltnp | grep 8072 shows Odoo listening. Check that the Nginx location includes proxy_http_version 1.1 and the Upgrade and Connection headers.

Updating Odoo 20

To update your Odoo source installation, pull the latest changes and refresh dependencies:

Terminal
sudo su - odoo20
cd /opt/odoo20/odoo
git checkout 20.0
git pull
source /opt/odoo20/odoo-venv/bin/activate
pip3 install -r requirements.txt
deactivate
exit
sudo systemctl restart odoo20

Odoo does not publish release tags in its GitHub repository. The 20.0 branch is the update channel for a source installation, so back up the database before you pull updates on a production server.

FAQ

Does Odoo 20 work on Ubuntu 24.04?
Yes. Odoo 20 requires Python 3.12 or later and PostgreSQL 16 or later, and Ubuntu 24.04 ships both in its standard repositories. For PDF reports with headers and footers, you also need the official wkhtmltopdf 0.12.6 build.

What PostgreSQL version does Odoo 20 require?
PostgreSQL 16 or later. Odoo 19 accepted PostgreSQL 13 and newer.

Which wkhtmltopdf version should I use?
Use the official wkhtmltopdf 0.12.6 build for correct PDF headers and footers.

Can I install Odoo 19 with this guide?
Yes. Follow the Odoo 19 version changes before you begin. The explicit http_interface = 127.0.0.1 setting in the configuration keeps Odoo 19 bound to localhost, matching the SSH tunnel and reverse proxy instructions.

How do I upgrade an existing Odoo 19 installation to Odoo 20?
Switching the Git branch is not enough. The database must be migrated to the new version, and custom modules must be ported. Follow the official Odoo upgrade documentation and test the upgrade on a copy of the database first.

Conclusion

We have shown you how to install Odoo 20 on Ubuntu 24.04 in a Python virtual environment and serve it over HTTPS through Nginx. Your next step should be to set up automatic daily backups of Odoo databases .

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 1000+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page