Skip to main contentSkip to navigation
[email protected]
Client AreaSupport
Hosting Mammoth
HostingMammothYour Data, Our Responsibility
Home
Solutions
Hosting Services
Store
Pricing
About
Blog
API
Contact

Stay Ahead of the Curve

Get the latest insights on cybersecurity, AI innovations, and enterprise data solutions delivered to your inbox.

Hosting Mammoth
HostingMammothEnterprise Solutions

Enterprise-grade data solutions. Hosting, recovery, cybersecurity, and AI-powered services for businesses worldwide.

[email protected]
Sun - Fri, 9:00am - 5:00pm

Services

  • Cloud Hosting
  • Data Recovery
  • Cybersecurity
  • Legal Support
  • MSP Services
  • Web Development
  • AI Services
  • Free Server Migration

Hosting

  • VPS Hosting (NVMe SSD)
  • VDS Hosting (NVMe)
  • Storage VPS (High SSD)
  • GPU Servers
  • Managed Services
  • Cloud Firewall
  • Load Balancer
  • One-Click Apps
  • n8n Hosting
  • Object Storage
  • FAQ

Company

  • Store
  • Pricing
  • About Us
  • Locations
  • Blog
  • Testimonials
  • Contact
  • Affiliate Program
  • White-Label
  • Terms of Service
  • Privacy Policy
  • Browser Cookies
  • SLA

Support

  • Client Area
  • Submit Ticket
  • Knowledge Base
  • Server Status
  • API Documentation

© 2026 Hosting Mammoth. All rights reserved.

Knowledge Base
Getting StartedAccount ManagementVPS HostingGPU ServersStorage VPSCloud FirewallLoad BalancerServer ManagementBilling & PaymentsSupport & TicketsAffiliate ProgramReseller ProgramMarketplace & Appsn8n HostingManaged ServicesServer MigrationAPI & DevelopersSecurityTroubleshootingGlossaryInstall Guides
  1. Home
  2. /
  3. Support
  4. /
  5. Install Guides
  6. /
  7. How To Install Odoo Ubuntu
GUIDEInstall Guides

How to Install Odoo 17 on Ubuntu 24.04 VPS: Self-Hosted Open-Source ERP

27 min read

How to Install Odoo 17 on Ubuntu 24.04 VPS: Self-Hosted Open-Source ERP

Deploying Odoo on your own VPS gives you a full enterprise resource planning platform — CRM, Sales, Inventory, Accounting, HR, Website, eCommerce, Manufacturing — running on infrastructure you control, with no per-user SaaS fees and no vendor lock-in. This guide walks you through installing Odoo 17 Community Edition on Ubuntu 24.04 from source, with PostgreSQL 16, a hardened systemd service, Nginx reverse proxy with WebSocket support for longpolling, and Let's Encrypt TLS.

Prefer a managed platform? If you want an Odoo-ready VPS with PostgreSQL tuned and Nginx pre-configured, deploy in minutes on our CloudCore Business plan and follow this guide straight through to a production-grade install.

