System Architecture and Component Flow

A production Odoo 18 deployment on CentOS 9 requires a clear understanding of its multi-tier architecture. This design separates concerns, enhances security, and enables scaling. The core components form a chain where each service handles a specific task, passing requests to the next layer in a structured flow. Visualize this as a stack where user interactions enter at the top and descend to the data persistence layer.

The user experience starts at the Nginx reverse proxy. This component acts as the public gateway, terminating SSL/TLS connections and serving static files with high efficiency. It forwards dynamic requests to the Odoo application server, which operates via the WSGI protocol. Nginx shields the Python application from direct internet exposure, providing a critical security buffer and performance boost for static content like images, CSS, and JavaScript.

The Odoo application server, running in a dedicated Python virtual environment, constitutes the business logic engine. It processes all dynamic requests, executes Python code, and renders QWeb templates. This environment, built with specific library versions, ensures absolute dependency isolation from the underlying CentOS system. The application layer communicates with the PostgreSQL database using pure Python drivers, executing complex queries and transactions.

PostgreSQL serves as the persistent data store, managing all structured information from customer records to product inventories. A dedicated system user owns this database cluster, enforcing strict access controls. The entire data flow follows a strict unidirectional pattern for requests, with responses traveling back through the same layers to the end-user’s browser. This architecture creates a secure, performant, and maintainable deployment foundation.

Prerequisites and Initial System Configuration

A properly prepared CentOS 9 server forms the bedrock of a stable Odoo installation. Begin with a minimal server installation, which reduces the attack surface and resource overhead. Your system requires at least 2 CPU cores, 4 GB of RAM, and 20 GB of free disk space for a production workload. A sudo-privileged user account must execute all administrative commands throughout this process.

First, update the entire system to incorporate the latest security patches and bug fixes. The dnf update command fetches and installs all available package updates. A system reboot ensures the server runs the newest kernel and core libraries. This step eliminates potential conflicts with outdated software packages.

sudo dnf update -y sudo reboot

Install the Essential Packages and Development Tools required for compiling Python modules and managing software. This group includes compilers, header files, and critical libraries that Odoo’s dependencies need. The @development group provides a comprehensive set of tools for building software from source code.

sudo dnf install -y python3-pip python3-devel git wget @development sudo dnf install -y openldap-devel libxml2-devel libxslt-devel libjpeg-devel libffi-devel

Create the System User and Groups that will manage the Odoo service and database. Running Odoo under a dedicated user account enhances security by following the principle of least privilege. This user owns the application code and executes the server process with minimal system permissions.

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

This command creates the odoo user with a home directory at /opt/odoo. The system will run the Odoo application and related processes under this isolated account. You now have a secure, updated base system ready for the database and application installation.

PostgreSQL Database Installation and Configuration

Odoo requires a robust relational database, and PostgreSQL delivers the performance and reliability needed for enterprise applications. Install the PostgreSQL server and client packages from the standard CentOS repositories. This provides a stable, well-tested database environment for your Odoo instance.

sudo dnf install -y postgresql-server postgresql-contrib

Initialize the PostgreSQL database cluster using the postgresql-setup command. This script creates the necessary data directory structure and configuration files. The initialization process sets up the default database locale and encoding, which must align with your Odoo deployment’s requirements.

sudo postgresql-setup --initdb --unit postgresql

Start and enable the PostgreSQL service to ensure it launches automatically upon system boot. The enable command links the service to the system’s init system, while start activates it immediately. Verify the database server accepts connections on the standard port.

sudo systemctl enable --now postgresql sudo systemctl status postgresql

Create a Dedicated PostgreSQL User for Odoo. This user matches the name of the system account you created earlier, which simplifies authentication. Switch to the postgres system user to execute database administration commands with the correct privileges.

sudo -u postgres createuser --createdb --username postgres --no-createrole --no-superuser --pwprompt odoo sudo -u postgres createdb --owner=odoo odoo

