Hey Guys... Haykins here π. Are you tired of managing multiple Odoo servers for different clients? scratch that. Letβs dockerize your hustle, make it scalable, and give each client their own domain β all on one Odoo engine. this also works out for B2B Startup adopting Odoo for their customers operational activities.
Quick Gist of what we are doing
We will be developing an Odoo setup where:
- And Odoo instance that serves multiple clients
- Each client has their own database
- Each database is accessible via a custom domain or subdomain like:
- client-1.haykinsodoo.docker
- client-2.haykinsodoo.docker
- client-3.haykinsodoo.docker
- Lastly, using Docker, PostgreSQL, Traefik for SSL & routing, sprinkles of Naija developer ginger π, and my PC with internet. NEPA or not π .
Now, let's get into it...
#1 Project Structure
let's get the project structure setup in this format:
βββ docker-compose.yml
βββ .env
βββ odoo.conf
βββ traefik/
βββ traefik.yml
βββ acme.json
#2 Setting up Environment Variables
we will be creating an .env file on the root folder.
ODOO_VERSION=18.0
ODOO_DB_USER=odoo
ODOO_DB_PASSWORD=password
POSTGRES_PASSWORD=password
DOMAINS=client-1.haykinsodoo.docker,client-2.haykinsodoo.docker,client-3.haykinsodoo.docker
#3 Setting up Docker Compose YAML
Next, we will be setting up the docker-compose.yml
file
# version: "3.9"
# Odoo with Traefik and PostgreSQL
# This docker-compose file sets up Odoo with Traefik as a reverse proxy and PostgreSQL as the database.
services:
db:
image: postgres:15
environment:
- POSTGRES_USER=${ODOO_DB_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 8432:5432
volumes:
- db-data:/var/lib/postgresql/data
secrets:
- postgresql_password
odoo:
image: odoo:${ODOO_VERSION}
depends_on:
- db
environment:
- HOST=db
- USER=${ODOO_DB_USER}
- PASSWORD=${ODOO_DB_PASSWORD}
secrets:
- postgresql_password
ports:
- "8069:8069"
- "8072:8072"
volumes:
- odoo-data:/var/lib/odoo
- ./odoo.conf:/etc/odoo/odoo.conf
- ./addons:/mnt/extra-addons
labels:
- "traefik.enable=true"
- "traefik.http.routers.odoo.rule=HostRegexp(`{subdomain:.+}.haykinsodoo.docker`)"
- "traefik.http.routers.odoo.entrypoints=web"
# - "traefik.http.routers.odoo.entrypoints=websecure"
# - "traefik.http.routers.odoo.tls=true"
# - "traefik.http.routers.odoo.tls.certresolver=letsencrypt"
- "traefik.http.services.odoo.loadbalancer.server.port=8069"
traefik:
image: traefik:v2.10
command:
- --api.insecure=true
- --providers.docker=true
# - --entrypoints.websecure.address=:443
- --entrypoints.web.address=:80
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.letsencrypt.acme.email=admin@haykinsodoo.docker
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
- "8080:8080" # Traefik dashboard port
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./traefik/traefik.yml:/traefik.yml
- ./traefik/acme.json:/letsencrypt/acme.json
volumes:
db-data:
odoo-data:
secrets:
postgresql_password:
file: odoo_pg_pass
#4 Setting up the Odoo Configuration
We continue with creatinf an odoo.conf
file and adding our configurations
[options]
addons_path = /mnt/extra-addons
admin_passwd = admin
db_host = db
db_port = 5432
db_user = odoo
db_password = password
dbfilter = ^%d$
xmlrpc_interface = 0.0.0.0
log_level = info
This dbfilter = ^%d$
simply means when the site: client-1.haykinsodoo.docker
is visited, Odoo will open client_1 as the database.
#5 Setting and Configuring Traefik
Let's create a traefik/traefik.yml
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
traefik:
address: ":8080"
api:
dashboard: true
insecure: true
providers:
docker:
exposedByDefault: false
Also, create acme.json
and set file permissions (access rights) to 600, so that only the file owner has read and write access, while no one else, including the group and others, has any access.
$ touch traefik/acme.json # create the file
$ chmod 600 traefik/acme.json # change file permission
#5 Let's get everything up and running
docker-compose up -d
Oshee! Our Odoo live... For us to access the different instances
-
client-1.haykinsodoo.docker
will serve the client-1 database. (note: ensure to copy the master password which will be re-used for all other clients installations) -
client-2.haykinsodoo.docker
will serve the client-2 database. -
client-3.haykinsodoo.docker
will serve the client-3 database.
Note In Prod: Make sure those subdomains point to your VPS/public IP address (you can use your domain providerβs DNS settings to handle this).
Bonus Bonus Bonus: Create a DB Manually (Optional)
$ docker exec -it <odoo_container_id> /bin/bash
# run the below code inside container
$ odoo -d client-1 --init=base --stop-after-init
Final 2kobo (thoughts π)
This entire process and setup gives you the power to serve, scale, and secure multiple Odoo clients like a true Odoo Developer and/or DevOps engineer. Itβs modular, clean, and cheap to maintain.
So whether youβre a developer, startup founder, or building the next ERP-as-a-Service, this is your kick-off point. With this setup, you're running your own multi-tenant Odoo app.
visit my GitHub for the full code setup: https://github.com/thisishaykins/multi-tenant-odoo-app
π Shoutout
Written by a Dev for Devs, proudly from the land of jollof, generators, and pure tech vibes. π³π¬
Built this with:
- My PC
- VS Code
- Docker
- Odoo
- Postgres
- Traefik
- Naija jollof rice πΆοΈ
Drop your questions below or tag me on Twitter/X: @thisishaykins
Top comments (0)