Tutorial

Host Odoo 17 Community on VPS: complete Docker installation

Self-hosting10 min read10 steps

Odoo 17 Community Edition is one of the most comprehensive open-source ERPs available today. Free, extensible, and backed by a large community, it covers sales management, accounting, inventory, human resources and more. Yet many businesses still pay SaaS subscriptions for features they could host themselves on a VPS, with full control over their data. This guide walks you through deploying Odoo 17 Community on a VPS using Docker Compose, configuring backups, securing the instance and optimising its performance.

Contents· Why self-host Odoo Community1/12
  1. 01Why self-host Odoo Community
  2. 02What Odoo 17 Community includes
  3. 03Differences between Community and Enterprise
  4. 04VPS requirements for hosting Odoo 17
  5. 05Install Odoo 17 with Docker Compose
  6. 06Configure the database and instance
  7. 07Configure automated backups
  8. 08Activate key modules after installation
  9. 09Optimise your instance performance
  10. 10Secure the Odoo instance in production
  11. 11Advanced tip: integrating custom modules
  12. 12Hosting comparison: self-hosted VPS vs Odoo SaaS

Why self-host Odoo Community

The SaaS version of Odoo, sold via Odoo.sh or through partners, charges per user and per activated module. For a 10-person SMB using five modules, the monthly bill quickly exceeds several hundred euros. A VPS starting at 99 DH/month is enough to run the same instance, with no restrictions on the number of users or Community modules.

Data control is the other compelling argument. With a self-hosted instance, the PostgreSQL database stays on your server, in your datacenter of choice. No third party accesses your customers, quotes, invoices or HR data. For companies subject to compliance requirements — healthcare, legal, fintech — this control is not optional.

Finally, customisation is unrestricted. Odoo Community allows installation of any module from the community or developed in-house, without restrictions from the publisher. On a SaaS or managed instance, third-party modules often need to be validated, and some customisations are simply impossible.

What Odoo 17 Community includes

  • CRM: sales pipeline, leads, activities and customer tracking
  • Sales: quotes, purchase orders, pricing and payment terms
  • Accounting: chart of accounts, journals, bank reconciliation, VAT
  • Invoicing: customer and supplier invoices, automated reminders, payments
  • Inventory: stock management, locations, replenishment rules
  • Purchasing: purchase requests, tenders and supplier tracking
  • Human Resources: employees, contracts, leave and attendance
  • Email Marketing: mailing lists, campaigns and send statistics
  • Website & e-commerce: page builder, integrated online store
  • Helpdesk: customer ticketing, SLA and self-service portal

Differences between Community and Enterprise

Scroll the table

FeatureCommunityEnterpriseOpen-source alternative
Advanced accounting (analytical reports)BasicFullOCA `account-financial-reporting` module
Electronic signatureNot includedIncludedCommunity `sign` module or Docusign
Advanced timesheetsNot includedIncludedOCA `hr-attendance` module
Official editor supportCommunity forumGuaranteed SLACertified Odoo partner
Automatic updates (Odoo.sh)Not applicableIncludedManual migration script
Number of usersNo capLicense-basedNo restrictions
Price (self-hosted)FreeFree if self-hosted *Free

VPS requirements for hosting Odoo 17

Odoo is a Python/PostgreSQL application with significant RAM requirements, especially when multiple users work simultaneously. The minimum recommended sizing for an SMB with 5 to 15 users:

- CPU: 4 vCPU minimum; Odoo is multi-process and benefits from parallelism
- RAM: 8 GB recommended (4 GB is functional for testing, insufficient in production)
- Storage: 40 GB NVMe SSD; plan for more if you activate e-commerce with media
- OS: Ubuntu 22.04 LTS or Debian 12 — both are stable and well-documented
- Docker Engine 24+ and Docker Compose v2 (integrated plugin, docker compose without hyphen)
- A domain name pointing to the VPS IP, with an active A or CNAME record
- A reverse proxy (Caddy or Nginx) to handle TLS and expose Odoo on port 443

A 299 DH/month VPS from ServOrbit.com easily meets these requirements with dedicated resources.