This sequence creates the odoo database user with limited privileges and a corresponding database owned by that user. The --pwprompt flag triggers a password creation dialog; record this password in a secure location. Your Odoo application will use these credentials to connect to its dedicated database, ensuring data isolation and security.

Python Environment and Odoo 18 Installation

A controlled Python environment prevents dependency conflicts and ensures consistent application behavior. CentOS 9 includes Python 3.9 by default, which meets Odoo 18’s requirements. We will create a virtual environment to house all Odoo’s Python dependencies, separate from the system’s Python packages.

Install the virtualenv package using pip3. This tool constructs isolated Python environments with their own package directories. Isolation prevents conflicts between Odoo’s requirements and other Python applications on the same system.

sudo pip3 install virtualenv

Switch to the odoo user and navigate to its home directory. All subsequent Odoo installation steps occur within this user’s context, which enforces proper file ownership and security boundaries.

sudo su - odoo

Create and activate a Python virtual environment within the odoo user’s home directory. This environment will contain the exact Python interpreter and library versions that Odoo 18 requires.

virtualenv odoo-venv source odoo-venv/bin/activate

Your command prompt should now display the (odoo-venv) prefix, confirming the active virtual environment. Install the Wheel package first, which accelerates the installation of binary Python packages by pre-building them.

pip install wheel

Install Odoo 18 from the source code using pip. This method fetches the latest stable release from the PyPI repository and handles all Python dependencies automatically. The installation process may take several minutes as it compiles native extensions.

pip install odoo

This command installs Odoo and all its required Python libraries into the virtual environment. The odoo command-line utility becomes available in the virtual environment’s binary path. Verify the installation by checking the Odoo version, which confirms a successful deployment of the core application.

odoo --version

Exit the odoo user session and return to your sudo-privileged account. The core Odoo application now resides in the virtual environment, ready for configuration.

exit

Odoo Application Configuration and Service Setup

A proper configuration file centralizes all Odoo settings and simplifies management. Create the main Odoo configuration directory and generate a default configuration file. This file controls database connections, server ports, file paths, and security settings.

sudo mkdir /etc/odoo sudo touch /etc/odoo/odoo.conf

Generate a base configuration using the odoo command with the --save flag. This creates a template with all default settings, which you can then customize for your specific deployment.

sudo su - odoo -c "cd /opt/odoo && source odoo-venv/bin/activate && odoo --stop-after-init --save --config /etc/odoo/odoo.conf --db_host=127.0.0.1 --db_port=5432 --db_user=odoo --db_password=your_db_password"

Replace your_db_password with the actual password you set for the PostgreSQL odoo user. This command initializes the configuration file with the correct database connection parameters.

Edit the Odoo configuration file to fine-tune the deployment settings. Use a text editor to modify the file, ensuring it contains the essential parameters for a production environment.

sudo nano /etc/odoo/odoo.conf

A production-ready configuration file should include these core parameters:

[options]
admin_passwd = your_master_admin_password
db_host = 127.0.0.1
db_port = 5432
db_user = odoo
db_password = your_db_password
addons_path = /opt/odoo/odoo-venv/lib/python3.9/site-packages/odoo/addons
data_dir = /var/lib/odoo
logfile = /var/log/odoo/odoo.log
log_level = warn

Set a strong master admin password to control database creation and restoration operations. The addons_path directs Odoo to its standard module directory, while data_dir defines where attachments and session data reside. Configure proper log file location and logging level for operational visibility.

Create the necessary directories for Odoo’s operational data and log files. Assign correct ownership to the odoo user so the application can write to these locations.

sudo mkdir /var/lib/odoo sudo mkdir /var/log/odoo sudo chown odoo:odoo /var/lib/odoo /var/log/odoo

Configure Odoo as a Systemd Service for automatic management and high availability. Create a service unit file that defines how the system should start, stop, and monitor the Odoo process.

sudo nano /etc/systemd/system/odoo.service

