Odoo is an open source suite of business applications (CRM, sales, invoicing, inventory, project management and more) that share one PostgreSQL database. In this tutorial you will install Odoo 18 Community on Ubuntu 24.04 from Odoo's official package repository, configure it for production with multiple workers, put it behind Nginx with a Let's Encrypt certificate, create your first database and schedule nightly backups.

Prerequisites

To follow this guide you need:

  • A server running Ubuntu 24.04 LTS, for example a CubePath VPS, with at least 2 vCPUs and 4 GB of RAM (8 GB for more than a handful of concurrent users).
  • A non-root user with sudo privileges.
  • A domain or subdomain (this guide uses your_domain) with a DNS A record pointing to your_server_ip.
  • Ports 80 and 443 open to the internet.

Step 1 - Installing PostgreSQL

Odoo stores all its data in PostgreSQL. Install it before Odoo, because the Odoo package looks for a local PostgreSQL server during installation to create its database role:

sudo apt update
sudo apt install postgresql

Check that the server is running:

sudo systemctl status postgresql --no-pager
● postgresql.service - PostgreSQL RDBMS
     Loaded: loaded (/usr/lib/systemd/system/postgresql.service; enabled; preset: enabled)
     Active: active (exited) since ...

active (exited) is normal here: this unit is a wrapper, and the actual cluster runs as postgresql@16-main.

Step 2 - Installing Odoo from the official repository

Odoo publishes signed Debian packages for each version. Download the repository key into /etc/apt/keyrings:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://nightly.odoo.com/odoo.key | sudo gpg --dearmor -o /etc/apt/keyrings/odoo.gpg

Add the Odoo 18.0 repository:

echo 'deb [signed-by=/etc/apt/keyrings/odoo.gpg] https://nightly.odoo.com/18.0/nightly/deb/ ./' | sudo tee /etc/apt/sources.list.d/odoo.list

Install the package. It pulls in all the Python libraries Odoo needs from Ubuntu's repositories, creates an odoo system user and a systemd service:

sudo apt update
sudo apt install odoo

Odoo generates PDF documents (quotes, invoices, delivery slips) with wkhtmltopdf, which the package does not install. Add the Ubuntu build:

sudo apt install wkhtmltopdf

Verify that the service is running and listening on its default port, 8069:

sudo systemctl status odoo --no-pager
curl -sI http://127.0.0.1:8069/web/database/selector | head -n 1
● odoo.service - Odoo Open Source ERP and CRM
     Active: active (running) since ...
HTTP/1.1 200 OK

Finally, confirm that a PostgreSQL role called odoo exists:

sudo -u postgres psql -c '\du odoo'

If the list is empty, create the role yourself. Odoo connects over the local socket as the odoo system user, so no password is needed:

sudo -u postgres createuser --createdb odoo

Step 3 - Configuring Odoo for production

The package runs Odoo in a single process listening on all interfaces, which is fine for a test but not for real use. Open the configuration file:

sudo nano /etc/odoo/odoo.conf

Replace its contents with the following block, choosing a long random value for your_master_password:

[options]
; Master password that protects database creation, backup and deletion
admin_passwd = your_master_password

; Local PostgreSQL over the Unix socket, as the odoo system user
db_host = False
db_port = False
db_user = odoo
db_password = False

; Only Nginx talks to Odoo
http_interface = 127.0.0.1
proxy_mode = True

; Multi-process mode: HTTP workers plus a separate websocket (gevent) process
workers = 3
max_cron_threads = 1
limit_time_cpu = 600
limit_time_real = 1200

A few notes on these settings:

  • proxy_mode = True makes Odoo trust the X-Forwarded-* headers from Nginx, so it generates https:// URLs and logs real client IPs.
  • With workers greater than 0, Odoo serves real-time features (chat, notifications) from a separate process on port 8072 at the /websocket path. Nginx must route that path to it, as you will do in the next step.
  • A common starting point is workers = (vCPUs * 2) + 1, as long as each worker has roughly 300 to 500 MB of RAM available.

Restart Odoo and confirm both ports are open on the loopback interface only:

sudo systemctl restart odoo
sudo ss -ltnp | grep -E ':8069|:8072'
LISTEN 0  128  127.0.0.1:8069  0.0.0.0:*  users:(("odoo",pid=...))
LISTEN 0  128  127.0.0.1:8072  0.0.0.0:*  users:(("odoo",pid=...))

Step 4 - Configuring Nginx as a reverse proxy

Install Nginx and open the firewall:

sudo apt install nginx
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Create a server block for Odoo:

