Integration Architecture and Data Flow
Your Odoo deployment’s reliability stems from a sound architectural foundation. We design a multi-tier system that separates concerns, enhances security, and enables independent scaling. The core components include a compute instance for the Odoo application, a managed PostgreSQL database, a block storage volume for session data and filestore, and a load balancer for distributing traffic. This segregated design prevents a single point of failure and allows you to optimize each layer for its specific workload.
The Odoo application itself runs within a Docker container on a Hetzner Cloud CX21 or larger instance. Containerization guarantees consistency across environments and simplifies the deployment process. We use a custom Dockerfile to build an Odoo image that includes all necessary Python dependencies and system libraries. The container orchestrates the Odoo application server, which handles all business logic, HTTP requests, and server-side rendering for the web interface.
A Hetzner Managed Database running PostgreSQL 15 serves as the persistent data layer. This dedicated database service provides automated backups, patches, and high availability out of the box. The Odoo container connects to this external database over a secure, private network connection established through Hetzner’s VPC. All transactional data, including sales orders, inventory records, and customer information, resides in this cluster, ensuring data durability and integrity.
User requests follow a specific path through the system. A client’s browser sends an HTTPS request to the Hetzner Load Balancer, which terminates SSL/TLS encryption. The load balancer then forwards the decrypted HTTP request to the Nginx reverse proxy running on the Odoo application instance. Nginx handles static file serving and proxies dynamic requests to the Odoo container. For file storage, we configure Odoo to use an S3-compatible object storage bucket, which offloads binary data from the database and improves overall performance.
Network Security and Data Isolation
We leverage Hetzner’s private network to create a secure communication channel between the application server and the managed database. This network isolation ensures that database traffic never exposes itself to the public internet. The system only opens two public-facing ports: 80 for HTTP and 443 for HTTPS on the load balancer. The application server’s firewall restricts inbound connections to the load balancer’s private IP address, creating a hardened security posture.
Session and Cache Management
We deploy a Redis container on the application instance to handle Odoo’s session storage and caching needs. This in-memory data store accelerates response times for frequently accessed data and manages user session state. The Odoo configuration directs all cache and session queries to this local Redis instance, which reduces the load on the primary PostgreSQL database and provides a faster experience for concurrent users.
Step-by-Step Configuration
Initial Server Provisioning with Terraform
We automate the infrastructure creation using Terraform for reproducible deployments. This code provisions a Hetzner Cloud server, configures the firewall, and sets up the private network. The Terraform configuration defines the server type, image, and location, ensuring consistent environments across staging and production.
resource "hcloud_server" "odoo_app" {
name = "odoo-app-prod"
image = "ubuntu-22.04"
server_type = "cx21"
location = "fsn1"
ssh_keys = [hcloud_ssh_key.odoo_admin.id]
user_data = file("${path.module}/config/cloud-init.yaml")
}
resource "hcloud_network" "odoo_private" {
name = "odoo-private-network"
ip_range = "10.0.0.0/16"
}
resource "hcloud_firewall" "odoo_base" {
name = "odoo-base-firewall"
rule {
direction = "in"
protocol = "tcp"
port = "22"
source_ips = ["0.0.0.0/0"]
}
}
The cloud-init configuration performs initial system setup, including creating a dedicated user, installing Docker, and configuring the system firewall. This automated bootstrap process ensures every deployment starts from an identical, hardened base image.
PostgreSQL Database Configuration
Create a Hetzner Managed Database cluster through the cloud console or API. Select PostgreSQL 15 as your database engine and choose the high-availability option for production workloads. Once the cluster provisions, create a dedicated database and user for Odoo with appropriate permissions.
Connect to your database instance using the provided connection string and execute these SQL commands:
CREATE USER odoo_user WITH PASSWORD 'your_secure_password_here';
CREATE DATABASE odoo_prod OWNER odoo_user;
ALTER USER odoo_user CREATEDB;
The CREATEDB privilege allows Odoo to create test databases during module installation. Update the database cluster’s firewall rules to accept connections only from your application server’s private IP address. This network-level security prevents unauthorized access attempts.
Odoo Docker Container Setup
Build a custom Docker image that extends the official Odoo image with your specific requirements. This Dockerfile installs additional Python packages and configures the proper environment.
FROM odoo:18.0
USER root
# Install system dependencies
RUN apt-get update && \
apt-get install -y python3-dev build-essential && \
rm -rf /var/lib/apt/lists/*
# Install additional Python packages
RUN pip3 install psycopg2-binary boto3
USER odoo
Create a Docker Compose file to manage the Odoo and Redis services. This compose configuration defines the container relationships, volume mounts, and environment variables.
version: '3.8'
services:
odoo:
build: .
restart: unless-stopped
ports:
- "8069:8069"
environment:
- HOST=your-database-host.private
- USER=odoo_user
- PASSWORD=your_secure_password_here
- DATABASE=odoo_prod
volumes:
- odoo-data:/var/lib/odoo
depends_on:
- redis
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis-data:/data
volumes:
odoo-data:
redis-data:
Nginx Reverse Proxy Configuration
Install and configure Nginx as a reverse proxy and SSL terminator. This setup handles domain name routing, static file serving, and SSL certificate management.
Create an Nginx configuration file for your Odoo domain:
server {
listen 80;
server_name your-odoo-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-odoo-domain.com;
ssl_certificate /etc/letsencrypt/live/your-odoo-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-odoo-domain.com/privkey.pem;
client_max_body_size 100M;
location / {
proxy_pass http://localhost: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;
}
location /longpolling {
proxy_pass http://localhost:8072;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Obtain an SSL certificate from Let’s Encrypt using Certbot. The certificate enables HTTPS encryption for all client connections and builds trust with your users.
Systemd Service Configuration
Create a systemd service file to ensure your Docker Compose stack starts automatically on system boot. This service management guarantees high availability and proper process supervision.
Create /etc/systemd/system/odoo.service:
[Unit]
Description=Odoo Docker Compose Stack
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/odoo
ExecStart=/usr/bin/docker-compose up -d
ExecStop=/usr/bin/docker-compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
Enable and start the service with systemctl enable odoo.service && systemctl start odoo.service. The system now automatically recovers from unexpected server restarts.
Data Mapping and Transformation
Odoo Module Structure and Data Models
Odoo’s data architecture centers around Python classes that extend Odoo models. These models map directly to PostgreSQL tables, with Odoo’s ORM handling the object-relational mapping. Each model field type corresponds to a specific PostgreSQL data type, creating a seamless integration between the application layer and the database.
When you install a new Odoo module, the system executes XML files that contain data records and view definitions. These XML files populate base data, such as country states, product categories, and access rights. The system stores this structural metadata in PostgreSQL tables with names like ir_model, ir_model_fields, and ir_ui_view.
Custom Field Mapping and Transformations
Extend standard Odoo models by adding custom fields that address your specific business needs. These field additions create new columns in the existing PostgreSQL tables without modifying the core table structure. The Odoo framework handles the schema migrations automatically when you install or update modules.
For example, add a custom field to the res.partner model to track customer loyalty points:
<record id="field_res_partner_loyalty_points" model="ir.model.fields">
<field name="name">loyalty_points</field>
<field name="model_id" ref="model_res_partner"/>
<field name="field_description">Loyalty Points</field>
<field name="ttype">integer</field>
</record>
This XML definition creates an integer column named loyalty_points in the res_partner table. The Odoo ORM manages all data access through this field, ensuring type consistency and validation.
File Storage Architecture with Object Storage
Configure Odoo to store attachments and files in Hetzner’s S3-compatible object storage instead of the PostgreSQL database. This architecture decision improves database performance and scales better with large files.
Set these parameters in your Odoo configuration file:
ir_attachment.location = 's3://your-bucket-name'
ir_attachment.config = '{"endpoint_url": "https://s3.your-hetzner-region.hetzner.com", "access_key_id": "your_access_key", "secret_access_key": "your_secret_key", "bucket_name": "your-bucket-name"}'
The system now stores all uploaded files as objects in your designated bucket. Odoo maintains the file metadata in the ir_attachment table, including the object key that points to the actual file in object storage. This hybrid approach combines the query capabilities of PostgreSQL with the scalability of object storage.
Data Import and Export Patterns
Odoo provides robust data import functionality through its web interface and external API. The system accepts CSV files for bulk data operations and maps the CSV columns to model fields based on your field definitions. For complex data transformations, implement custom import methods that validate and clean data before insertion.
Use Odoo’s external API to integrate with external systems. The XML-RPC and JSON-RPC interfaces allow bidirectional data synchronization. For example, sync product information from an external e-commerce platform:
import xmlrpc.client
url = 'https://your-odoo-domain.com'
db = 'odoo_prod'
username = 'api_user'
password = 'api_password'
common = xmlrpc.client.ServerProxy('{}/xmlrpc/2/common'.format(url))
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy('{}/xmlrpc/2/object'.format(url))
product_data = {
'name': 'New Product',
'list_price': 99.99,
'standard_price': 49.99,
'type': 'product',
}
product_id = models.execute_kw(db, uid, password, 'product.product', 'create', [product_data])
This programmatic approach enables seamless data flow between Odoo and your other business systems.
Error Handling and Resilience
Common Database Connection Issues
The managed PostgreSQL database may experience connection timeouts under heavy load or network congestion. Odoo logs these errors with messages like “psycopg2.OperationalError: could not connect to server” in the system logs. Implement a connection retry mechanism in your Odoo configuration to handle transient network failures.
Add these parameters to your Odoo configuration file to improve connection resilience:
db_maxconn = 64
db_reconnection_retries = 5
db_reconnection_delay = 2
These settings allow Odoo to recover from brief database unavailability without requiring manual intervention. The system attempts to reestablish database connections with exponential backoff, maintaining service availability during minor infrastructure issues.
Memory and Worker Process Management
Odoo’s multi-process architecture can exhaust server memory if not properly configured. The system spawns worker processes to handle concurrent requests, and each worker consumes a significant amount of RAM. Monitor your system’s memory usage and adjust the worker limits based on your available resources.
Set appropriate worker limits in your Odoo configuration:
workers = 4
limit_memory_soft = 671088640
limit_memory_hard = 805306368
limit_request = 8192
limit_time_cpu = 60
limit_time_real = 120
These values prevent any single worker process from consuming excessive memory or CPU time. The system automatically restarts workers that exceed the soft memory limit, and it terminates workers that reach the hard limit. This protection maintains overall system stability under unpredictable load patterns.
Attachment Storage Failures
Object storage connectivity issues can disrupt file uploads and downloads. Odoo reports these errors with “S3Storage: Connection failed” messages in the logs. Implement a fallback mechanism that temporarily stores attachments on the local filesystem when object storage becomes unavailable.
Create a custom storage backend that handles temporary fallback:
from odoo.tools import config
import logging
_logger = logging.getLogger(__name__)
class FallbackS3Storage:
def __init__(self, s3_config):
self.s3_config = s3_config
self.fallback_path = config.filestore
def store(self, key, data):
try:
# Attempt S3 storage first
return self._store_s3(key, data)
except Exception as e:
_logger.warning("S3 storage failed, using fallback: %s", e)
return self._store_local(key, data)
This defensive programming approach ensures that temporary object storage outages don’t block critical business processes. The system continues to function with local storage until the object storage service recovers.
Automated Backup and Recovery Procedures
Implement a comprehensive backup strategy that captures both the database and filestore. Schedule daily automated backups that export the database dump and sync the object storage bucket to a backup location.
Create a backup script that runs via cron:
#!/bin/bash
# Database backup
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME > /backups/odoo_$(date +%Y%m%d).sql
# Object storage sync
rclone sync s3:production-bucket s3:backup-bucket --s3-endpoint https://s3.your-hetzner-region.hetzner.com
Test your backup restoration process quarterly to verify data integrity and recovery time objectives. A proven recovery procedure minimizes downtime during actual disaster scenarios.
Testing and Validation
Post-Installation Health Check
Verify your Odoo installation’s basic functionality through a systematic health check. Access your Odoo instance through the web interface and create a test database. Navigate to the Apps menu and install the Contacts module to validate core system operations.
Check these critical system components:
- Database connection stability - Monitor the logs for any connection errors
- User authentication - Create a test user and verify login capabilities
- Module installation - Install a simple module like Contacts or Notes
- File upload - Attach a test file to a record and verify download functionality
- Scheduled actions - Check that automated jobs run without errors
These basic tests confirm that all system layers communicate properly and handle standard operations. Any failures at this stage indicate configuration issues that require immediate attention.
Load Testing and Performance Validation
Simulate realistic user traffic to identify performance bottlenecks before they impact real users. Use a tool like Apache JMeter or Locust to generate concurrent requests that mimic typical user behavior.
Create a load testing scenario that includes:
- Multiple user logins and session management
- Data import and export operations
- Report generation and printing
- Search and filter operations across large datasets
- Concurrent write operations on shared records
Monitor these key performance metrics during the load test:
- Response time for page loads and API calls
- Database query execution time
- Memory and CPU utilization on the application server
- Network bandwidth consumption
- PostgreSQL connection pool usage
Establish performance baselines that you can reference during future capacity planning exercises. The test results help you right-size your infrastructure and identify optimization opportunities.
Integration Testing with External Systems
Validate data exchange between Odoo and your other business systems. Create test cases that cover both inbound and outbound data flows, including API connections, file imports, and webhook handlers.
Test these common integration patterns:
- CSV product import from your e-commerce platform
- Customer data synchronization with your CRM
- Inventory level updates from warehouse management systems
- Accounting journal entry exports to financial software
- Email gateway functionality for customer communications
Document the expected data transformations and verify that the system applies them correctly. For example, confirm that currency conversions happen at the proper exchange rates and that tax calculations follow your business rules.
Security and Access Control Testing
Verify that your security configuration enforces proper access controls. Test user permission levels to ensure that employees can only access authorized data and functions.
Execute these security validation steps:
- Attempt to access admin functions with a non-admin user account
- Verify that users cannot view records outside their assigned departments
- Test password policy enforcement for complexity requirements
- Validate HTTPS enforcement across all application pages
- Check that API endpoints require proper authentication
These security tests protect your business data from both external threats and internal misuse. Regular security validation should become part of your standard maintenance routine.
Security Considerations
Network Security and Access Controls
Hetzner’s cloud firewall provides your first defense layer. Configure strict inbound rules that only allow essential traffic. Open port 22 for SSH access from your administrative IP range, and permit HTTP/HTTPS traffic from the load balancer. Block all other inbound connections by default.
Implement Hetzner’s private networking for all internal communication between your application server and managed database. This network isolation ensures that database traffic never traverses the public internet. Configure the database firewall to only accept connections from your application server’s private IP address.
Application-Level Security Hardening
Secure your Odoo installation through proper configuration settings. Disable the default database manager in production environments to prevent unauthorized database creation. Set strong master passwords for both the database and the Odoo application.
Add these security settings to your Odoo configuration file:
list_db = False
dbfilter = ^odoo_prod$
admin_passwd = your_secure_master_password
max_cron_threads = 2
These settings prevent database enumeration attacks, restrict database access to your production instance, and limit the resources available to automated tasks. Regularly update your Odoo installation to incorporate security patches and vulnerability fixes.
Data Encryption and Privacy
Enable full-disk encryption for your block storage volumes to protect data at rest. Hetzner’s storage systems provide transparent encryption, but you must enable this feature during volume creation. For additional security, implement application-level encryption for sensitive customer data.
Use Odoo’s built-in encryption fields for storing highly sensitive information like bank account details or government identification numbers. These fields encrypt data before persisting it to the database, providing an extra security layer even if someone gains unauthorized database access.
Authentication and Session Security
Implement strong password policies for all user accounts. Odoo’s password security settings enforce minimum complexity requirements and prevent password reuse. Enable two-factor authentication for administrative accounts to protect against credential theft.
Configure session security settings to automatically expire inactive sessions and regenerate session identifiers after login. These measures prevent session hijacking attacks and protect user accounts from unauthorized access.
Performance Optimization
Database Query Optimization
PostgreSQL query performance directly impacts your Odoo instance’s responsiveness. Identify slow queries using Odoo’s built-in logging or PostgreSQL’s pg_stat_statements extension. Common performance issues include missing indexes on frequently searched fields and inefficient joins across large tables.
Create custom indexes on fields you often use in filters or search operations. For example, add an index on the create_date field of frequently accessed models:
CREATE INDEX res_partner_create_date_idx ON res_partner (create_date);
Regularly analyze and vacuum your database to maintain optimal performance. The Hetzner Managed Database service handles these maintenance tasks automatically, but you should monitor their execution and impact.
Application Server Tuning
Optimize Odoo’s worker configuration based on your server’s available resources. The ideal worker count depends on your CPU cores and expected concurrent users. A general rule allocates one worker per CPU core, plus an additional worker for cron jobs.
Adjust these Odoo configuration parameters for optimal performance:
workers = 4
limit_memory_soft = 671088640
limit_memory_hard = 805306368
max_cron_threads = 1
Enable Odoo’s built-in caching for frequently accessed but rarely changed data. The system can cache translatable terms, website assets, and other static content to reduce database load.
Static Content Delivery Optimization
Configure Nginx to serve static files directly, bypassing the Odoo application server for these requests. This optimization reduces the load on your Odoo workers and improves response times for CSS, JavaScript, and image files.
Add these static file handling rules to your Nginx configuration:
location /web/static/ {
alias /var/lib/odoo/static/;
expires 1y;
add_header Cache-Control public;
add_header Vary Accept-Encoding;
}
Implement browser caching headers for static assets to reduce bandwidth consumption and improve page load times for returning visitors. The expires directive tells browsers to cache static files for one year.
Monitoring and Capacity Planning
Install a monitoring agent on your application server to track key performance metrics. Monitor CPU utilization, memory consumption, disk I/O, and network traffic. Set up alerts for resource thresholds that indicate impending capacity limits.
Track these Odoo-specific metrics:
- Active user sessions and request rates
- Database connection pool usage
- Long-running queries and transactions
- Queue depth for scheduled actions
- Memory usage per worker process
Use this monitoring data to inform your capacity planning decisions. The metrics help you anticipate when you need to scale your infrastructure to handle growing business demands.