Skip to content
Self-Hosting Odoo on Ubuntu 24.04: The Complete 2026 Guide
·15 min read·By Hexalian Engineering

Self-Hosting Odoo on Ubuntu 24.04: The Complete 2026 Guide

A production-ready Odoo server installation on Ubuntu 24.04 LTS, from a blank VPS to a hardened, SSL-terminated, monitored Odoo 18 instance. This guide covers Nginx reverse proxy, PostgreSQL tuning, Fail2ban, and automated Let's Encrypt renewal.

Prerequisites

Before starting, you need:

This guide targets Odoo 18 Community Edition. The same steps apply to Odoo 17 with minor version number changes.


1. System Preparation

# Update system packages
sudo apt update && sudo apt upgrade -y

# Install dependencies
sudo apt install -y python3-pip python3-dev python3-venv   python3-wheel libxml2-dev libpq-dev libjpeg8-dev liblcms2-dev   libxslt1-dev zlib1g-dev libsasl2-dev libldap2-dev build-essential   git libssl-dev libffi-dev libmysqlclient-dev libjpeg-dev   libblas-dev libatlas-base-dev npm nodejs wkhtmltopdf

# Install wkhtmltopdf (required for PDF generation)
# Ubuntu 24.04 includes a version that works with Odoo 18
sudo ln -sf /usr/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf

2. PostgreSQL Installation and Configuration

sudo apt install -y postgresql postgresql-contrib

# Create Odoo PostgreSQL user
sudo -u postgres createuser --createdb --no-createrole --no-superuser odoo18

# Set password
sudo -u postgres psql -c "ALTER USER odoo18 PASSWORD 'your_strong_db_password';"

PostgreSQL Performance Tuning

For a 4GB RAM server, add these settings to /etc/postgresql/16/main/postgresql.conf:

# Memory settings
shared_buffers = 1GB           # 25% of RAM
effective_cache_size = 3GB     # 75% of RAM
work_mem = 16MB                # Per-sort / per-hash operation
maintenance_work_mem = 256MB   # For VACUUM, CREATE INDEX

# Query planner
default_statistics_target = 100
random_page_cost = 1.1         # For SSD storage; use 4.0 for HDD

# Checkpoints
checkpoint_completion_target = 0.9
wal_buffers = 16MB

# Connection settings
max_connections = 100
sudo systemctl restart postgresql

3. Create Odoo System User

sudo adduser --system --home=/opt/odoo18 --group odoo18

4. Install Odoo 18

# Clone Odoo Community Edition
sudo git clone --depth=1 --branch=18.0   https://github.com/odoo/odoo.git /opt/odoo18/odoo

# Create virtual environment
sudo -u odoo18 python3 -m venv /opt/odoo18/venv

# Install Python dependencies
sudo -u odoo18 /opt/odoo18/venv/bin/pip install   --upgrade pip setuptools wheel
sudo -u odoo18 /opt/odoo18/venv/bin/pip install   -r /opt/odoo18/odoo/requirements.txt

# Create addons and config directories
sudo -u odoo18 mkdir /opt/odoo18/addons
sudo -u odoo18 mkdir /opt/odoo18/config
sudo -u odoo18 mkdir /opt/odoo18/data

5. Odoo Configuration File

Create /opt/odoo18/config/odoo18.conf:

[options]
; Administration
admin_passwd = your_master_password_here
db_host = 127.0.0.1
db_port = 5432
db_user = odoo18
db_password = your_strong_db_password

; Paths
addons_path = /opt/odoo18/odoo/addons,/opt/odoo18/addons
data_dir = /opt/odoo18/data

; Performance
workers = 4                    ; Number of worker processes (CPU count × 2)
max_cron_threads = 1
limit_memory_hard = 2684354560 ; 2.5GB hard limit per worker
limit_memory_soft = 2147483648 ; 2GB soft limit per worker
limit_time_cpu = 600
limit_time_real = 1200
limit_request = 8192

; Logging
logfile = /var/log/odoo18/odoo18.log
log_level = warn

; Network (Nginx handles HTTPS upstream)
proxy_mode = True
xmlrpc_port = 8069
longpolling_port = 8072

6. Systemd Service

Create /etc/systemd/system/odoo18.service:

[Unit]
Description=Odoo 18 Community
Requires=postgresql.service
After=network.target postgresql.service

[Service]
Type=simple
SyslogIdentifier=odoo18
PermissionsStartOnly=true
User=odoo18
Group=odoo18
ExecStart=/opt/odoo18/venv/bin/python3   /opt/odoo18/odoo/odoo-bin   --config=/opt/odoo18/config/odoo18.conf

StandardOutput=journal+console

[Install]
WantedBy=multi-user.target
sudo mkdir /var/log/odoo18
sudo chown odoo18:odoo18 /var/log/odoo18

