Install Odoo on Ubuntu 22.04 & 24.04
Complete Odoo 18 installation on a fresh Ubuntu server. Python, PostgreSQL, wkhtmltopdf, Nginx, SSL — everything configured and hardened for production. Tested on both Ubuntu 22.04 LTS and 24.04 LTS.
This guide walks through a complete Odoo 18 installation on a fresh Ubuntu server. Every step has been tested on both Ubuntu 22.04 LTS (Jammy) and 24.04 LTS (Noble). By the end, you will have Odoo running behind Nginx with SSL, managed by systemd, and hardened for production.
If you want a Docker-based installation instead, see our Docker Compose guide. If you would rather skip the manual setup entirely, OEC.sh deploys Odoo on any cloud provider in under 5 minutes.
Prerequisites
Before starting, make sure you have:
- •Ubuntu 22.04 LTS or 24.04 LTS — a fresh server installation (minimal or standard). Other Ubuntu versions may work but are not covered here.
- •Root or sudo access — you need to install packages and create system users.
- •A domain name pointed at your server's IP — for example,
odoo.yourcompany.com. Set an A record in your DNS provider now, because DNS propagation can take up to an hour. - •At least 2 GB of RAM — Odoo can run on 1 GB for testing, but production needs 2 GB minimum. For worker-based setups with concurrent users, 4 GB or more is recommended. Use our Server Requirements Calculator to size your instance properly.
- •20 GB of disk space — for Odoo source, PostgreSQL data, and the filestore. Plan for more if you expect heavy attachment uploads.
Verify your Ubuntu version:
lsb_release -aYou should see 22.04 or 24.04 in the output.
Install System Dependencies
Odoo 18 requires Python 3.11 or later, PostgreSQL 16, wkhtmltopdf for PDF report rendering, and Node.js for compiling LESS/SCSS assets.
Update the system
sudo apt update && sudo apt upgrade -yInstall Python and build tools
Ubuntu 24.04 ships with Python 3.12. Ubuntu 22.04 ships with Python 3.10, which is too old for Odoo 18. If you are on 22.04, add the deadsnakes PPA:
# Ubuntu 22.04 only — add deadsnakes PPA for Python 3.12
sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt update
sudo apt install -y python3.12 python3.12-venv python3.12-dev# Ubuntu 24.04 — Python 3.12 is already available
sudo apt install -y python3 python3-venv python3-devInstall the build dependencies Odoo needs for compiling Python packages:
sudo apt install -y build-essential libxml2-dev libxslt1-dev \
libevent-dev libpq-dev libldap2-dev libsasl2-dev \
libssl-dev libjpeg-dev libfreetype6-dev zlib1g-dev \
libffi-dev git wget curlInstall PostgreSQL 16
# Add the official PostgreSQL repository
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo apt update
sudo apt install -y postgresql-16Verify PostgreSQL is running:
sudo systemctl status postgresqlInstall wkhtmltopdf
Odoo uses wkhtmltopdf to render HTML reports (invoices, purchase orders, etc.) as PDFs. The version in Ubuntu's default repositories is outdated and missing the patched Qt WebKit that Odoo requires. Install the correct version directly:
# Download the patched wkhtmltopdf (0.12.6.1 for amd64)
wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb
# Install it (will pull in dependencies automatically)
sudo apt install -y ./wkhtmltox_0.12.6.1-3.jammy_amd64.debNote for Ubuntu 24.04: The Jammy .deb file installs cleanly on Noble as well. If you encounter dependency issues, install the missing libraries with sudo apt install -y libssl3 libpng16-16.
Verify the installation:
wkhtmltopdf --version
# Expected: wkhtmltopdf 0.12.6 (with patched qt)Install Node.js
Odoo needs Node.js for compiling SCSS/LESS frontend assets:
sudo apt install -y nodejs npm
sudo npm install -g rtlcssIf you need a more recent Node.js version, use the NodeSource repository, but the default Ubuntu packages work fine for Odoo.
Create Odoo System User and Directory Structure
Never run Odoo as root. Create a dedicated system user:
sudo useradd -m -d /opt/odoo -U -r -s /bin/bash odooThis creates:
- •A system user named
odoo(no login shell for interactive sessions) - •A home directory at
/opt/odoo - •A group also named
odoo
Create the directory structure:
sudo mkdir -p /opt/odoo/{custom-addons,config,logs}
sudo chown -R odoo:odoo /opt/odooThe layout will look like:
/opt/odoo/
├── odoo/ # Odoo source code (from git)
├── venv/ # Python virtual environment
├── custom-addons/ # Your custom and third-party modules
├── config/ # odoo.conf
└── logs/ # Application logsInstall Odoo from Source
Installing from source gives you full control over the version, lets you apply patches, and makes it easy to pull updates. This is the recommended method for production.
Clone the Odoo source
sudo su - odoo
git clone https://www.github.com/odoo/odoo --depth 1 --branch 18.0 /opt/odoo/odooThe --depth 1 flag creates a shallow clone (only the latest commit), saving disk space and download time. Replace 18.0 with 17.0 or 19.0 if you need a different version.
Create a virtual environment and install Python dependencies
# Still as the odoo user
python3.12 -m venv /opt/odoo/venv
source /opt/odoo/venv/bin/activate
pip install --upgrade pip wheel
pip install -r /opt/odoo/odoo/requirements.txtThis will take a few minutes. The requirements.txt pulls in around 80 packages including lxml, Pillow, psycopg2, Werkzeug, and the rest of Odoo's dependency tree.
Exit the odoo user session when done:
deactivate
exitInstall Odoo from APT Package
If you prefer a simpler installation managed by APT (automatic updates, standard Debian packaging), Odoo publishes an official repository.
Trade-off: The APT package is easier to install but harder to customize. You cannot easily patch the source, run multiple versions side-by-side, or use a virtual environment. For production, the source installation above is generally preferred.
# Add Odoo's official GPG key and repository
wget -qO - https://nightly.odoo.com/odoo.key | sudo gpg --dearmor -o /usr/share/keyrings/odoo-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/odoo-archive-keyring.gpg] https://nightly.odoo.com/18.0/nightly/deb/ ./" | sudo tee /etc/apt/sources.list.d/odoo.list
sudo apt update
sudo apt install -y odooThis installs Odoo 18 as a system package, creates the odoo user, installs a default configuration at /etc/odoo/odoo.conf, and sets up a systemd service automatically.
To check the status:
sudo systemctl status odooIf you used the APT method, skip the systemd and directory structure sections below — the package handles those. You should still configure PostgreSQL, Nginx, and production hardening.
Configure PostgreSQL
Odoo needs a PostgreSQL role that can create databases. Create one that matches the odoo system user:
sudo su - postgres
createuser --createdb --no-superuser --no-createrole --pwprompt odooEnter a strong password when prompted. Save this password — you will need it for odoo.conf.
Harden PostgreSQL authentication
Edit the PostgreSQL client authentication file:
sudo nano /etc/postgresql/16/main/pg_hba.confFind the line for local connections and ensure it uses scram-sha-256 (not peer or trust):
# TYPE DATABASE USER ADDRESS METHOD
local all odoo scram-sha-256
host all odoo 127.0.0.1/32 scram-sha-256
host all odoo ::1/128 scram-sha-256If you changed anything, restart PostgreSQL:
sudo systemctl restart postgresqlVerify the connection works:
psql -U odoo -d postgres -h 127.0.0.1 -c "SELECT version();"Configure Odoo
Create the main Odoo configuration file:
sudo nano /opt/odoo/config/odoo.confPaste the following configuration and adjust the values:
[options]
; Database
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = YOUR_STRONG_PASSWORD_HERE
db_name = False
db_maxconn = 64
list_db = False
; Paths
addons_path = /opt/odoo/odoo/addons,/opt/odoo/custom-addons
data_dir = /opt/odoo/.local/share/Odoo
; Security
admin_passwd = CHANGE_THIS_MASTER_PASSWORD
proxy_mode = True
; Workers (production — adjust based on CPU cores)
; Formula: workers = (CPU cores * 2) + 1
workers = 5
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_cpu = 600
limit_time_real = 1200
limit_time_real_cron = -1
limit_request = 8192
; Logging
logfile = /opt/odoo/logs/odoo.log
log_level = warn
log_handler = :WARNING
logrotate = True
; Longpolling (required when workers > 0)
gevent_port = 8072
; Network
http_port = 8069
xmlrpc_interface = 127.0.0.1
netrpc_interface = 127.0.0.1Set the file permissions so only the odoo user can read it (it contains passwords):
sudo chown odoo:odoo /opt/odoo/config/odoo.conf
sudo chmod 640 /opt/odoo/config/odoo.confKey settings explained
- •
proxy_mode = True— required when Odoo sits behind Nginx. Tells Odoo to trustX-Forwarded-*headers for correct IP logging and HTTPS detection. - •
workers = 5— enables multi-process mode. Without this, Odoo runs single-threaded and cannot handle concurrent requests. The formula(CPU * 2) + 1is a reasonable starting point for a 2-core machine. - •
list_db = False— hides the database manager from the web UI. Important for security in production. - •
admin_passwd— the master password for creating/deleting databases via the web UI. Set a strong value or disable database management entirely.
Configure Nginx Reverse Proxy
Nginx handles SSL termination, serves static files efficiently, and proxies requests to Odoo. This is essential for production.
Install Nginx and Certbot
sudo apt install -y nginx certbot python3-certbot-nginxCreate the Nginx server block
sudo nano /etc/nginx/sites-available/odooupstream odoo {
server 127.0.0.1:8069;
}
upstream odoo-chat {
server 127.0.0.1:8072;
}
# Redirect HTTP to HTTPS
server {
listen 80;
server_name odoo.yourcompany.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name odoo.yourcompany.com;
# SSL certificates (managed by Certbot)
ssl_certificate /etc/letsencrypt/live/odoo.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/odoo.yourcompany.com/privkey.pem;
# SSL hardening
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# Security headers
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
# Logging
access_log /var/log/nginx/odoo-access.log;
error_log /var/log/nginx/odoo-error.log;
# Proxy buffers for large Odoo responses
proxy_buffers 16 64k;
proxy_buffer_size 128k;
proxy_read_timeout 900s;
proxy_connect_timeout 900s;
proxy_send_timeout 900s;
# Request size (for file uploads)
client_max_body_size 200m;
# Gzip compression
gzip on;
gzip_types text/css text/plain text/xml application/xml application/json application/javascript;
gzip_min_length 1000;
# Longpolling (live chat, notifications)
location /websocket {
proxy_pass http://odoo-chat;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# All other Odoo traffic
location / {
proxy_pass http://odoo;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
# Static file caching
location ~* /web/static/ {
proxy_pass http://odoo;
proxy_cache_valid 200 90m;
proxy_buffering on;
expires 7d;
add_header Cache-Control "public, no-transform";
}
}Enable the site and obtain SSL
# Enable the site
sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/odoo
sudo rm /etc/nginx/sites-enabled/default
# Test configuration (ignore SSL errors — we have not generated certs yet)
sudo nginx -t
# Get SSL certificate from Let's Encrypt
# First, temporarily comment out the SSL server block and the HTTP redirect,
# add a plain HTTP server block, then run:
sudo certbot --nginx -d odoo.yourcompany.com --non-interactive --agree-tos --email your@email.com
# Certbot will modify the Nginx config to add SSL certificate paths
# and set up automatic renewal
# Verify auto-renewal is working
sudo certbot renew --dry-runRestart Nginx:
sudo systemctl restart nginxSet Up Systemd Service
Create a systemd unit file so Odoo starts automatically on boot and restarts on failure:
sudo nano /etc/systemd/system/odoo.service[Unit]
Description=Odoo 18
Documentation=https://www.odoo.com/documentation/18.0/
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=odoo
Group=odoo
ExecStart=/opt/odoo/venv/bin/python3 /opt/odoo/odoo/odoo-bin \
--config=/opt/odoo/config/odoo.conf
# Restart policy
Restart=on-failure
RestartSec=5s
# Resource limits
LimitNOFILE=65536
LimitNPROC=4096
# Security hardening
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=odoo
[Install]
WantedBy=multi-user.targetEnable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable odoo
sudo systemctl start odooCheck that Odoo is running:
sudo systemctl status odoo
sudo journalctl -u odoo -f --no-pager -n 50You should see Odoo loading modules and listening on port 8069.
Post-Install Verification
With Odoo running behind Nginx with SSL, open your browser and navigate to:
https://odoo.yourcompany.comYou should see the Odoo database creation page (or the login page if list_db = False and you already created a database).
Create your first database
If list_db is set to True (or you access the database manager directly at /web/database/manager):
- Enter the master password (the
admin_passwdfromodoo.conf). - Choose a database name (e.g.,
production). - Set the admin email and password.
- Select your language and country.
- Check “Demo data” only if this is a test instance.
- Click Create Database.
Database creation takes 30–60 seconds. Odoo will install the base modules and redirect you to the home screen.
Verify core functionality
- •Navigate to Settings > General Settings to confirm the admin panel loads.
- •Install the CRM or Sales module to verify module installation works.
- •Go to Settings > Technical > System Parameters and confirm
web.base.urlmatches your domain. - •Print any report to PDF (e.g., a sample invoice) to verify wkhtmltopdf is working.
Production Hardening
A running Odoo instance is only half the job. Production systems need firewall rules, intrusion detection, and log management.
Configure UFW firewall
# Allow SSH, HTTP, HTTPS only
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enableVerify:
sudo ufw status verboseThe Odoo ports (8069, 8072) should NOT be exposed publicly — Nginx proxies all traffic.
Install fail2ban
Protect against brute-force SSH and Odoo login attempts:
sudo apt install -y fail2banCreate a custom Odoo jail:
sudo nano /etc/fail2ban/jail.d/odoo.conf[odoo-login]
enabled = true
port = http,https
filter = odoo-login
logpath = /opt/odoo/logs/odoo.log
maxretry = 5
bantime = 900
findtime = 600Create the filter:
sudo nano /etc/fail2ban/filter.d/odoo-login.conf[Definition]
failregex = ^ \d+ WARNING .* Login failed for db:.* login:.* from <HOST>
ignoreregex =sudo systemctl restart fail2banSet up log rotation
If Odoo's built-in logrotate = True setting is not sufficient, add a system-level logrotate config:
sudo nano /etc/logrotate.d/odoo/opt/odoo/logs/odoo.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
copytruncate
}Enable automatic security updates
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgradesThis ensures your Ubuntu server receives critical security patches without manual intervention.
Common Installation Issues and Fixes
wkhtmltopdf renders blank or broken PDFs
Symptom: PDF reports are empty, garbled, or throw an error about missing fonts.
Fix: The system wkhtmltopdf (from apt install wkhtmltopdf) lacks the patched Qt WebKit. You must install the specific .deb from the wkhtmltopdf GitHub releases as shown in the dependencies section. Also install common fonts:
sudo apt install -y fonts-liberation fonts-dejavu-core fontconfig
sudo fc-cache -f -vLocale errors during installation
Symptom: Errors like locale.Error: unsupported locale setting when Odoo starts.
Fix:
sudo locale-gen en_US.UTF-8
sudo update-locale LANG=en_US.UTF-8
# Log out and back in, or run:
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8Permission denied errors
Symptom: Odoo cannot write to the filestore or log directory.
Fix: Ensure the odoo user owns all relevant directories:
sudo chown -R odoo:odoo /opt/odoo
sudo chown -R odoo:odoo /opt/odoo/.localPostgreSQL connection refused
Symptom: psycopg2.OperationalError: could not connect to server: Connection refused
Fix: Check three things:
- PostgreSQL is running:
sudo systemctl status postgresql - The
db_hostinodoo.confmatches yourpg_hba.confentries. If you use127.0.0.1, thepg_hba.confmust have ahostline for127.0.0.1/32. If you uselocalhost, it might try a Unix socket — use the explicit IP. - The
odooPostgreSQL role exists:sudo -u postgres psql -c "\du"should list theodoorole.
“413 Request Entity Too Large” on file uploads
Symptom: Uploading attachments larger than 1 MB fails with an Nginx error.
Fix: Increase client_max_body_size in the Nginx server block:
client_max_body_size 200m;Then reload Nginx: sudo systemctl reload nginx
Odoo is extremely slow with a single worker
Symptom: Pages take 10+ seconds to load, especially with multiple users.
Fix: You are running in single-process mode. Set workers in odoo.conf to at least (CPU cores * 2) + 1. With workers enabled, Odoo spawns separate processes for handling requests and a gevent process for longpolling on port 8072.
Or Deploy in 5 Minutes with OEC.sh
Everything above — Python, PostgreSQL, Nginx, SSL, systemd, firewall, log rotation — is roughly 45 minutes of work if everything goes perfectly, and a few hours if you hit compatibility issues.
OEC.sh handles all of it:
- Pick your cloud provider — DigitalOcean, AWS, Google Cloud, Azure, Hetzner, Vultr, OVH, or any other provider. No vendor lock-in.
- Choose your Odoo version — 16, 17, 18, or 19. Community or Enterprise.
- Deploy — SSL, backups, monitoring, and updates are configured automatically.
- Free tier available — start without a credit card.
The manual install above is the right choice if you want complete control over every configuration detail. OEC.sh is the right choice if you want to get Odoo running today and focus on your business instead of your infrastructure.
Skip the manual setup
OEC.sh deploys Odoo on any cloud provider with SSL, backups, and monitoring — in under 5 minutes. No server configuration needed.
- Free tier available
- No credit card required
- Any cloud provider
Frequently Asked Questions
What Ubuntu version should I use for Odoo 18?
Ubuntu 24.04 LTS (Noble) is the best choice for new installations. It ships with Python 3.12, which Odoo 18 supports natively without adding third-party PPAs. Ubuntu 22.04 LTS (Jammy) also works but requires adding the deadsnakes PPA for Python 3.11 or 3.12. Both are supported LTS releases with security updates through 2027 (22.04) and 2029 (24.04).
How much RAM does Odoo need on Ubuntu?
Minimum 2 GB for a basic installation with a handful of users. For production with 10–50 concurrent users, plan for 4–8 GB. With workers enabled (which you should always do in production), each Odoo worker process uses 150–300 MB of RAM. The formula is roughly: (number of workers × 250 MB) + 1 GB for PostgreSQL + 512 MB for the OS.
Can I install multiple Odoo versions on the same server?
Yes, if you use the source installation method with separate virtual environments. Create distinct system users (e.g., odoo17, odoo18), clone each version into its own directory, and run them on different ports. Each version needs its own odoo.conf, systemd service, and Nginx upstream block. That said, this gets complex fast — consider Docker containers for multi-version setups.
Should I install Odoo from source or from the APT package?
Install from source if you need fine-grained control: custom patches, specific Python package versions, virtual environments, or side-by-side installations. Install from APT if you want a simpler setup with automatic updates through the package manager. Most production deployments use the source method because it provides more flexibility for upgrades and rollbacks.
How do I update Odoo after installation?
For a source installation: stop the Odoo service, pull the latest changes from the Odoo Git repository (git pull), update pip packages (pip install -r requirements.txt), restart the service, and run the database upgrade if needed (odoo-bin -u all -d your_database --stop-after-init). Always back up your database before upgrading. For APT installations: sudo apt update && sudo apt upgrade odoo.
Is it better to use Docker or a native Ubuntu installation?
Neither is universally better — it depends on your workflow. Native installation gives you direct access to all system components, easier debugging, and no container abstraction layer. Docker gives you reproducible environments, easier rollbacks (swap the image tag), and cleaner multi-service setups. If your team is already comfortable with Docker, use Docker. If you prefer managing services directly on the OS, use the native installation covered in this guide.
Last updated: February 2026. Tested with Odoo 18.0, Ubuntu 22.04.5 LTS, and Ubuntu 24.04.1 LTS.
Deploy Odoo Without the Manual Setup
OEC.sh automates everything in this guide — Python, PostgreSQL, Nginx, SSL, systemd, firewall, and monitoring. Deploy on any cloud provider in under 5 minutes.
Related Resources
Odoo Docker Guide
Complete guide to running Odoo in Docker containers.
Docker Compose for Odoo
Production-ready Docker Compose setup with PostgreSQL and Nginx.
Odoo Docker Hub Reference
Official image tags, versions, and environment variables.
Enterprise vs Community Docker
Run Enterprise or Community Edition with Docker.
Nginx Reverse Proxy Config
Production Nginx config with SSL and websocket support.
Docker Compose Generator
Generate production-ready Docker Compose files visually.
Deploy Odoo on Any Cloud
Step-by-step guide to deploy Odoo on any cloud provider.
Server Requirements Calculator
Calculate the right server size for your Odoo workload.
OEC.sh Pricing
Free tier available. Deploy Odoo without infrastructure hassle.