Table of Contents

  • What is Odoo?
  • Why Self-Host Odoo on Your VPS?
  • Prerequisites
  • Step 1: Update System Packages and Install Dependencies
  • Step 2: Install PostgreSQL 16 and Create the Odoo Role
  • Step 3: Install wkhtmltopdf 0.12.6 (Patched Qt)
  • Step 4: Create the Odoo System User and Directory Layout
  • Step 5: Clone Odoo 17 from GitHub
  • Step 6: Create a Python Virtual Environment and Install Requirements
  • Step 7: Create the odoo.conf Configuration File
  • Step 8: Create the systemd Unit
  • Step 9: Configure Nginx as a Reverse Proxy with WebSocket Support
  • Step 10: Obtain a Let's Encrypt TLS Certificate
  • Step 11: Create Your First Database and Install Apps
  • Post-Install: Custom Addons and OCA Modules
  • Multi-Database Setup and Database Filtering
  • Daily Backups (PostgreSQL + Filestore)
  • Updating Odoo
  • Troubleshooting
  • FAQ
  • Next Steps
  • What is Odoo?

    Odoo is a modular open-source business management suite that competes directly with SAP, Oracle NetSuite, and Microsoft Dynamics. Originally released in 2005 as TinyERP, it has grown into a platform of more than 40 official modules plus thousands of community-maintained apps, all built on a single Python/PostgreSQL core with a consistent data model and ORM.

    The modular architecture is what makes Odoo stand out. You install only the modules your business needs and they work together natively. CRM captures leads and tracks the sales pipeline; Sales turns quotes into orders that flow directly into Inventory for picking and shipping; stock moves automatically generate journal entries in Accounting; HR manages employees, time off, payroll, and expenses; Website and eCommerce run your public site and online store against the same product catalog; Manufacturing handles MRP, work orders, and bills of materials; Project tracks tasks and timesheets that feed back into invoicing. There is no integration layer to maintain — every module reads and writes the same database tables.

    The Community Edition is released under the LGPLv3 license, which means you can self-host it, modify it, and use it commercially without paying Odoo SA a cent. Enterprise Edition adds features like Studio (low-code app builder), Accounting full localizations, and official mobile apps, but Community covers the core functionality that most small and medium businesses actually use day to day. The full Odoo 17 documentation is publicly available and thorough.

    Typical deployments range from a solo consultant using CRM and Invoicing, to a 200-person distributor running CRM + Sales + Inventory + Accounting + Purchase + Manufacturing, to a SaaS provider hosting dozens of isolated Odoo databases for their customers. The same stack scales from 1 user to several hundred on a properly sized VPS.

    Why Self-Host Odoo on Your VPS?

    Running Odoo on your own Ubuntu server instead of paying for Odoo.sh or Odoo Online — or worse, licensing SAP Business One or NetSuite — comes with concrete benefits:

    • Zero per-user licensing fees — Odoo Community is free forever. Odoo Online charges roughly EUR 24 per user per month, and SAP Business One or NetSuite routinely run upwards of EUR 100 per user per month plus implementation fees. A 20-person team saves EUR 5,000+ per year versus Odoo Online alone, and tens of thousands versus legacy ERPs.
    • Full data ownership — your customer list, invoices, inventory, and financial records stay on a server you control. No data is transmitted to a third-party ERP vendor. This is essential for regulated industries and GDPR-sensitive EU businesses.
    • Unlimited custom modules — you can install any OCA (Odoo Community Association) module, write your own, or fork existing ones. Odoo.sh restricts what you can deploy; self-hosting does not.
    • No user count caps or artificial limits — add staff without the accountant flinching. Create dozens of databases for sandboxing or multi-company setups without extra fees.
    • Database-level access — direct PostgreSQL access lets you run complex SQL reports, build Metabase or Grafana dashboards on live data, or replicate to a warehouse. SaaS Odoo does not expose the database.
    • Predictable cost — one VPS monthly invoice covers everything. No surprise overages when you onboard a new team.
    • Hardware flexibility — scale vertically by moving to a larger VPS or horizontally by splitting the web and database tiers. You choose the infrastructure.

    Cost Comparison: Self-Hosted Odoo vs. SaaS ERP

    Scenario (20 users)SAP Business OneNetSuiteOdoo OnlineSelf-Hosted Odoo (VPS)
    Monthly cost~EUR 2,000+~EUR 2,500+~EUR 480EUR 29.99/mo (flat)
    Per-user feeYesYesYes (EUR 24/user)No
    ImplementationEUR 20k+EUR 30k+LowDIY or partner
    Custom modulesExpensive addonsLimitedRestrictedUnlimited
    Data ownershipVendor-hostedVendor-hostedVendor-hostedYours
    Typical 3-year TCOEUR 90k+EUR 120k+~EUR 17k~EUR 1.1k
    For almost any SMB with more than a handful of users, self-hosted Odoo pays for itself in the first month.

    Prerequisites

    Before you start, make sure you have:

    • A VPS running Ubuntu 24.04 LTS with root or sudo access
    • SSH access to the server
    • At least 4 GB of RAM (8 GB recommended for 10+ concurrent users)
    • At least 40 GB of disk space (filestore and database grow with attachments)
    • A domain name pointed at the VPS IP (for TLS — optional, but strongly recommended)
    • Ports 80 and 443 open in your firewall for Nginx and Let's Encrypt
    Recommended Plan: CloudCore Business
    >
    For a production Odoo install serving a small team, we recommend the CloudCore Business plan:
    >
    - 6 vCPU cores
    - 16 GB RAM
    - 200 GB NVMe SSD
    - Unmetered bandwidth
    >
    This comfortably handles Odoo + PostgreSQL + Nginx on one box with room for 20–40 concurrent users and 2–4 worker processes. For larger teams or multi-tenant deployments, scale up vCPU and RAM before splitting tiers.

    Connect to your server:

    bash
    ssh root@your-server-ip

    Step 1: Update System Packages and Install Dependencies

    Start by refreshing the package index and installing the build tools and libraries Odoo needs to compile its Python dependencies.

    bash
    sudo apt update && sudo apt upgrade -y

    Install the system packages:

    bash
    sudo apt install -y git python3 python3-pip python3-dev python3-venv \
      build-essential wget curl nodejs npm \
      libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev libtiff5-dev \
      libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev liblcms2-dev \
      libwebp-dev libharfbuzz-dev libfribidi-dev libxcb1-dev libpq-dev \
      libffi-dev libssl-dev

    Install the rtlcss npm package, which Odoo uses to generate right-to-left CSS (required for Arabic, Hebrew, and similar locales):

    bash
    sudo npm install -g rtlcss

    Step 2: Install PostgreSQL 16 and Create the Odoo Role

    Odoo 17 officially supports PostgreSQL 12 through 16. We'll install PostgreSQL 16 from Ubuntu's default repositories.

    bash
    sudo apt install -y postgresql postgresql-contrib

    Check that the service is running:

    bash
    sudo systemctl status postgresql

    Expected output:

    text
    ● postgresql.service - PostgreSQL RDBMS
         Loaded: loaded (/lib/systemd/system/postgresql.service; enabled; preset: enabled)
         Active: active (exited) since Wed 2026-04-16 10:00:00 UTC; 5s ago

    Create a PostgreSQL role that matches the Linux system user we'll create in Step 4. Odoo connects to PostgreSQL using peer authentication when the DB and app are on the same host, so the PostgreSQL role name must equal the OS user name.

    bash
    sudo -u postgres createuser --createdb --username postgres --no-createrole --no-superuser --pwprompt odoo17

    You will be prompted to set a password for the odoo17 role. Choose a strong password and keep it handy — you'll put it in odoo.conf in Step 7.

    The --createdb flag lets the odoo17 role create new databases, which is how Odoo's database manager creates fresh tenants. The role intentionally is not a superuser — it only has the permissions it needs.

    For a deeper look at PostgreSQL tuning, see our PostgreSQL install guide.

    Step 3: Install wkhtmltopdf 0.12.6 (Patched Qt)

    Odoo uses wkhtmltopdf to render PDF reports (invoices, quotes, delivery slips). It must be version 0.12.6 or later built against a patched Qt — the regular Ubuntu package is built against unpatched Qt and will produce broken headers and footers.

    Download and install the official .deb package:

    bash
    cd /tmp
    wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb
    sudo apt install -y ./wkhtmltox_0.12.6.1-3.jammy_amd64.deb
    The jammy (22.04) build also works correctly on Ubuntu 24.04 (noble). The wkhtmltopdf project did not publish a separate noble build as of this writing.

    Verify the version:

    bash
    wkhtmltopdf --version

    Expected output:

    text
    wkhtmltopdf 0.12.6.1 (with patched qt)

    The (with patched qt) suffix is the important part — if you see anything else, Odoo reports will have layout issues.

    Step 4: Create the Odoo System User and Directory Layout

    Create a dedicated non-login system user to run the Odoo service. Running Odoo as root is a security mistake.

    bash
    sudo useradd -m -d /opt/odoo17 -U -r -s /bin/bash odoo17

    Flag breakdown:

    • -m -d /opt/odoo17 — create the home directory at /opt/odoo17
    • -U — create a group with the same name
    • -r — system account (UID below 1000, no expiration)
    • -s /bin/bash — shell is needed because we'll su into this account to run git and pip
    Create the log directory:

    bash
    sudo mkdir -p /var/log/odoo17
    sudo chown odoo17:odoo17 /var/log/odoo17

    Create the custom addons directory (we'll use this in the Post-Install section):

    bash
    sudo mkdir -p /opt/odoo17/custom-addons
    sudo chown odoo17:odoo17 /opt/odoo17/custom-addons

    Step 5: Clone Odoo 17 from GitHub

    Switch to the odoo17 user and clone the Odoo 17 branch. A shallow clone (--depth 1) saves several gigabytes and cuts the download time dramatically.

    bash
    sudo su - odoo17
    bash
    git clone --depth 1 --branch 17.0 https://github.com/odoo/odoo.git /opt/odoo17/odoo

    Expected output:

    text
    Cloning into '/opt/odoo17/odoo'...
    remote: Enumerating objects: 45120, done.
    remote: Counting objects: 100% (45120/45120), done.
    remote: Compressing objects: 100% (36521/36521), done.
    remote: Total 45120 (delta 12103), reused 21456 (delta 6342), pack-reused 0
    Receiving objects: 100% (45120/45120), 312.45 MiB | 48.21 MiB/s, done.
    Resolving deltas: 100% (12103/12103), done.
    Updating files: 100% (42103/42103), done.

    The full clone (without --depth 1) is around 4 GB; the shallow clone is closer to 400 MB.

    Step 6: Create a Python Virtual Environment and Install Requirements

    Still as the odoo17 user, create an isolated Python virtual environment so Odoo's dependencies don't collide with system Python packages.

    bash
    python3 -m venv /opt/odoo17/venv
    source /opt/odoo17/venv/bin/activate

    Upgrade pip and install Odoo's requirements:

    bash
    pip install --upgrade pip wheel
    pip install -r /opt/odoo17/odoo/requirements.txt

    This step compiles several native extensions (psycopg2, lxml, Pillow, python-ldap) and typically takes 3–8 minutes depending on CPU. If a package fails to compile, the most common cause is a missing system library — re-check Step 1.

    When the install finishes, exit the odoo17 shell back to your sudo user:

    bash
    exit

    Step 7: Create the odoo.conf Configuration File

    Create the configuration file that Odoo reads at startup:

    bash
    sudo tee /etc/odoo17.conf > /dev/null <<'EOF'
    [options]
    ; Admin master password — required to create, restore, or drop databases
    ; Generate a strong one: openssl rand -base64 32
    admin_passwd = CHANGE_THIS_TO_A_LONG_RANDOM_STRING

    ; PostgreSQL connection db_host = False db_port = False db_user = odoo17 db_password = CHANGE_THIS_TO_THE_DB_PASSWORD_FROM_STEP_2

    ; Addons path — built-in Odoo modules + our custom folder addons_path = /opt/odoo17/odoo/addons,/opt/odoo17/custom-addons

    ; Data & log locations data_dir = /opt/odoo17/data logfile = /var/log/odoo17/odoo17.log log_level = info

    ; Networking xmlrpc_port = 8069 longpolling_port = 8072 proxy_mode = True

    ; Workers — multiprocessing mode for production ; Formula: workers = (2 * CPU_cores) + 1, capped by RAM workers = 3

    ; Per-worker memory limits (bytes) — prevents runaway requests from OOMing the box limit_memory_soft = 2147483648 limit_memory_hard = 2684354560

    ; Per-request CPU/wall time limits (seconds) limit_time_cpu = 600 limit_time_real = 1200

    ; Database listing — disable in production to prevent DB enumeration from the login page list_db = False EOF

    Secure the file — it contains two secrets:

    bash
    sudo chown odoo17:odoo17 /etc/odoo17.conf
    sudo chmod 640 /etc/odoo17.conf

    Create the data directory referenced in the config:

    bash
    sudo mkdir -p /opt/odoo17/data
    sudo chown odoo17:odoo17 /opt/odoo17/data

    Key settings explained:

    • admin_passwd — master password that protects the /web/database/manager endpoint. Anyone with this password can create, drop, or restore any database. Treat it like a root password.
    • proxy_mode = True — tells Odoo to honor X-Forwarded-For and X-Forwarded-Proto headers from Nginx so it knows the real client IP and scheme. Required when running behind a reverse proxy.
    • workers = 3 — starts Odoo in multiprocessing mode with 3 HTTP workers plus one cron worker. On a 6 vCPU / 16 GB RAM box, 3–4 workers is the sweet spot. Setting workers = 0 runs Odoo in threaded mode (dev only — not suitable for production).
    • longpolling_port = 8072 — a second HTTP port that handles long-poll/WebSocket connections for the chatter, live notifications, and Discuss. Nginx must proxy this port separately.
    • limit_memory_hard — the hard cap; a worker exceeding this is killed and respawned by the master. Set to ~2.5 GB per worker on a 16 GB server to leave headroom for PostgreSQL and the OS.
    • list_db = False — hides the database selector on the login page. Combined with dbfilter, this means end users never see other tenants' database names.

    Step 8: Create the systemd Unit

    Create a systemd service so Odoo starts on boot and restarts on failure.

    bash
    sudo tee /etc/systemd/system/odoo17.service > /dev/null <<'EOF'
    [Unit]
    Description=Odoo 17 Community
    Documentation=https://www.odoo.com/documentation/17.0/
    Requires=postgresql.service
    After=network.target postgresql.service

    [Service] Type=simple User=odoo17 Group=odoo17 ExecStart=/opt/odoo17/venv/bin/python3 /opt/odoo17/odoo/odoo-bin -c /etc/odoo17.conf StandardOutput=journal+console Restart=on-failure RestartSec=5s

    ; Hardening NoNewPrivileges=true PrivateTmp=true ProtectSystem=full ProtectHome=read-only ReadWritePaths=/opt/odoo17 /var/log/odoo17

    [Install] WantedBy=multi-user.target EOF

    Reload systemd, enable the service so it survives reboots, and start it:

    bash
    sudo systemctl daemon-reload
    sudo systemctl enable odoo17
    sudo systemctl start odoo17

    Check status:

    bash
    sudo systemctl status odoo17

    Expected output (abbreviated):

    text
    ● odoo17.service - Odoo 17 Community
         Loaded: loaded (/etc/systemd/system/odoo17.service; enabled; preset: enabled)
         Active: active (running) since Wed 2026-04-16 10:30:00 UTC; 5s ago
       Main PID: 12345 (python3)
          Tasks: 5 (limit: 19128)
         Memory: 185.0M
            CPU: 2.134s
         CGroup: /system.slice/odoo17.service
                 ├─12345 /opt/odoo17/venv/bin/python3 /opt/odoo17/odoo/odoo-bin -c /etc/odoo17.conf
                 ├─12346 odoo: worker cron 0
                 ├─12347 odoo: worker 0
                 ├─12348 odoo: worker 1
                 └─12349 odoo: worker 2

    Tail the log to confirm there are no errors:

    bash
    sudo tail -f /var/log/odoo17/odoo17.log

    You should see HTTP service (werkzeug) running on 0.0.0.0:8069 followed by worker startup messages.

    Step 9: Configure Nginx as a Reverse Proxy with WebSocket Support

    Odoo listens on ports 8069 (HTTP) and 8072 (longpolling). You never expose these directly — Nginx sits in front, terminates TLS, and proxies to both ports.

    Install Nginx:

    bash
    sudo apt install -y nginx

    Our Nginx install guide has a full walkthrough of hardening and tuning if you want to go deeper.

    Create the Odoo site config:

    bash
    sudo tee /etc/nginx/sites-available/odoo17 > /dev/null <<'EOF'
    

    Upstreams — Odoo multi-process

    upstream odoo_backend { server 127.0.0.1:8069; } upstream odoo_longpoll { server 127.0.0.1:8072; }

    Redirect HTTP to HTTPS (Certbot will replace this after TLS is installed)

    server { listen 80; server_name odoo.yourdomain.com; return 301 https://$host$request_uri; }

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

    # TLS certs (filled in by Certbot in Step 10) ssl_certificate /etc/letsencrypt/live/odoo.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/odoo.yourdomain.com/privkey.pem;

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

    # Large uploads (product images, attachments) client_max_body_size 200m;

    # Proxy timeouts — some Odoo operations (imports, installs) are slow proxy_read_timeout 720s; proxy_connect_timeout 720s; proxy_send_timeout 720s;

    # Forward real client info 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;

    # Gzip compression gzip on; gzip_min_length 1000; gzip_types text/xml text/plain text/css application/xml application/xhtml+xml application/rss+xml application/atom+xml application/json application/javascript application/x-javascript text/javascript image/svg+xml;

    # Longpolling / WebSocket — chatter, live notifications, Discuss location /websocket { proxy_pass http://odoo_longpoll; proxy_http_version 1.1; 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; } location /longpolling { proxy_pass http://odoo_longpoll; }

    # Cache static assets aggressively location ~* /web/static/ { proxy_cache_valid 200 90m; proxy_buffering on; expires 864000; proxy_pass http://odoo_backend; }

    # Everything else → Odoo HTTP workers location / { proxy_pass http://odoo_backend; } } EOF

    Enable the site, remove the default, and test the config:

    bash
    sudo ln -s /etc/nginx/sites-available/odoo17 /etc/nginx/sites-enabled/
    sudo rm -f /etc/nginx/sites-enabled/default
    sudo nginx -t

    Don't reload Nginx yet — the TLS certs referenced in the config don't exist. Certbot will handle that in the next step.

    Step 10: Obtain a Let's Encrypt TLS Certificate

    Install Certbot and the Nginx plugin:

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

    Temporarily comment out the two ssl_certificate* lines in /etc/nginx/sites-available/odoo17 and the listen 443 ssl http2; line (or change it to listen 80; on a different server_name), reload Nginx, then run Certbot. Alternatively, use the standalone mode by stopping Nginx briefly:

    bash
    sudo systemctl stop nginx
    sudo certbot certonly --standalone -d odoo.yourdomain.com \
      --non-interactive --agree-tos -m [email protected]
    sudo systemctl start nginx
    sudo nginx -t && sudo systemctl reload nginx

    Expected Certbot output:

    text
    Successfully received certificate.
    Certificate is saved at: /etc/letsencrypt/live/odoo.yourdomain.com/fullchain.pem
    Key is saved at:         /etc/letsencrypt/live/odoo.yourdomain.com/privkey.pem
    This certificate expires on 2026-07-15.

    Certbot installs a systemd timer that auto-renews certificates before expiry — verify:

    bash
    sudo systemctl list-timers | grep certbot

    See our dedicated Let's Encrypt with Certbot guide for alternative ACME clients (Caddy, acme.sh) and wildcard DNS-01 setups.

    Visit https://odoo.yourdomain.com in your browser — you should now see the Odoo database manager page.

    Step 11: Create Your First Database and Install Apps

    Navigate to https://odoo.yourdomain.com/web/database/manager. You will see a form asking for:

    • Master Password — the admin_passwd value from /etc/odoo17.conf
    • Database Name — e.g. acme_prod (lowercase, underscores, no spaces)
    • Email — the first admin user's login
    • Password — the first admin user's password
    • Language / Country — used for default localization (chart of accounts, tax rules, date formats)
    • Demo data — uncheck for production
    Click Create database. Odoo will initialize the schema, which takes 30–90 seconds. When it finishes, you'll be redirected to the Apps screen logged in as the admin user.

    Install Core Apps

    From the Apps menu, remove the Apps filter chip (which hides technical modules by default) and install the apps you need. Good starting points:

    • CRM — lead and opportunity management
    • Sales — quotations, sales orders, customer portal
    • Invoicing — if you only need billing without the full Accounting module
    • Inventory — stock, warehouses, transfers
    • Purchase — supplier orders and bills
    • Accounting — full GL, reconciliation, localized chart of accounts (Community version has limitations vs Enterprise)
    • Website + eCommerce — public-facing site and online store
    • Employees + Time Off + Expenses — HR basics
    Each install takes 10–60 seconds and may pull in dependent modules automatically.

    Once your database works end to end, lock down database operations — go to the database manager URL, note that the list_db = False setting already hides databases on the login screen, and make sure your admin_passwd is a long random string (not the default).

    Post-Install: Custom Addons and OCA Modules

    The real power of self-hosted Odoo is the module ecosystem. The Odoo Community Association (OCA) maintains hundreds of high-quality free modules on GitHub.

    Install an OCA Repository

    Switch to the odoo17 user and clone the repo into the custom addons folder. Example — account-financial-reports, which adds General Ledger, Aged Partner Balance, Trial Balance, and other reports that Community edition lacks:

    bash
    sudo su - odoo17
    cd /opt/odoo17/custom-addons
    git clone --depth 1 --branch 17.0 https://github.com/OCA/account-financial-reports.git

    Install the OCA repo's Python dependencies (most have a requirements.txt):

    bash
    source /opt/odoo17/venv/bin/activate
    pip install -r /opt/odoo17/custom-addons/account-financial-reports/requirements.txt 2>/dev/null || true
    exit

    Restart Odoo and update the app list from Apps → Update Apps List:

    bash
    sudo systemctl restart odoo17

    The new modules now appear in the Apps screen and install like any built-in module.

    Writing Your Own Module

    Create a new module skeleton inside /opt/odoo17/custom-addons/my_module/ with an __init__.py, __manifest__.py, and the usual models/, views/, security/ folders. After saving, restart Odoo and Update Apps List. The Odoo developer tutorial walks through a full custom module step by step.

    Multi-Database Setup and Database Filtering

    Odoo can host multiple isolated databases on the same server — useful for dev/staging/prod separation, multi-company setups with distinct legal entities, or SaaS-style customer hosting.

    Create additional databases via the /web/database/manager URL. To route different domains to different databases, use the dbfilter option in odoo.conf:

    ini
    ; Match database name to subdomain — e.g. acme.yourdomain.com → acme database
    dbfilter = ^%d$
    list_db = False

    The %d placeholder expands to the first component of the Host header. A request to acme.yourdomain.com only loads the acme database; globex.yourdomain.com only loads globex. Combined with list_db = False, users can never see or access any database except the one mapped to their hostname.

    Point multiple subdomains at the same VPS (A records in DNS) and add them as server_name entries in the Nginx config. Odoo handles the rest.

    Daily Backups (PostgreSQL + Filestore)

    Odoo data lives in two places:

  • PostgreSQL database — all structured data (records, relationships, views)
  • Filestore — attachments, product images, document uploads, at /opt/odoo17/data/filestore/<db_name>/
  • You must back up both for a restore to work. Backing up only the database leaves you with dangling attachment references.

    Create a backup script:

    bash
    sudo tee /usr/local/bin/odoo-backup.sh > /dev/null <<'EOF'
    #!/bin/bash
    set -euo pipefail

    BACKUP_DIR="/var/backups/odoo17" TIMESTAMP=$(date +%Y%m%d-%H%M%S) RETENTION_DAYS=14 DATABASES=$(sudo -u postgres psql -tAc "SELECT datname FROM pg_database WHERE datistemplate = false AND datname NOT IN ('postgres');")

    mkdir -p "$BACKUP_DIR"

    for DB in $DATABASES; do echo "Backing up $DB..." # 1. PostgreSQL dump sudo -u postgres pg_dump -Fc "$DB" > "$BACKUP_DIR/${DB}-${TIMESTAMP}.dump" # 2. Filestore tarball if [ -d "/opt/odoo17/data/filestore/$DB" ]; then tar -czf "$BACKUP_DIR/${DB}-filestore-${TIMESTAMP}.tar.gz" \ -C /opt/odoo17/data/filestore "$DB" fi done

    Prune old backups

    find "$BACKUP_DIR" -type f -mtime +$RETENTION_DAYS -delete echo "Backup complete — $BACKUP_DIR" EOF sudo chmod +x /usr/local/bin/odoo-backup.sh

    Schedule it via cron to run nightly at 02:00:

    bash
    echo "0 2   * root /usr/local/bin/odoo-backup.sh >> /var/log/odoo17/backup.log 2>&1" | sudo tee /etc/cron.d/odoo-backup

    Test a restore before you need one. Create a throwaway database via the manager, restore the most recent dump and filestore into it, and log in to verify. An untested backup is not a backup.

    For offsite storage, pipe the backup files to S3-compatible storage (Contabo Object Storage, Backblaze B2, AWS S3) with rclone or aws s3 sync at the end of the script.

    Updating Odoo

    Odoo 17 receives regular bugfix and security updates on the 17.0 branch. Update monthly:

    bash
    sudo systemctl stop odoo17
    sudo su - odoo17
    cd /opt/odoo17/odoo
    git pull origin 17.0
    source /opt/odoo17/venv/bin/activate
    pip install -r requirements.txt --upgrade
    exit
    sudo systemctl start odoo17

    After a pull that touches module code, log into each database as admin and run Apps → Update Apps List → then upgrade any modules flagged with an available update. For safety, restart Odoo with -u all once to run all module updates:

    bash
    sudo systemctl stop odoo17
    sudo -u odoo17 /opt/odoo17/venv/bin/python3 /opt/odoo17/odoo/odoo-bin \
      -c /etc/odoo17.conf -d your_db_name -u all --stop-after-init
    sudo systemctl start odoo17

    Never jump major versions in place. Going from Odoo 16 to 17 requires a proper migration (OpenUpgrade or a paid Odoo SA migration) — don't just change the branch.

    Troubleshooting

    ProblemCauseSolution
    PDF reports have broken headers/footers or wrong layoutwkhtmltopdf not built against patched QtVerify wkhtmltopdf --version shows (with patched qt). Reinstall from the GitHub release in Step 3, not from apt install wkhtmltopdf.
    Worker (pid:12345) memory limit (2684354560) reached in logs, HTTP 500sSingle request blew past limit_memory_hardIncrease limit_memory_hard in odoo.conf (2 GB → 3 GB) and restart. Investigate the offending request — likely an import or a buggy report.
    Login succeeds, page redirects back to login (login loop)proxy_mode = True missing, or Nginx not forwarding X-Forwarded-ProtoVerify proxy_mode = True in /etc/odoo17.conf. Verify Nginx has proxy_set_header X-Forwarded-Proto $scheme;. Clear browser cookies for the domain.
    Chatter, notifications, or Discuss don't update live/websocket or /longpolling not proxied to port 8072Check Nginx config has both location blocks from Step 9 and that longpolling_port = 8072 is set in odoo.conf. curl -I https://odoo.yourdomain.com/longpolling/poll should not 404.
    psycopg2.OperationalError: FATAL: Peer authentication failed for user "odoo17"PostgreSQL role name doesn't match OS user, or password is wrongConfirm the PostgreSQL role created in Step 2 is named exactly odoo17. Reset its password: sudo -u postgres psql -c "ALTER USER odoo17 WITH PASSWORD 'newpass';" and update db_password in /etc/odoo17.conf.
    Odoo starts but uses only one core regardless of loadworkers = 0 (threaded mode)Set workers = 3 (or 2*CPU+1) in /etc/odoo17.conf and restart. Threaded mode is dev-only.
    Internal Server Error after git pull updateDB schema out of sync with codeRun odoo-bin -u all --stop-after-init once for each database as shown in the Updating section, then restart the service.
    Can't access /web/database/manager — 403 or blank pagelist_db = False blocks listing, but manager URL should still work with master passwordMaster password prompt appears on the page. If blank, check Odoo logs for werkzeug errors and ensure Nginx isn't caching a 403.
    Installer fails with ERROR: Failed building wheel for psycopg2Missing libpq-dev or python3-devsudo apt install libpq-dev python3-dev build-essential and re-run pip install -r requirements.txt.
    Web UI is slow, high CPU on one workerSingle request monopolizing worker — often a report with no indexesCheck /var/log/odoo17/odoo17.log for long-running queries. Add PostgreSQL indexes on filtered/sorted columns. Increase limit_time_real.

    Viewing Logs

    Stream the Odoo log live:

    bash
    sudo tail -f /var/log/odoo17/odoo17.log

    Or view via journalctl:

    bash
    sudo journalctl -u odoo17 -f

    PostgreSQL slow-query log (useful for performance debugging) lives at /var/log/postgresql/postgresql-16-main.log.

    FAQ

    What's the difference between Odoo Community and Odoo Enterprise?

    Community (what this guide installs) is free LGPLv3 open source. It includes all the core modules — CRM, Sales, Inventory, Accounting, Purchase, Manufacturing, HR, Website, eCommerce, Project — with fully functional versions. Enterprise adds proprietary modules like Studio (low-code builder), Documents, Sign, Marketing Automation, Full Accounting (bank sync, follow-ups, advanced reports), and official mobile apps, plus SLA-backed support from Odoo SA. Licensing runs approximately EUR 25–50 per user per month depending on the apps. For most SMBs, Community plus OCA modules covers 90%+ of real-world needs; Enterprise is worth it if you specifically want Studio, official accounting localization, or Odoo's direct support.

    Can I run Odoo on the same server as other services?

    Yes, but plan resource allocation carefully. On a 16 GB VPS you can comfortably run Odoo (3 workers = ~6 GB) + PostgreSQL (2–4 GB shared buffers) + Nginx alongside light services like Nextcloud or a WordPress site. Avoid running Odoo on the same box as memory-hungry apps like ElasticSearch, GitLab, or another ERP. If Odoo is business-critical, give it a dedicated server — the operational simplicity is worth the extra EUR 10–20/month.

    How many users can one VPS handle?

    As a rough guide on CloudCore Business (6 vCPU / 16 GB RAM) with 3 workers: 30–50 concurrent active users in CRM/Sales/Inventory-heavy workloads, or 100+ casual users (mostly reading dashboards, occasional data entry). The real bottlenecks are PostgreSQL query performance (fix with indexes) and worker count. Scale vertically first (more RAM, more workers, faster CPU) before splitting tiers. Above 100 concurrent users, consider dedicated PostgreSQL on a separate server and a second Odoo app server behind a load balancer.

    Is Odoo Community production-ready, or is it a "limited demo" of Enterprise?

    Odoo Community is production-ready and used by thousands of real businesses. It is not a crippled trial. You will hit limits if you need Enterprise-only modules (Studio, full Accounting localizations, Marketing Automation) or require Odoo SA's paid support, but the core ERP functionality is fully present. Many businesses run Community forever; others start on Community and only upgrade to Enterprise when a specific Enterprise module becomes essential. OCA modules close most of the gap for free.

    How do I migrate from QuickBooks, Xero, SAP, or another ERP?

    Odoo has a CSV/XLS import interface on most models (Customers, Products, Bills, Invoices, Journal Entries, etc.) at the top-right ⚙️ → Import records action. Export your existing data, map column headers to Odoo field names, and run a dry-run import first. For complex migrations (with historical data, foreign keys, multi-company) use the Odoo External API (XML-RPC or JSON-RPC) with a Python script — full docs at odoo.com/documentation/17.0/developer/reference/external_api.html. Plan 2–4 weeks of data work for a typical SMB migration; get a sandbox database running first and test end to end before go-live.

    Can Odoo be integrated with Stripe, WooCommerce, Shopify, or other external systems?

    Yes. Odoo ships with built-in payment acquirers for Stripe, PayPal, Adyen, Authorize.net, Mollie, and more — configure them under Invoicing → Configuration → Payment Providers. eCommerce integrations for Shopify, WooCommerce, Amazon, and eBay are available as OCA modules or paid Enterprise connectors. For anything not covered, Odoo's External API makes it straightforward to build custom integrations with Zapier, Make, n8n (install guide), or direct webhooks.

    Next Steps

    Now that Odoo is running on your VPS, here are recommended next steps:

    • Set up automated off-site backups — extend /usr/local/bin/odoo-backup.sh to push nightly dumps to Contabo Object Storage, Backblaze B2, or AWS S3 with rclone. Test a full restore at least once per quarter.
    • Install OCA accounting extensions — Community accounting is functional but missing reports like General Ledger and Trial Balance. Install account-financial-reports and account-closing from OCA to close the gap without buying Enterprise.
    • Add monitoring with Prometheus + Grafana — follow our Prometheus and Grafana guides to track Odoo response times, worker memory, and PostgreSQL query rates. Alert on 5xx spikes and DB slow queries.
    • Harden SSH and enable Fail2Ban — your Odoo server is now a business-critical asset. Disable root SSH, enforce key-only auth, and install Fail2Ban to block brute-force attempts on both SSH and the Odoo login page.
    • Add staging alongside production — clone your prod database into a staging database on the same server (or a smaller separate VPS) and point a subdomain at it. Test module upgrades and OCA installs on staging before touching production.
    • Connect Odoo to n8n or Make for workflow automation — trigger Slack alerts on new leads, sync contacts to Mailchimp, post invoices to Slack finance channels. Odoo's External API makes it straightforward.

    Need more horsepower for Odoo?
    >
    Our CloudCore Business plan is sized for production Odoo deployments — 6 vCPU, 16 GB RAM, 200 GB NVMe SSD, unmetered bandwidth — and comes with a clean Ubuntu 24.04 image ready for this guide.
    >
    - Handles 30–50 concurrent Odoo users comfortably
    - NVMe SSD keeps PostgreSQL snappy on large databases
    - Unmetered bandwidth for product images, attachments, and customer portal traffic
    - Upgrade vCPU/RAM live as your team grows
    >
    Deploy Your Odoo VPS Now — production-grade infrastructure, no per-user ERP fees, ever.

    Was this article helpful?

    ← Back to Install GuidesBrowse all categories →

    Still have questions?

    Contact Support →Submit a Ticket