Votre installation Odoo n'est pas « terminée » quand la page de connexion s'affiche
Chaque déploiement Odoo commence par une installation. Et chaque incident de production que nous avons investigué chez Octura commence par une installation qui était « suffisante pour le moment ». La page de connexion s'affichait, les données de démonstration se chargeaient, et quelqu'un déclarait que c'était terminé. Six mois plus tard : la base de données ne supporte pas 50 utilisateurs simultanés, les sauvegardes n'ont jamais été testées, et le serveur tourne en root avec le mot de passe maître par défaut.
Odoo 19 a relevé la barre. Le runtime exige désormais PostgreSQL 15+, embarque une gestion de sessions werkzeug plus stricte, et le pipeline d'assets attend rtlcss et wkhtmltopdf 0.12.7 à des chemins spécifiques. Installez-le mal et vous obtiendrez des erreurs 500 cryptiques sur les rapports PDF, des expirations de session sous charge, et un système qui se dégrade silencieusement quand vous en avez le plus besoin.
Ce guide couvre trois méthodes d'installation — Docker, installation depuis les sources, et Odoo.sh — avec les étapes de durcissement production qui distinguent un jouet de staging d'un système sur lequel vous pouvez parier vos opérations.
Docker vs Source vs Odoo.sh : quelle méthode d'installation Odoo 19 convient à votre équipe
Il n'existe pas de méthode « universelle » pour installer Odoo. Le bon choix dépend de la maturité opérationnelle de votre équipe, de vos exigences de conformité, et du nombre de modules personnalisés que vous exploitez. Voici la comparaison honnête :
| Aspect | Docker | Installation source | Odoo.sh |
|---|---|---|---|
| Temps de mise en place | 15 minutes | 45 à 90 minutes | 5 minutes |
| Modules personnalisés | Volume monté ou image custom | Accès complet au système de fichiers | Sous-modules Git uniquement |
| Contrôle PostgreSQL | Conteneur séparé, configurable | Contrôle total, toute version | Géré (paramétrage limité) |
| Scalabilité | Horizontale via orchestration | Configuration multi-workers manuelle | Intégrée (avec limites du plan) |
| SSL / Proxy | Reverse proxy requis | Nginx / Caddy requis | Inclus |
| Sauvegardes | À votre charge (pg_dump + filestore) | À votre charge (pg_dump + filestore) | Automatique quotidienne |
| Coût | Votre infrastructure uniquement | Votre infrastructure uniquement | À partir de 32 $/mois + licence Odoo |
| Idéal pour | Équipes avec capacité DevOps | Personnalisation poussée, industries réglementées | PME souhaitant des opérations managées |
Pour la plupart des entreprises de taille intermédiaire, Docker avec un service PostgreSQL managé (AWS RDS, Google Cloud SQL, ou DigitalOcean Managed DB) offre le meilleur compromis. Vous obtenez des déploiements reproductibles sans gérer vous-même les sauvegardes, la réplication et le basculement de la base de données. L'installation depuis les sources est réservée aux clients dans des secteurs réglementés qui nécessitent une auditabilité au niveau du noyau.
Docker Compose de niveau production pour Odoo 19 : la stack complète
L'image Docker officielle d'Odoo vous amène à un écran de connexion. Elle ne vous amène pas en production. Voici le docker-compose.yml que nous utilisons comme point de départ pour les déploiements clients — avec le tuning PostgreSQL, des volumes persistants, des limites de ressources appropriées et un durcissement sécurité.
version: "3.8"
services:
odoo:
image: odoo:19.0
container_name: odoo19
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:8069:8069"
- "127.0.0.1:8072:8072" # longpolling / websocket
volumes:
- odoo-data:/var/lib/odoo
- ./custom-addons:/mnt/extra-addons:ro
- ./config/odoo.conf:/etc/odoo/odoo.conf:ro
environment:
- HOST=db
- USER=odoo
- PASSWORD_FILE=/run/secrets/db_password
secrets:
- db_password
deploy:
resources:
limits:
memory: 4G
cpus: "2.0"
db:
image: postgres:16-alpine
container_name: odoo19-db
restart: unless-stopped
environment:
- POSTGRES_USER=odoo
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
- POSTGRES_DB=postgres
volumes:
- pg-data:/var/lib/postgresql/data
- ./config/postgresql.conf:/etc/postgresql/postgresql.conf:ro
command: postgres -c config_file=/etc/postgresql/postgresql.conf
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U odoo"]
interval: 10s
timeout: 5s
retries: 5
deploy:
resources:
limits:
memory: 2G
secrets:
db_password:
file: ./secrets/db_password.txt
volumes:
odoo-data:
pg-data:Détails clés que la plupart des tutoriels omettent :
- Ports liés à 127.0.0.1 — n'exposez jamais Odoo directement à internet. Nginx ou Caddy se place devant.
- Docker secrets pour le mot de passe de la base — pas des variables d'environnement qui fuient dans la sortie de
docker inspect. - Health check sur PostgreSQL — Odoo n'entrera pas en boucle de crash en attendant un démarrage lent de la base.
- Addons personnalisés montés en lecture seule — empêche les écritures accidentelles par le processus Odoo.
- Limites mémoire — sans elles, une génération de rapport incontrôlée provoquera un OOM-kill de tout l'hôte.
[options]
; ── Security ──────────────────────────────────
admin_passwd = False
list_db = False
proxy_mode = True
; ── Performance ───────────────────────────────
workers = 4
max_cron_threads = 2
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_cpu = 600
limit_time_real = 1200
limit_time_real_cron = 1800
; ── Database ──────────────────────────────────
db_host = db
db_port = 5432
db_user = odoo
db_name = production
dbfilter = ^production$
; ── Paths ─────────────────────────────────────
addons_path = /mnt/extra-addons,/usr/lib/python3/dist-packages/odoo/addons
data_dir = /var/lib/odoo Définir admin_passwd = False désactive entièrement le gestionnaire de base de données. C'est non négociable en production. Le gestionnaire de base de données permet à quiconque de créer, dupliquer, supprimer ou restaurer des bases — avec un seul mot de passe protégeant l'ensemble de l'opération. Combiné avec list_db = False et dbfilter, cela verrouille l'instance sur une seule base de données sans surface de gestion web.
Installer Odoo 19 depuis les sources sur Ubuntu 24.04 : étape par étape avec durcissement sécurité
L'installation depuis les sources vous donne un contrôle total. C'est aussi la plus facile à mal configurer. Voici la séquence que nous suivons pour les déploiements bare-metal et VM.
Dépendances système
# System user — never run Odoo as root
sudo adduser --system --home=/opt/odoo --group odoo
# PostgreSQL 16
sudo apt install -y postgresql-16 postgresql-client-16
# Create DB role (no superuser, no createdb in production)
sudo -u postgres createuser --createdb --no-superuser \
--no-createrole odoo
# Python build deps + Odoo runtime deps
sudo apt install -y \
python3-dev python3-pip python3-venv \
libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \
libpq-dev libjpeg-dev zlib1g-dev \
node-less npm git
# wkhtmltopdf 0.12.7 (Odoo 19 requirement)
wget https://github.com/wkhtmltopdf/packaging/releases/\
download/0.12.7-1/wkhtmltox_0.12.7-1.jammy_amd64.deb
sudo dpkg -i wkhtmltox_0.12.7-1.jammy_amd64.deb
sudo apt install -f -y
# rtlcss for RTL language support
sudo npm install -g rtlcssCloner et configurer
# Clone Odoo 19 (shallow clone saves ~2GB)
sudo -u odoo git clone --depth 1 --branch 19.0 \
https://github.com/odoo/odoo.git /opt/odoo/odoo
# Virtual environment (isolated from system Python)
sudo -u odoo python3 -m venv /opt/odoo/venv
sudo -u odoo /opt/odoo/venv/bin/pip install --upgrade pip wheel
sudo -u odoo /opt/odoo/venv/bin/pip install \
-r /opt/odoo/odoo/requirements.txt
# Enterprise (if licensed)
sudo -u odoo git clone --depth 1 --branch 19.0 \
https://github.com/odoo/enterprise.git /opt/odoo/enterprise
# Custom addons
sudo mkdir -p /opt/odoo/custom-addons
sudo chown odoo:odoo /opt/odoo/custom-addonsService Systemd
[Unit]
Description=Odoo 19
After=postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=odoo
Group=odoo
ExecStart=/opt/odoo/venv/bin/python /opt/odoo/odoo/odoo-bin \
-c /etc/odoo/odoo.conf
StandardOutput=journal
StandardError=journal
# Security hardening
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/odoo/.local /var/log/odoo
NoNewPrivileges=true
PrivateTmp=true
# Restart policy
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target Les directives ProtectSystem=strict et NoNewPrivileges=true rendent l'intégralité du système de fichiers en lecture seule pour le processus Odoo, sauf les chemins explicitement autorisés. C'est de la défense en profondeur : même si un attaquant obtient l'exécution de code via une vulnérabilité dans un module personnalisé, il ne peut ni modifier les binaires système ni escalader ses privilèges.
Reverse Proxy Nginx
upstream odoo_backend {
server 127.0.0.1:8069;
}
upstream odoo_longpoll {
server 127.0.0.1:8072;
}
server {
listen 443 ssl http2;
server_name erp.yourcompany.com;
ssl_certificate /etc/letsencrypt/live/erp.yourcompany.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/erp.yourcompany.com/privkey.pem;
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
# Odoo request size (large imports, attachments)
client_max_body_size 256m;
# Timeouts for long operations (reports, exports)
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;
location / {
proxy_pass http://odoo_backend;
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;
proxy_redirect off;
}
location /websocket {
proxy_pass http://odoo_longpoll;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
# Block database manager from outside
location ~* ^/web/database {
deny all;
return 404;
}
# Static file caching
location ~* /web/static/ {
proxy_pass http://odoo_backend;
expires 365d;
add_header Cache-Control "public, immutable";
}
}3 erreurs d'installation qui paralysent Odoo 19 en production
Tourner avec workers = 0 (mode mono-thread)
Le odoo.conf par défaut est livré avec workers = 0, ce qui exécute Odoo en mode mono-thread. Cela signifie qu'une seule génération de rapport lente bloque tous les autres utilisateurs. Un export PDF qui prend 30 secondes verrouille l'application entière pour les 50 utilisateurs. Nous avons vu des entreprises fonctionner ainsi pendant des mois, accusant « Odoo est lent » alors que le vrai coupable était un paramètre par défaut prévu pour le développement.
Définissez workers = (nb coeurs CPU * 2) + 1 comme base. Pour un serveur 4 coeurs, cela donne 9 workers. Puis configurez max_cron_threads = 2 séparément pour que les actions planifiées ne volent pas de slots aux workers HTTP. Surveillez avec htop aux heures de pointe et ajustez jusqu'à ce que le CPU reste sous 70 %.
PostgreSQL avec les paramètres par défaut
Une installation fraîche de PostgreSQL 16 alloue 128 Mo de shared buffers — suffisant pour un blog personnel, pas pour un ERP gérant 10 000 écritures comptables. Nous trouvons régulièrement des serveurs Odoo où la base de données est le goulot d'étranglement, mais personne n'a vérifié pg_stat_user_tables parce que « la base a été configurée par l'hébergeur ».
Tuning minimum pour une base Odoo de production sur un serveur 16 Go de RAM : shared_buffers = 4GB, effective_cache_size = 12GB, work_mem = 64MB, maintenance_work_mem = 1GB. Utilisez PGTune comme point de départ, puis profilez avec pg_stat_statements pour trouver les vraies requêtes lentes.
Aucune stratégie de sauvegarde automatisée
« On mettra en place les sauvegardes après la mise en production » est la phrase la plus coûteuse du déploiement ERP. Le filestore Odoo (pièces jointes, images, rapports) vit sur le disque en dehors de PostgreSQL. Un pg_dump seul restaure une base avec des liens de pièces jointes cassés. Nous avons été appelés pour des situations de récupération où une entreprise avait perdu 6 mois de bons de commande uploadés parce que personne n'avait sauvegardé /var/lib/odoo/filestore.
Nous déployons un cron qui exécute pg_dump et rsync du répertoire filestore vers un stockage distant (S3, Backblaze B2, ou un serveur séparé). Les sauvegardes sont chiffrées avec gpg, la rétention est de 30 quotidiennes + 12 mensuelles, et nous lançons un test de restauration mensuel sur un serveur de staging pour prouver que la sauvegarde fonctionne réellement. Une sauvegarde non testée n'est pas une sauvegarde.
Ce qu'une installation correcte fait économiser à votre entreprise
L'installation n'est pas un coût ponctuel — c'est la fondation qui détermine votre coût total de possession. Voici ce que nous observons sur le terrain :
Une configuration correcte des workers et le tuning PostgreSQL éliminent la plainte n°1 des déploiements Odoo.
Des sauvegardes automatisées et testées signifient que vous ne payez jamais de récupération d'urgence — qui coûte en moyenne entre 5 000 et 25 000 $.
Avec des templates Docker Compose, les nouveaux environnements sont opérationnels en heures au lieu du processus manuel de 2 à 3 jours.
Le vrai ROI ne réside pas dans l'installation elle-même — il est dans les incidents qui ne se produisent jamais. Chaque décision de configuration ci-dessus — de NoNewPrivileges dans systemd à admin_passwd = False dans odoo.conf — supprime un mode de défaillance qui vous coûterait autrement des heures d'indisponibilité, des tickets de support, ou pire : une faille de sécurité qui érode la confiance de vos clients.
Métadonnées d'optimisation
Installation Odoo 19 prête pour la production via Docker et source. Couvre le tuning PostgreSQL, le durcissement sécurité, la configuration Nginx et la stratégie de sauvegarde.
1. « Docker vs Source vs Odoo.sh : quelle méthode d'installation Odoo 19 convient à votre équipe »
2. « Docker Compose de niveau production pour Odoo 19 : la stack complète »
3. « 3 erreurs d'installation qui paralysent Odoo 19 en production »