--- title: "How to Install Odoo 18 on Ubuntu 24.04 with Nginx and SSL" description: "Install Odoo 18 Community on Ubuntu 24.04 from the official repository with PostgreSQL, run it with workers behind Nginx and Let's Encrypt, and back it up." category: "Web Applications Hosting" language: en source: https://cubepath.com/docs/web-applications-hosting/odoo-erp-installation-on-linux updated: 2026-09-25 --- # How to Install Odoo 18 on Ubuntu 24.04 with Nginx and SSL 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: ```bash sudo apt update sudo apt install postgresql ``` Check that the server is running: ```bash sudo systemctl status postgresql --no-pager ``` ```output ● 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`: ```bash 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: ```bash 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: ```bash 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: ```bash sudo apt install wkhtmltopdf ``` > Note: The Ubuntu `wkhtmltopdf` package 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: ```bash sudo systemctl status odoo --no-pager curl -sI http://127.0.0.1:8069/web/database/selector | head -n 1 ``` ```output ● 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: ```bash 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: ```bash 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: ```bash sudo nano /etc/odoo/odoo.conf ``` Replace its contents with the following block, choosing a long random value for `your_master_password`: ```ini [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: ```bash sudo systemctl restart odoo sudo ss -ltnp | grep -E ':8069|:8072' ``` ```output 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: ```bash sudo apt install nginx sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw enable ``` Create a server block for Odoo: ```bash sudo nano /etc/nginx/sites-available/odoo ``` ```nginx 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: ```bash 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: ```bash sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d your_domain ``` Check that renewal will work: ```bash 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`: ```ini list_db = False dbfilter = ^odoo$ ``` Restart Odoo: ```bash 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: ```bash sudo ls /var/lib/odoo/.local/share/Odoo/filestore/ ``` ```output odoo ``` Create a backup script: ```bash sudo nano /usr/local/sbin/odoo-backup ``` ```bash #!/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: ```bash sudo chmod 700 /usr/local/sbin/odoo-backup sudo /usr/local/sbin/odoo-backup sudo ls -lh /var/backups/odoo ``` ```output -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: ```bash 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 `, 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.