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
sudoprivileges. - A domain or subdomain (this guide uses
your_domain) with a DNSArecord pointing toyour_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
NoteThe Ubuntu
wkhtmltopdfpackage is built without the patched Qt that Odoo recommends, so report headers and footers may be missing from PDFs. If you need them, install the 0.12.6 build with patched Qt from the wkhtmltopdf project's releases instead.
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 = Truemakes Odoo trust theX-Forwarded-*headers from Nginx, so it generateshttps://URLs and logs real client IPs.- With
workersgreater than 0, Odoo serves real-time features (chat, notifications) from a separate process on port 8072 at the/websocketpath. 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_passwdvalue 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 odooand the Odoo log in/var/log/odoo/orsudo journalctl -u odoo -n 50. A syntax error inodoo.confis a common cause. - The browser console shows websocket errors or chat does not update: the
/websocketlocation is missing from Nginx, orworkersis 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_softandlimit_memory_hard(in bytes) inodoo.conf, or reduce the number of workers. - PDF reports have no header or footer: the Ubuntu
wkhtmltopdfbuild 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.