The service file should contain this configuration:

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

[Service]
Type=simple
SyslogIdentifier=odoo
User=odoo
Group=odoo
ExecStart=/opt/odoo/odoo-venv/bin/odoo --config /etc/odoo/odoo.conf
KillMode=mixed
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

This unit file defines Odoo as a simple service that requires PostgreSQL. It runs under the odoo user account and restarts automatically after failures. The KillMode=mixed setting ensures proper process termination during shutdown sequences.

Reload the systemd manager to recognize the new service file, then start and enable the Odoo service.

sudo systemctl daemon-reload sudo systemctl enable --now odoo sudo systemctl status odoo

The Odoo application server now runs as a managed system service, accessible on port 8069. The system will automatically restart the service if it fails and maintain it across server reboots.

Nginx Reverse Proxy and SSL Configuration

A reverse proxy server handles client connections, offloads SSL processing, and serves static content efficiently. Install Nginx from the CentOS repositories to act as this front-end proxy for your Odoo application.

sudo dnf install -y nginx

Create a new Nginx server block configuration specifically for Odoo. This configuration defines how Nginx handles incoming HTTP and HTTPS requests and proxies them to the Odoo backend.

sudo nano /etc/nginx/conf.d/odoo.conf

The server block configuration should include these core elements:

upstream odoo_backend {
    server 127.0.0.1:8069;
}

server {
    listen 80;
    server_name your-domain.com;

    # Redirect HTTP to HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /etc/ssl/certs/odoo.crt;
    ssl_certificate_key /etc/ssl/private/odoo.key;

    # SSL security settings
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;

    # Proxy settings
    proxy_read_timeout 720s;
    proxy_connect_timeout 720s;
    proxy_send_timeout 720s;
    proxy_set_header X-Forwarded-Host $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;

    # Serve static files directly
    location /web/static/ {
        proxy_cache_valid 200 60m;
        proxy_buffering on;
        expires 864000;
        proxy_pass http://odoo_backend;
    }

    # Longpolling endpoint
    location /longpolling {
        proxy_pass http://odoo_backend;
    }

    # Main Odoo application
    location / {
        proxy_pass http://odoo_backend;
    }
}

Replace your-domain.com with your actual domain name. The configuration defines an upstream block for the Odoo backend and handles both HTTP redirection and HTTPS termination.

Generate a Self-Signed SSL Certificate for testing, or obtain a trusted certificate from Let’s Encrypt for production use. Create the SSL directory structure and generate the certificate files.

sudo mkdir -p /etc/ssl/certs /etc/ssl/private sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/odoo.key -out /etc/ssl/certs/odoo.crt

The OpenSSL command creates a self-signed certificate valid for 365 days. For production deployments, use Certbot with Let’s Encrypt to obtain a trusted certificate that browsers recognize.

Test the Nginx configuration for syntax errors, then start and enable the service.

sudo nginx -t sudo systemctl enable --now nginx sudo systemctl reload nginx

Nginx now acts as a secure reverse proxy, handling SSL termination and static content delivery while forwarding dynamic requests to the Odoo application server.

Security Hardening and Firewall Configuration

A secure Odoo deployment requires multiple defense layers at the network, application, and system levels. Begin with the CentOS firewall, which controls network access to your server’s services. Configure firewalld to permit only essential traffic while blocking all other connections.

sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --permanent --remove-service=ssh --remove-port=8069/tcp sudo firewall-cmd --reload

These commands open HTTP and HTTPS ports while closing direct access to Odoo’s default port 8069. The configuration forces all traffic through the Nginx reverse proxy, which provides SSL encryption and additional security filtering.

Harden the Odoo Application Configuration with security-specific parameters. Edit the main Odoo configuration file to implement these protective measures.

sudo nano /etc/odoo/odoo.conf

Add these security directives to the [options] section:

list_db = False
proxy_mode = True
x_sendfile = True
csv_insecure_sep = False

