π What You'll Master Today
By the end of this guide, you'll confidently:
- Launch your first Odoo instance using Docker in under 10 minutes
- Understand the magic behind containers and why they're game-changers
- Manage multiple Odoo instances on one machine (yes, really!)
- Generate beautiful PDFs with proper headers and footers
- Manage databases like a seasoned developer
- Troubleshoot common issues before they become problems
10min readbeginner friendly
π€ Why This Matters (And Why Docker?)
Traditional Installation (The Hard Way):
β Install Python, PostgreSQL, dependencies manually
β Version conflicts with other software
β "Works on my machine" syndrome
β Hours of configuration hell
β Difficult to run multiple Odoo versionsDocker Installation (The Smart Way):
β
Everything pre-configured and isolated
β
Start/stop/delete instances in seconds
β
Run Odoo 17, 18, 19 simultaneously
β
Identical setup on any Windows/Mac/Linux machine
β
Production-ready from day oneReal-World Scenario
Imagine you're a developer managing three clients:
- Client A: Needs Odoo 18 for accounting
- Client B: Wants the latest Odoo 19 with custom modules
- Client C: Still running Odoo 16 (migrating next year)
With Docker, you run all three on the same machineβisolated, stable, professional. That's the power we're unlocking today.
ποΈ Understanding The Architecture
Think of our setup like an apartment building:
π’ The Odoo Hub (Your Computer)
βββ ποΈ The Landlord (PostgreSQL Database)
β βββ Stores all data for all tenants
β
βββ πͺ Tenant 1 (First Odoo Instance)
β βββ Your main production app
β
βββ πͺ Tenant 2 (Test Instance)
β βββ For trying new modules safely
β
βββ πͺ Tenant 3 (Client Demo)
βββ Show off features to clients
Key Insight: One PostgreSQL database server ("The Landlord") hosts multiple separate Odoo applications ("Tenants"). Each tenant is completely isolated but shares resources efficiently.
π οΈ Prerequisites: Your Toolkit
Required Software
Docker Desktop for Windows (Free)
- Download: docker.com/products/docker-desktop
- Ensure WSL2 is enabled during installation
- Restart your computer after installation
Visual Studio Code (Free)
- Download: code.visualstudio.com
- Install "Docker" extension (by Microsoft)
Basic Knowledge Check β
- Can you open PowerShell? β You're ready!
- Ever edited a text file? β Perfect!
- Comfortable following step-by-step instructions? β Let's go!
Verify Docker Installation
Open PowerShell (in VS Code or Windows Terminal):
# Check Docker is running
docker --version
# Should show: Docker version 24.x.x or higher
# Test Docker works
docker run hello-world
# Should download and run a test container
β¨ Pro Tip: If Docker commands fail, ensure Docker Desktop is running (check system tray for whale icon).
π Project Structure: Building Our Foundation
Let's create a clean, organized project structure. This naming convention will be your standard for every Odoo project.
Step 1: Create Your Project Folder
# Navigate to your preferred location
cd C:\Projects
# Create the main hub folder
mkdir odoo-hub
cd odoo-hub
Step 2: Create The Complete Structure
# Create all folders in one go
mkdir building-1
mkdir building-1\landlord
mkdir building-1\landlord\init
mkdir building-1\tenants
mkdir building-1\tenants\my-first-odoo
mkdir building-1\tenants\my-first-odoo\config
mkdir building-1\tenants\my-first-odoo\addons
Your Final Structure
π odoo-hub/
βββ π building-1/
βββ π docker-compose.yml β The brain of our operation
βββ π landlord/ β PostgreSQL configuration
β βββ π init/ β Database initialization scripts
βββ π tenants/ β All your Odoo instances live here
βββ π my-first-odoo/ β Your first tenant
βββ π config/ β Odoo configuration
β βββ π odoo.conf β Settings file
βββ π addons/ β Custom modules go here
π― Naming Convention Explained:
- building-1: Groups related Odoo instances (building-2 for enterprise, building-3 for staging, etc.)
- landlord: PostgreSQL server (one per building)
- tenants/tenant-name: Individual Odoo instances
- Format: lowercase, hyphens (not underscores), descriptive names
π Configuration Files: The Heart of Your Setup
File 1: Docker Compose (The Orchestrator)
Create building-1/docker-compose.yml:
services:
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ποΈ THE LANDLORD - PostgreSQL Database Server
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
landlord:
image: postgres:16
container_name: building-1-landlord
environment:
POSTGRES_DB: postgres
POSTGRES_USER: odoo
POSTGRES_PASSWORD: B1_SecurePass_2025!
volumes:
- landlord-data:/var/lib/postgresql/data
- ./landlord/init:/docker-entrypoint-initdb.d:ro
ports:
- "5432:5432"
restart: unless-stopped
networks:
- building-1-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U odoo"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
command: >
postgres
-c max_connections=200
-c shared_buffers=512MB
-c effective_cache_size=1536MB
labels:
- "hub.building=building-1"
- "hub.service=landlord"
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# πͺ TENANT: my-first-odoo (Odoo 19 Community)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
my-first-odoo:
image: odoo:19
container_name: my-first-odoo
depends_on:
landlord:
condition: service_healthy
ports:
- "8069:8069"
- "8072:8072"
volumes:
- ./tenants/my-first-odoo/config/odoo.conf:/etc/odoo/odoo.conf:ro
- ./tenants/my-first-odoo/addons:/mnt/extra-addons
- my-first-odoo-data:/var/lib/odoo
environment:
- HOST=building-1-landlord
- USER=odoo
- PASSWORD=B1_SecurePass_2025!
networks:
- building-1-network
extra_hosts:
Β Β Β - "host.docker.internal:host-gateway"
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8069/web/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
labels:
- "hub.building=building-1"
- "hub.tenant=my-first-odoo"
- "hub.version=19"
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π§ PGADMIN - Database Management GUI
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
pgadmin:
image: dpage/pgadmin4:latest
container_name: building-1-pgadmin
environment:
PGADMIN_DEFAULT_EMAIL: [email protected]
PGADMIN_DEFAULT_PASSWORD: admin123
ports:
- "5050:80"
volumes:
- pgadmin-data:/var/lib/pgadmin
networks:
- building-1-network
restart: unless-stopped
labels:
- "hub.building=building-1"
- "hub.service=pgadmin"
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# πΎ PERSISTENT STORAGE VOLUMES
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
volumes:
landlord-data:
name: building-1-landlord-data
my-first-odoo-data:
name: my-first-odoo-data
pgadmin-data:
name: building-1-pgadmin-data
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π NETWORKING - Isolated Communication
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
networks:
building-1-network:
name: building-1-network
driver: bridge
π Configuration Breakdown:
Component | Purpose | Access Point |
|---|---|---|
landlord | PostgreSQL database server | localhost:5432 |
my-first-odoo | Your Odoo application | localhost:8069 |
pgadmin | Visual database manager | localhost:5050 |
π― Key Settings Explained:
- depends_on: Ensures database starts before Odoo
- healthcheck: Verifies services are actually ready (not just running)
- restart: unless-stopped: Auto-recovery from crashes
- volumes: Preserves your data even if containers are deleted
- memory limits: Prevents one service from hogging all RAM
File 2: Odoo Configuration (The Brain)
Create building-1/tenants/my-first-odoo/config/odoo.conf:
[options]
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π ODOO CONFIGURATION - my-first-odoo
# Building: building-1 | Version: 19 | Port: 8069
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# ποΈ DATABASE CONNECTION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
db_host = building-1-landlord
db_port = 5432
db_user = odoo
db_password = B1_SecurePass_2025!
db_maxconn = 64
db_sslmode = prefer
# Database filter (shows only databases matching this pattern)
dbfilter = ^my_first_odoo_.*$
# Allow database listing (change to False in production)
list_db = True
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# β‘ SERVER CONFIGURATION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
http_interface = 0.0.0.0
http_port = 8069
# Worker processes (2 = good for development, increase for production)
workers = 2
max_cron_threads = 1
# Request timeout limits
limit_time_cpu = 600
limit_time_real = 1200
limit_time_real_cron = 3600
# Memory limits in bytes
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π FILE PATHS
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
data_dir = /var/lib/odoo
addons_path = /mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π LOGGING
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
log_level = info
log_db = False
log_handler = :INFO
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π SECURITY
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
admin_passwd = my_first_odoo_master_2025
# Enable proxy mode when behind nginx/reverse proxy
proxy_mode = False
# Disable demo data for cleaner setup
without_demo = all
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π¨ SESSION & PERFORMANCE
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Session timeout: 7 days (in seconds)
session_timeout = 604800
# Server-wide modules (always loaded)
server_wide_modules = base,web
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π PDF GENERATION
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
wkhtmltopdf_path = /usr/local/bin/wkhtmltopdf
report_url = http://host.docker.internal:8869
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# π§ EMAIL CONFIGURATION (configure after setup)
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# email_from = [email protected]
# smtp_server = smtp.gmail.com
# smtp_port = 587
# smtp_ssl = True
# smtp_user = [email protected]
# smtp_password = your-app-password
β¨ Configuration Highlights:
- dbfilter: Shows only databases starting with my_first_odoo_
- admin_passwd: Master password for database operations (CHANGE THIS!)
- workers = 2: Uses multi-processing for better performance
- addons_path: Loads both custom and standard modules
π Launch Sequence: Starting Your Odoo Empire
Step 1: Navigate to Your Project
# Open VS Code in your project folder
cd C:\Projects\odoo-hub\building-1
code .
Step 2: Start Everything
Open the VS Code integrated terminal (Ctrl + `) and run:
# Start all services
docker-compose up -d
# Expected output:
# [+] Running 4/4
# β Network building-1-network Created
# β Container building-1-landlord Started
# β Container my-first-odoo Started
# β Container building-1-pgadmin Started
π― Command Breakdown:
- docker-compose up: Starts all services defined in docker-compose.yml
- -d: Detached mode (runs in background)
Step 3: Monitor the Startup
# Watch Odoo logs in real-time
docker logs -f my-first-odoo
# Press Ctrl+C to stop watching (container keeps running)
β Success Indicators:
INFO ? odoo: Odoo version 19.0
INFO ? odoo: Using configuration file at /etc/odoo/odoo.conf
INFO ? odoo: addons paths: ['/mnt/extra-addons', ...]
INFO ? odoo.service.server: HTTP service (werkzeug) running on 0.0.0.0:8069
Step 4: Access Your Odoo Instance
Open your browser and navigate to:
http://localhost:8069
π First Launch Setup:
Create Your Database:
- Master Password: my_first_odoo_master_2025
- Database Name: my_first_odoo_production
- Email: [email protected]
- Password: Choose a strong password
- Demo Data: Uncheck (for clean setup)
- Language: English (or your preference)
- Click "Create Database" and wait 2-3 minutes
- Welcome to Odoo! π