sudo nano /etc/nginx/sites-available/odoo
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;
    listen [::]:80;
    server_name your_domain;

    client_max_body_size 100m;
    proxy_read_timeout 720s;
    proxy_connect_timeout 720s;
    proxy_send_timeout 720s;

    location /websocket {
        proxy_pass http://odoochat;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-Host $http_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_redirect off;
        proxy_set_header X-Forwarded-Host $http_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/json application/javascript;
}

The long timeouts allow slow operations such as large imports or database backups from the web interface to finish. Enable the site, remove the default one and reload Nginx:

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

Request a Let's Encrypt certificate. Certbot adds the HTTPS listener and the HTTP to HTTPS redirect to this server block:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your_domain

Check that renewal will work:

sudo certbot renew --dry-run

Step 5 - Creating the first database

Open https://your_domain/web/database/manager in a browser. Fill in the form:

  • Master Password: the admin_passwd value from Step 3.
  • Database Name: for example odoo. Use lowercase letters, digits and underscores.
  • Email and Password: the login of the first administrator user.
  • Language and Country: they set the default localization, including the chart of accounts.
  • Demo data: leave it unchecked for a production database.

Click Create database. After a minute or two you are logged in and see the Apps screen, where you can install modules such as Sales, Invoicing or Inventory with one click.

Once the database exists, hide the database manager so nobody can list, download or drop databases from the internet. Add these two lines to /etc/odoo/odoo.conf:

list_db = False
dbfilter = ^odoo$

Restart Odoo:

sudo systemctl restart odoo

Now https://your_domain/web/database/manager should return an error page saying the database manager has been disabled, while https://your_domain opens the login screen of your database directly.

Step 6 - Backing up the database and filestore

An Odoo backup has two parts: the PostgreSQL database and the filestore, where Odoo keeps attachments and images. With the Debian package, the filestore lives under the odoo user's home directory. Confirm its location:

sudo ls /var/lib/odoo/.local/share/Odoo/filestore/
odoo

Create a backup script:

sudo nano /usr/local/sbin/odoo-backup
#!/usr/bin/env bash
set -euo pipefail
umask 077

DB=odoo
BACKUP_DIR=/var/backups/odoo
FILESTORE=/var/lib/odoo/.local/share/Odoo/filestore
STAMP=$(date +%F-%H%M)

mkdir -p "$BACKUP_DIR"

# Custom-format dump, restorable with pg_restore
runuser -u postgres -- pg_dump -Fc "$DB" > "$BACKUP_DIR/$DB-$STAMP.dump"

tar -czf "$BACKUP_DIR/$DB-filestore-$STAMP.tar.gz" -C "$FILESTORE" "$DB"
cp /etc/odoo/odoo.conf "$BACKUP_DIR/odoo.conf-$STAMP"

find "$BACKUP_DIR" -type f -mtime +14 -delete

Make it executable, run it and check the output:

sudo chmod 700 /usr/local/sbin/odoo-backup
sudo /usr/local/sbin/odoo-backup
sudo ls -lh /var/backups/odoo
-rw------- 1 root root 5.8M Sep 25 11:05 odoo-2026-09-25-1105.dump
-rw------- 1 root root 2.1K Sep 25 11:05 odoo.conf-2026-09-25-1105
-rw------- 1 root root  14M Sep 25 11:05 odoo-filestore-2026-09-25-1105.tar.gz

Schedule it every night:

echo '0 3 * * * root /usr/local/sbin/odoo-backup' | sudo tee /etc/cron.d/odoo-backup

To restore, create an empty database owned by odoo, load the dump with pg_restore --no-owner --role=odoo -d <dbname>, and extract the filestore archive back into the filestore directory as the odoo user. Keep a copy of the backups on another server.

Troubleshooting

  • Nginx returns 502 Bad Gateway: Odoo is not running or failed to start. Check sudo systemctl status odoo and the Odoo log in /var/log/odoo/ or sudo journalctl -u odoo -n 50. A syntax error in odoo.conf is a common cause.
  • The browser console shows websocket errors or chat does not update: the /websocket location is missing from Nginx, or workers is set to 0 while Nginx sends traffic to port 8072.
  • Workers are killed with "virtual memory limit reached": large reports or imports exceed the default memory limit. Raise limit_memory_soft and limit_memory_hard (in bytes) in odoo.conf, or reduce the number of workers.
  • PDF reports have no header or footer: the Ubuntu wkhtmltopdf build lacks patched Qt. Install the patched 0.12.6 build.

Conclusion

Odoo 18 is now running on Ubuntu 24.04 in multi-worker mode, reachable only through Nginx with HTTPS, with the database manager locked and nightly backups of both the database and the filestore. Next, configure an outgoing mail server under Settings > Technical > Outgoing Mail Servers (visible in developer mode), install the apps your business needs, and test a full restore on a separate server before you rely on the backups.