sudo systemctl daemon-reload
sudo systemctl enable odoo18
sudo systemctl start odoo18
sudo systemctl status odoo18

7. Nginx Reverse Proxy with SSL

sudo apt install -y nginx certbot python3-certbot-nginx

Create /etc/nginx/sites-available/odoo18.conf:

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name odoo.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name odoo.yourdomain.com;

    # SSL (managed by certbot after initial setup)
    ssl_certificate /etc/letsencrypt/live/odoo.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/odoo.yourdomain.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    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;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options SAMEORIGIN always;
    add_header X-Content-Type-Options nosniff always;
    add_header Referrer-Policy strict-origin-when-cross-origin always;

    # Proxy to Odoo
    location / {
        proxy_pass http://127.0.0.1:8069;
        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_read_timeout 720s;
        proxy_connect_timeout 720s;
        proxy_send_timeout 720s;
        client_max_body_size 100m;
    }

    # Longpolling for real-time features (chat, IoT)
    location /longpolling {
        proxy_pass http://127.0.0.1:8072;
        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;
    }

    # Cache static assets
    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        proxy_pass http://127.0.0.1:8069;
        proxy_set_header Host $host;
        expires 7d;
        add_header Cache-Control "public, immutable";
    }
}
sudo ln -s /etc/nginx/sites-available/odoo18.conf /etc/nginx/sites-enabled/
sudo nginx -t

# Issue SSL certificate
sudo certbot --nginx -d odoo.yourdomain.com

sudo systemctl reload nginx

8. Fail2ban for Brute Force Protection

sudo apt install -y fail2ban

Create /etc/fail2ban/jail.d/odoo18.conf:

[odoo18]
enabled = true
port = http,https
backend = auto
filter = odoo18
logpath = /var/log/odoo18/odoo18.log
maxretry = 10
findtime = 600
bantime = 3600

Create /etc/fail2ban/filter.d/odoo18.conf:

[Definition]
failregex = ^.*Login attempt from <HOST> failed for.*$
            ^.*Login failed for.*from <HOST>.*$
ignoreregex =
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban
sudo fail2ban-client status odoo18

9. Automated Backups

Create /opt/odoo18/scripts/backup.sh:

#!/bin/bash
BACKUP_DIR="/opt/odoo18/backups"
DATE=$(date +%Y%m%d_%H%M%S)
DB_NAME="your_odoo_database"

mkdir -p "$BACKUP_DIR"

# Database backup
pg_dump -U odoo18 -h 127.0.0.1 "$DB_NAME" | gzip >   "$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"

# Data directory backup (filestore, sessions)
tar -czf "$BACKUP_DIR/filestore_${DATE}.tar.gz"   /opt/odoo18/data/filestore/

# Remove backups older than 30 days
find "$BACKUP_DIR" -name "*.gz" -mtime +30 -delete

echo "Backup completed: ${DATE}"
chmod +x /opt/odoo18/scripts/backup.sh

# Schedule daily backup at 2 AM
echo "0 2 * * * odoo18 /opt/odoo18/scripts/backup.sh >> /var/log/odoo18/backup.log 2>&1"   | sudo tee -a /etc/crontab

10. Monitoring with Odoo's Built-in Tools

Once running, check performance via:

For external monitoring, consider:

Common Issues

wkhtmltopdf returns blank PDFs: Ubuntu 24.04's wkhtmltopdf may require Xvfb for headless rendering on servers without a display. Install:

sudo apt install xvfb
# Then configure wkhtmltopdf path in Odoo settings to use xvfb-run wrapper

Worker OOM kills: Increase limit_memory_hard in odoo.conf, or reduce workers count. Monitor with journalctl -u odoo18 -f.

Slow module list loading: Run UPDATE ir_module_module SET state = 'uninstalled' WHERE state = 'to remove'; in psql if you have residual module states after failed installs.


Need help with a complex Odoo infrastructure setup? Hexalian's infrastructure hardening service covers production server setup, security hardening, and disaster recovery for Odoo deployments.

Browse Odoo modules at hexalian.com/store or run a free Odoo health scan at nonaguard.com (7-day trial).

Running Odoo in production?

Get Odoo modules with full source code, or scan your instance for security and performance issues in under a minute.

Try NonaGuard Free (7 days)Browse ModulesContact

Recommended Odoo Modules

E-commerce Suite All-in-One - 10+ Features Odoo
E-commerce Suite All-in-One - 10+ Features Odoo
From $160.99 · Website
View
Recently Viewed Products - Browsing History Odoo
Recently Viewed Products - Browsing History Odoo
From $10.99 · Website/Website
View
NonaGuard — Odoo Security Audit & Health Monitor
NonaGuard — Odoo Security Audit & Health Monitor
Free · Technical
View