Install Odoo 17 with Docker Compose

  1. Create the directory structure

    Connect via SSH to your VPS and create the working tree:

    mkdir -p /opt/odoo/{data,addons,config,backups}
    cd /opt/odoo

    These folders will hold persistent data, custom modules, Odoo configuration and backups respectively.

  2. Write the docker-compose.yml file

    Create /opt/odoo/docker-compose.yml with the following content:

    services:
      db:
        image: postgres:16
        restart: unless-stopped
        environment:
          POSTGRES_DB: postgres
          POSTGRES_USER: odoo
          POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
        volumes:
          - ./data/postgres:/var/lib/postgresql/data
        healthcheck:
          test: ["CMD-SHELL", "pg_isready -U odoo"]
          interval: 10s
          retries: 5
    
      odoo:
        image: odoo:17.0
        restart: unless-stopped
        depends_on:
          db:
            condition: service_healthy
        environment:
          HOST: db
          USER: odoo
          PASSWORD: ${POSTGRES_PASSWORD}
        volumes:
          - ./data/odoo:/var/lib/odoo
          - ./addons:/mnt/extra-addons
          - ./config/odoo.conf:/etc/odoo/odoo.conf
        ports:
          - "127.0.0.1:8069:8069"
          - "127.0.0.1:8072:8072"

    Note that ports are only exposed on localhost — the reverse proxy handles external access.

  3. Create the .env file and Odoo configuration

    Create /opt/odoo/.env:

    POSTGRES_PASSWORD=$(openssl rand -hex 32)
    echo "POSTGRES_PASSWORD=${POSTGRES_PASSWORD}" > /opt/odoo/.env

    Then create /opt/odoo/config/odoo.conf:

    [options]
    db_host = db
    db_port = 5432
    db_user = odoo
    db_password = ${POSTGRES_PASSWORD}
    addons_path = /usr/lib/python3/dist-packages/odoo/addons,/mnt/extra-addons
    admin_passwd = REPLACE_WITH_A_STRONG_PASSWORD
    without_demo = all
    workers = 4
    max_cron_threads = 2
    limit_memory_hard = 2684354560
    limit_memory_soft = 2147483648
  4. Configure the reverse proxy with Caddy

    Caddy is the simplest choice: it handles TLS automatically via Let's Encrypt. Install it and create /etc/caddy/Caddyfile:

    odoo.yourdomain.com {
        reverse_proxy 127.0.0.1:8069
    
        # WebSocket support for real-time notifications
        handle /websocket {
            reverse_proxy 127.0.0.1:8072
        }
    
        header {
            X-Frame-Options SAMEORIGIN
            X-Content-Type-Options nosniff
            Strict-Transport-Security "max-age=31536000; includeSubDomains"
        }
    
        encode gzip
    }

    Reload Caddy: systemctl reload caddy.

  5. Start the containers

    From /opt/odoo, run:

    docker compose up -d

    Follow the startup logs:

    docker compose logs -f odoo

    Odoo takes 30 to 60 seconds to initialise. You will see HTTP service (werkzeug) running when it is ready.

  6. Access the interface and create the database

    Open https://odoo.yourdomain.com/web/database/manager in your browser. Enter the master password (admin_passwd) defined in odoo.conf, choose a database name, language and administrator email, then click Create. The first initialisation takes 2 to 5 minutes depending on the selected modules.

Configure the database and instance

After the database is created, Odoo redirects you to the main interface. The first thing to do is verify the master password in Settings > Technical > Master Password. This password protects access to the database manager — it must be long and unique.

In Settings > General, configure the company name, base currency, time zone and address. These settings influence generated documents (invoices, purchase orders).

If you are migrating from another system, Odoo provides CSV importers for customers, suppliers, products and accounting balances. Always start with a test environment using real data before switching to production.

Configure automated backups

A production Odoo instance without backups is an immediate technical debt. The recommended strategy relies on two levels.

Daily PostgreSQL dump with a cron script:

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

docker compose -f /opt/odoo/docker-compose.yml exec -T db \
  pg_dump -U odoo ${DB_NAME} | gzip > ${BACKUP_DIR}/odoo_${DATE}.sql.gz

# Retain 7 days
find ${BACKUP_DIR} -name "odoo_*.sql.gz" -mtime +7 -delete

Schedule this script in /etc/cron.d/odoo-backup to run at 02:00 every night.

Volume backup: the /opt/odoo/data/odoo folder contains attachments, images and uploaded files. Synchronise it daily to object storage (S3, Scaleway Object Storage) using rclone or restic.