The list_db = False setting prevents the database manager interface from displaying available databases, which blocks unauthorized database operations. proxy_mode = True enables proper reverse proxy support for IP address forwarding. x_sendfile offloads file downloads to the web server, and csv_insecure_sep prevents CSV injection attacks.

Implement File System Security by restricting access to Odoo directories and configuration files. The Odoo configuration contains database credentials, so it must have strict permissions.

sudo chown odoo:odoo /etc/odoo/odoo.conf sudo chmod 640 /etc/odoo/odoo.conf

These commands ensure only the odoo user and members of the odoo group can read the configuration file. Other system users cannot access the database password or other sensitive settings.

Configure PostgreSQL Security by editing the host-based authentication file. This controls which users can connect to the database from which network locations.

sudo nano /var/lib/pgsql/data/pg_hba.conf

Ensure the local connections use peer or md5 authentication:

local   all             all                                     peer
host    all             all             127.0.0.1/32           md5
host    all             all             ::1/128                md5

This configuration permits database connections only from localhost, preventing direct external access to PostgreSQL. Restart the PostgreSQL service to apply these authentication changes.

sudo systemctl restart postgresql

Your Odoo installation now operates behind multiple security layers, with controlled network access, application-level protections, and filesystem permissions that follow security best practices.

Performance Optimization and Monitoring

A well-tuned Odoo instance delivers responsive user experiences and handles concurrent operations efficiently. Begin with Database Performance optimizations by adjusting PostgreSQL configuration parameters. Edit the main PostgreSQL configuration file to allocate resources based on your server’s capacity.

sudo nano /var/lib/pgsql/data/postgresql.conf

Modify these key performance parameters:

shared_buffers = 1GB
work_mem = 10MB
maintenance_work_mem = 256MB
effective_cache_size = 3GB
random_page_cost = 1.1

The shared_buffers setting controls how much memory PostgreSQL dedicates to caching data. Allocate approximately 25% of your system RAM for this parameter. work_mem determines the amount of memory available for sort operations and hash tables. Increase maintenance_work_mem for faster database vacuuming and index creation.

Optimize Odoo’s Worker Processes to handle concurrent requests efficiently. The default Odoo configuration uses a single process, which limits performance under load. Edit the Odoo configuration file to enable multiprocessing mode.

sudo nano /etc/odoo/odoo.conf

Add these worker configuration parameters:

workers = 4
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_request = 8192
limit_time_cpu = 600
limit_time_real = 1200
max_cron_threads = 1

The workers parameter defines the number of simultaneous request handlers. A good starting point calculates workers based on CPU cores: (CPU cores * 2) + 1. Memory limits prevent worker processes from consuming excessive system resources. Adjust these values based on your server’s available RAM and typical workload patterns.

Implement Caching Strategies to reduce database load. Odoo supports in-memory caching for frequently accessed data. Configure the Odoo cache parameters to optimize response times for common operations.

cache_timeout = 3600
cache_size = 16777216

The cache_timeout sets how long cached data remains valid, while cache_size defines the memory allocated for caching. These settings work with the worker processes to serve repeated requests from memory instead of querying the database.

Configure Logging and Monitoring to track system performance and identify bottlenecks. The Odoo log file provides insights into application behavior, while system monitoring tools track resource utilization.

sudo nano /etc/odoo/odoo.conf

Set appropriate log levels and enable specific log handlers:

log_level = info
log_handler = [':INFO']
log_db = False

The log_level of ‘info’ provides operational details without excessive debug noise. log_db set to False prevents log entries from consuming database space. For production systems, integrate with external monitoring solutions like Prometheus and Grafana for comprehensive performance visibility.

Restart both Odoo and PostgreSQL services to apply all performance optimizations.

sudo systemctl restart postgresql sudo systemctl restart odoo

Monitor system resource usage after applying these changes to ensure stable operation under production workloads. Adjust parameters based on actual usage patterns and performance metrics.