Activate key modules after installation

  • Sales (sale_management): quotes, orders, customer portal — core module for any commercial activity
  • Accounting (account_accountant): chart of accounts, VAT, bank reconciliation, closings
  • Inventory (stock): multi-warehouse management, lots and serial numbers, replenishment rules
  • Purchasing (purchase): purchase requests, tenders, receiving and supplier invoicing
  • Human Resources (hr): employee file, organisational structure, HR documents
  • Helpdesk (helpdesk): ticketing, SLA, customer self-service portal — Community includes basic features
  • Website (website): page builder, blog, contact forms
  • E-Commerce (website_sale): online store, cart, payment — activated alongside the Website module

Optimise your instance performance

  1. Adjust the number of workers

    In odoo.conf, the workers parameter controls the number of Python processes handling HTTP requests. The practical rule: workers = (vCPU × 2) + 1. On a 4 vCPU VPS, set workers = 4. Below 2, Odoo runs in single-process mode, which blocks long requests (imports, reports).

  2. Configure memory limits

    Odoo kills workers that exceed defined limits to prevent memory leaks.

    limit_memory_soft = 2147483648   # 2 GB: graceful end signal
    limit_memory_hard = 2684354560   # 2.5 GB: immediate kill

    On 8 GB RAM with 4 workers + PostgreSQL, these values are consistent. Increase them if your reports are slow or workers restart frequently (docker compose logs odoo | grep killed).

  3. Limit crons to avoid CPU saturation

    The max_cron_threads = 2 parameter reserves 2 threads for scheduled tasks (emails, replenishment, reports). Beyond that, crons compete with HTTP workers. On a server dedicated to Odoo, you can go up to 4, but start conservatively.

  4. Enable Redis session storage (optional)

    By default, Odoo stores sessions on disk. On shared volumes or with frequent restarts, this can cause disconnections. Add a Redis service to docker-compose.yml and configure:

    session_store = redis
    redis_url = redis://redis:6379

    This option is especially useful if you plan a multi-instance architecture in the future.

Secure the Odoo instance in production

The security of an Odoo instance relies on several complementary layers.

Disabling the database manager in production is the most important measure. This interface, accessible by default at /web/database/manager, allows anyone who knows the master password to create, delete or restore databases. Add to odoo.conf:

dbfilter = ^your_database$
list_db = False

list_db = False hides the management interface and prevents database enumeration.

Force TLS: Caddy handles this natively. With Nginx, ensure the HTTP vhost systematically redirects to HTTPS and that Strict-Transport-Security is set.

Fail2ban: configure a jail for failed login attempts on /web/login. Odoo logs these attempts at warning level — a regex filter on Login failed is sufficient.

Strong master password: this password should have at least 32 randomly generated alphanumeric characters. It can only be changed by modifying odoo.conf and restarting the container — make it a vault password from the start.

Advanced tip: integrating custom modules

The /opt/odoo/addons folder is mounted in the container at /mnt/extra-addons. To install a community module (OCA, or developed in-house), place it in this folder and add the path to addons_path in odoo.conf.

After adding a module, restart Odoo (docker compose restart odoo), then go to Settings > Apps > Update Apps List. The module appears in the list and installs like any native module.

For OCA modules, clone directly from GitHub into the addons folder: the [OCA organisation on GitHub](https://github.com/OCA) groups hundreds of thematic modules (French accounting, EDI, e-commerce connectors, etc.) that are actively maintained.

Hosting comparison: self-hosted VPS vs Odoo SaaS

Scroll the table

CriterionSelf-hosted VPS (ServOrbit.com)Odoo.sh / SaaS partner
Monthly cost (10 users)From 99 DH/month€150 to €500 depending on modules
Data controlTotal — data on your serverData with publisher or partner
Community modulesAll available, without restrictionDepends on plan and partner
Enterprise modulesNot included (separate licence)Included in subscription
BackupsYour responsibility, configurableManaged by platform
UpdatesManual (major migration)Managed (assisted upgrade)
CustomisationNo capRestricted or billable
Skills requiredLinux administration, DockerNo server skills needed
Technical supportCommunity + partner of choiceSLA per publisher contract

Deploy your ERP with full autonomy

ServOrbit.com offers VPS instances optimised for demanding application workloads like Odoo. Dedicated resources, NVMe SSD, responsive technical support — everything you need to run your ERP in production.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab