La réponse courte
Pour héberger Odoo sur Azure, faites-le tourner sur une VM x86 d'usage général avec un disque Premium SSD. Mettez Postgres sur la même VM ou sur Azure Database for PostgreSQL. N'ouvrez que les ports 80 et 443, et connectez-vous via Azure Bastion au lieu d'un port SSH public. Envoyez les sauvegardes de la base et des fichiers vers un container Blob Storage où la VM peut écrire, mais ni lire ni supprimer. Évitez les VM de la série B pour la production, et testez une restauration avant la mise en ligne.
Beaucoup d'entreprises tournent déjà sur Microsoft 365 et Azure, alors Odoo y va aussi. Azure a une région près de presque tout le monde. Il offre aussi beaucoup de façons de mal régler Odoo, juste un peu. Ce guide vous donne les commandes exactes pour chaque étape Azure.
Pour l'installation elle-même (Odoo, Postgres, le fichier de configuration et le proxy), suivez notre guide sur Odoo sur un VPS. Cette page couvre ce qui change sur Azure.
Vous pouvez lancer toutes les commandes az ci-dessous depuis votre propre ordinateur avec l'Azure CLI, ou depuis Azure Cloud Shell dans le portail. Une étape, la connexion par Bastion, demande la CLI sur votre propre ordinateur. Remplacez les noms en majuscules par les vôtres. Les exemples utilisent la région westeurope. Utilisez la vôtre.
Quelle taille de VM choisir
Deux choses comptent le plus pour Odoo :
- La mémoire. Le minimum pour démarrer est de 2 vCPU, 4 Go de mémoire et un disque de 50 Go. Cela fait tourner Odoo et Postgres sur une seule VM pour une petite équipe. Chaque worker a besoin de sa part de mémoire, et Postgres veut la sienne. Pour plus d'utilisateurs, de gros imports ou Azure Database for PostgreSQL, notre guide sur le nombre de workers Odoo dont vous avez besoin montre comment bien dimensionner.
- Un CPU stable. Odoo travaille toute la journée, tant que les gens l'utilisent.
Pourquoi pas une VM de la série B
Les VM de la série B sont « burstable ». Elles gagnent des crédits CPU quand elles sont calmes et les dépensent quand elles sont occupées. Quand les crédits sont épuisés, Azure ralentit la VM à son niveau de base, jusqu'à ce qu'elle en regagne. Un Odoo utilisé toute la journée peut épuiser ses crédits en pleine journée de travail. Alors chaque page devient lente.
Pour la production, choisissez donc une taille d'usage général avec un CPU fixe, par exemple :
- Standard_D2s_v5 (Intel) ou Standard_D2as_v5 (AMD). 2 vCPU et 8 Gio de mémoire. Un bon choix par défaut.
- Une génération plus récente, comme Standard_D2s_v6, si votre région la propose.
- Une taille de la série E (plus de mémoire par CPU) quand Postgres tourne sur la même VM et que la base est grosse.
Les VM de la série B conviennent pour une copie de test que peu de gens utilisent.
Choisir une taille x86
Azure vend aussi des tailles Arm, comme Dpsv5 et Dpsv6 (Azure Cobalt). Choisissez plutôt une taille Intel ou AMD. Si vous pensez nous confier le travail Odoo plus tard, c'est important : notre logiciel bring your own server tourne uniquement sur des serveurs x86.
Image
Utilisez Ubuntu Server 22.04 LTS ou Debian 12. wkhtmltopdf, qu'Odoo utilise pour imprimer les PDF, a des paquets officiels pour les deux (jammy et bookworm). Imprimez une facture avant la mise en ligne.
Dans la CLI, Ubuntu 22.04 est l'image Ubuntu2204. Pour Debian 12, trouvez le nom exact de l'image avec :
az vm image list --publisher Debian --offer debian-12 --all --output table
Disque : Premium SSD
Utilisez un Premium SSD (Premium_LRS) pour le disque système. Premium SSD v2 est plus rapide, mais il ne peut pas servir de disque système. Vous pourrez en ajouter un plus tard comme disque de données, si besoin.
Sur Premium SSD, la vitesse grandit avec la taille du disque. Un disque de 128 Gio a plus d'IOPS qu'un disque de 64 Gio. Gardez de la place pour le filestore et trois jours de sauvegardes locales.
Région
Choisissez la région avec soin. Votre VM, votre base et vos disques vivent dans la région choisie. Mettez la VM, la base et le stockage des sauvegardes dans la même région, sauf si vous voulez exprès des sauvegardes dans une deuxième région.
Réseau et règles de sécurité
Créer le réseau
Tout va dans un seul resource group et un seul réseau virtuel (VNet). Le VNet reçoit trois sous-réseaux : un pour la VM, un pour Azure Bastion et un pour la base.
az group create --name odoo-rg --location westeurope
az network vnet create --resource-group odoo-rg --name odoo-vnet \
--address-prefixes 10.0.0.0/16 \
--subnet-name odoo-web --subnet-prefixes 10.0.1.0/24
az network vnet subnet create --resource-group odoo-rg --vnet-name odoo-vnet \
--name AzureBastionSubnet --address-prefixes 10.0.2.0/26
az network vnet subnet create --resource-group odoo-rg --vnet-name odoo-vnet \
--name odoo-db --address-prefixes 10.0.3.0/27 \
--delegations Microsoft.DBforPostgreSQL/flexibleServers
Bastion a besoin d'un sous-réseau qui s'appelle exactement AzureBastionSubnet, de taille /26 ou plus. Le sous-réseau de la base est « délégué ». Seul Azure Database for PostgreSQL peut l'utiliser. Vous ne pourrez pas l'agrandir plus tard, alors ne descendez pas sous /27. Sautez le sous-réseau odoo-db si Postgres reste sur la VM.
Network security group
Créez un network security group (NSG) et n'autorisez que le trafic web venant d'internet :
az network nsg create --resource-group odoo-rg --name odoo-web-nsg
az network nsg rule create --resource-group odoo-rg --nsg-name odoo-web-nsg \
--name allow-web --priority 100 --direction Inbound --access Allow \
--protocol Tcp --source-address-prefixes Internet \
--destination-port-ranges 80 443
az network nsg rule create --resource-group odoo-rg --nsg-name odoo-web-nsg \
--name allow-ssh-from-bastion --priority 110 --direction Inbound --access Allow \
--protocol Tcp --source-address-prefixes 10.0.2.0/26 \
--destination-port-ranges 22
az network vnet subnet update --resource-group odoo-rg --vnet-name odoo-vnet \
--name odoo-web --network-security-group odoo-web-nsg
Le port 22 n'est ouvert qu'au sous-réseau Bastion, pas à internet. Les règles par défaut d'Azure bloquent tout autre trafic venant d'internet. Les ports d'Odoo (8069 et 8072) restent fermés. Seul nginx, sur la VM, leur parle.
Vérifiez les règles :
az network nsg rule list --resource-group odoo-rg --nsg-name odoo-web-nsg --output table
Créer la VM
Une adresse fixe
Créez d'abord une IP publique Standard. Les IP Standard sont toujours statiques, l'adresse ne change donc pas quand la VM s'arrête et redémarre :
az network public-ip create --resource-group odoo-rg --name odoo-ip --sku Standard
az network public-ip show --resource-group odoo-rg --name odoo-ip \
--query "{ip:ipAddress, method:publicIPAllocationMethod}" --output table
La méthode doit indiquer Static. Faites pointer l'enregistrement DNS de votre domaine vers cette adresse avant de demander un certificat à Let's Encrypt.
La lancer
az vm create \
--resource-group odoo-rg --name odoo-vm \
--image Ubuntu2204 \
--size Standard_D2s_v5 \
--vnet-name odoo-vnet --subnet odoo-web \
--nsg "" \
--public-ip-address odoo-ip \
--storage-sku Premium_LRS --os-disk-size-gb 128 \
--assign-identity \
--admin-username azureuser --generate-ssh-keys
Ce que font ces options :
--nsg ""n'ajoute pas de deuxième NSG sur la VM elle-même. Le NSG du sous-réseau, créé plus haut, s'applique.--assign-identitydonne à la VM une managed identity attribuée par le système. C'est l'identité propre de la VM dans Azure. Elle permet à la VM d'écrire les sauvegardes et d'envoyer les chiffres du disque, sans mot de passe ni clé stockés dessus.--generate-ssh-keysgarde une clé de secours pour le compteazureuser. Vous ne l'utiliserez pas au quotidien.
Vérifiez que l'identité existe, et notez son ID. Vous en aurez besoin plus tard :
az vm identity show --resource-group odoo-rg --name odoo-vm --query principalId --output tsv
Si une VM tourne déjà sans identité, ajoutez-en une avec :
az vm identity assign --resource-group odoo-rg --name odoo-vm
Vérifier que les ports d'Odoo sont fermés
Une fois Odoo en marche, vérifiez depuis votre propre ordinateur que seul nginx répond :
nc -zv -w 5 YOUR_PUBLIC_IP 8069
Cette commande doit expirer. Si elle se connecte, vérifiez les règles NSG ci-dessus.
Se connecter avec Bastion, pas par un port SSH public
Azure Bastion vous donne un shell sur la VM sans ouvrir le port 22 à internet. Vous vous connectez avec votre compte Microsoft Entra ID, il n'y a donc aucune clé SSH à partager ou à perdre.
Activer la connexion Entra ID sur la VM
Installez l'extension de connexion, et donnez-vous le rôle de connexion admin :
az vm extension set --resource-group odoo-rg --vm-name odoo-vm \
--publisher Microsoft.Azure.ActiveDirectory --name AADSSHLoginForLinux
az role assignment create \
--role "Virtual Machine Administrator Login" \
--assignee "$(az account show --query user.name --output tsv)" \
--scope "$(az group show --name odoo-rg --query id --output tsv)"
L'extension a besoin de la managed identity de la VM, que vous avez déjà ajoutée. Être propriétaire de l'abonnement ne suffit pas pour se connecter. Il vous faut ce rôle.
Créer Bastion
Pour vous connecter depuis votre propre terminal, il faut le SKU Standard, avec le « tunneling » (native client support) activé :
az network public-ip create --resource-group odoo-rg --name odoo-bastion-ip --sku Standard
az network bastion create --resource-group odoo-rg --name odoo-bastion \
--vnet-name odoo-vnet --public-ip-address odoo-bastion-ip \
--sku Standard --enable-tunneling true --location westeurope
Cela prend quelques minutes. Bastion est facturé pour chaque heure où il existe.
Se connecter
Depuis votre propre ordinateur (cette commande ne fonctionne pas dans Cloud Shell) :
az extension add --name ssh
az login
VM_ID=$(az vm show --resource-group odoo-rg --name odoo-vm --query id --output tsv)
az network bastion ssh --name odoo-bastion --resource-group odoo-rg \
--target-resource-id "$VM_ID" --auth-type AAD
Vous arrivez en tant que votre utilisateur Entra ID, et vous pouvez utiliser sudo.
Où mettre Postgres
Vous avez deux bonnes options :
- Sur la même VM. Simple, et très bien pour beaucoup d'équipes. Suivez le guide VPS tel quel.
- Sur Azure Database for PostgreSQL (Flexible Server). Azure gère le serveur de base de données, les correctifs et la restauration à un instant donné. Les étapes sont ci-dessous.
Préparer la zone DNS privée
Avec l'accès privé, la base n'a pas d'adresse publique. Les VM du VNet la trouvent grâce à une zone DNS privée. Créez la zone et reliez-la au VNet :
az network private-dns zone create --resource-group odoo-rg \
--name odoo.private.postgres.database.azure.com
az network private-dns link vnet create --resource-group odoo-rg \
--zone-name odoo.private.postgres.database.azure.com \
--name odoo-vnet-link --virtual-network odoo-vnet --registration-enabled false
Le nom de la zone doit finir par postgres.database.azure.com.
Créer le serveur de base de données
Tapez le mot de passe admin dans une variable, pour qu'il reste hors de l'historique de votre shell :
read -s -p "Admin password: " PGADMIN_PW; echo
az postgres flexible-server create \
--resource-group odoo-rg --name YOUR_DB_SERVER --location westeurope \
--tier GeneralPurpose --sku-name Standard_D2ds_v5 \
--version 17 \
--storage-size 64 --storage-auto-grow Enabled \
--admin-user odoo_admin --admin-password "$PGADMIN_PW" \
--vnet odoo-vnet --subnet odoo-db \
--private-dns-zone odoo.private.postgres.database.azure.com \
--backup-retention 14
Ce que font ces options :
--tier GeneralPurposeévite le tier Burstable, qui a les mêmes limites de crédits que les VM de la série B.--version 17est un exemple. Choisissez une version que votre version d'Odoo prend en charge.--storage-auto-grow Enabledagrandit le disque avant qu'il soit plein. Un serveur plein passe en lecture seule.--backup-retention 14garde 14 jours de sauvegardes du serveur. La valeur par défaut est 7, et le maximum 35.- Ajoutez
--geo-redundant-backup Enabledpour copier aussi les sauvegardes dans la région jumelée. Vous ne pouvez choisir cette option qu'à la création du serveur. - Ajoutez
--zonal-resiliency Enabledpour une copie de secours dans une autre zone (haute disponibilité). Les anciennes versions de la CLI l'appellent--high-availability ZoneRedundant.
Depuis la VM, vérifiez que le nom pointe vers une adresse privée dans 10.0.3.0/27 :
getent hosts YOUR_DB_SERVER.postgres.database.azure.com
Autoriser l'extension pg_trgm
Odoo active l'extension pg_trgm quand il crée une base. Azure n'autorise que les extensions que vous avez d'abord listées :
az postgres flexible-server parameter set --resource-group odoo-rg \
--server-name YOUR_DB_SERVER --name azure.extensions --value pg_trgm
Si vous mettez unaccent = True dans odoo.conf, utilisez --value pg_trgm,unaccent. Vérifiez la liste avec SHOW azure.extensions; dans psql.
Créer l'utilisateur de base de données odoo
Odoo a besoin de son propre utilisateur, qui peut créer des bases. N'utilisez pas l'utilisateur admin au quotidien. L'utilisateur admin n'est pas un superuser. Il est membre de azure_pg_admin, avec les droits de créer des rôles et des bases.
Sur la VM, installez le client Postgres (voir « Prendre la bonne version du client Postgres » plus bas), puis connectez-vous :
psql "host=YOUR_DB_SERVER.postgres.database.azure.com user=odoo_admin dbname=postgres sslmode=require"
CREATE ROLE odoo WITH LOGIN CREATEDB PASSWORD 'a-long-random-password';
Le chat en direct d'Odoo se connecte à la base postgres, pas seulement à la vôtre. Vérifiez que l'utilisateur odoo peut s'y connecter :
psql "host=YOUR_DB_SERVER.postgres.database.azure.com user=odoo dbname=postgres sslmode=require" -c 'SELECT current_user;'
Laissez Odoo créer yourdb lui-même. À son premier démarrage avec -d yourdb, Odoo crée la base en tant qu'utilisateur odoo, donc odoo en est le propriétaire. Vérifiez le propriétaire avec \l yourdb dans psql.
Ne la créez pas en tant qu'admin avec CREATE DATABASE yourdb OWNER odoo. À partir de Postgres 16, cela échoue, sauf si l'admin a le droit d'agir en tant que odoo.
Relier Odoo au serveur de base de données
Dans odoo.conf :
db_host = YOUR_DB_SERVER.postgres.database.azure.com
db_port = 5432
db_user = odoo
db_password = a-long-random-password
db_sslmode = require
Azure active require_secure_transport par défaut. Il refuse les connexions sans TLS. db_sslmode = require fait qu'Odoo l'utilise toujours.
Limites de connexions et PgBouncer
Chaque processus Odoo peut ouvrir jusqu'à db_maxconn connexions (64 par défaut). Additionnez vos workers, vos threads cron et le processus du chat, et multipliez par db_maxconn. Gardez ce total sous la limite du serveur. Un serveur Standard_D2ds_v5 accepte 844 connexions utilisateur. Un petit Burstable B1ms n'en accepte que 35, il lui faut donc un db_maxconn bien plus bas.
Azure a un PgBouncer intégré sur le port 6432. Par défaut, il regroupe les connexions en mode transaction. Le chat en direct d'Odoo garde une connexion LISTEN, et le mode transaction la casse. Gardez Odoo sur le port 5432.
Prendre la bonne version du client Postgres
pg_dump refuse de sauvegarder un serveur d'une version majeure plus récente que la sienne. Si le serveur tourne en Postgres 17, la VM a besoin du client en version 17. Installez-le depuis le dépôt apt de PostgreSQL :
sudo apt install -y postgresql-common
sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh
sudo apt install -y postgresql-client-17
Les sauvegardes du serveur ne couvrent pas le filestore
Azure sauvegarde le serveur de base de données et peut le restaurer à n'importe quel moment de la période de rétention. Il ne sauvegarde pas le filestore. Les pièces jointes et les images vivent sur le disque de la VM, dans /var/lib/odoo/filestore. Il vous faut quand même la sauvegarde Blob Storage ci-dessous, pour que la base et les fichiers soient sauvegardés ensemble.
Sauvegardes vers Blob Storage
Créer le storage account
Les noms de storage account sont partagés par tous les clients Azure. Utilisez de 3 à 24 lettres minuscules et chiffres, et choisissez un nom unique :
az storage account create --resource-group odoo-rg --name STORAGE_ACCOUNT \
--location westeurope --kind StorageV2 --sku Standard_GRS \
--min-tls-version TLS1_2 \
--allow-blob-public-access false \
--allow-shared-key-access false
Ce que font ces options :
Standard_GRSgarde une deuxième copie dans la région jumelée. Vérifiez que cette paire respecte vos règles sur les données. Sinon, utilisezStandard_ZRS(des copies dans trois zones d'une seule région).--allow-blob-public-access falseveut dire qu'aucun container ne pourra jamais devenir public.--allow-shared-key-access falsedésactive les clés du compte. Chaque requête doit venir d'une identité Entra ID, comme celle de la VM. Aucune clé ne peut donc être volée.
Vérifiez-le :
az storage account show --resource-group odoo-rg --name STORAGE_ACCOUNT \
--query "{publicAccess:allowBlobPublicAccess, sharedKey:allowSharedKeyAccess}"
Les deux doivent valoir false.
Activer le versioning et le soft delete
Le versioning garde l'ancienne copie quand un fichier est écrasé ou supprimé. Le soft delete garde les fichiers et les versions supprimés pendant un nombre de jours fixé :
az storage account blob-service-properties update --resource-group odoo-rg \
--account-name STORAGE_ACCOUNT \
--enable-versioning true \
--enable-delete-retention true --delete-retention-days 14 \
--enable-container-delete-retention true --container-delete-retention-days 14
Créer le container
az storage container-rm create --resource-group odoo-rg \
--storage-account STORAGE_ACCOUNT --name your-odoo-backups --enable-vlw
--enable-vlw ne verrouille rien pour l'instant. Il rend seulement possible, plus tard, le verrouillage en option décrit ci-dessous.
Supprimer les anciennes sauvegardes à date fixe
Enregistrez ceci sous lifecycle.json :
{
"rules": [
{
"enabled": true,
"name": "expire-old-odoo-backups",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"]
},
"actions": {
"baseBlob": {
"delete": { "daysAfterModificationGreaterThan": 30 }
},
"version": {
"delete": { "daysAfterCreationGreaterThan": 30 }
}
}
}
}
]
}
az storage account management-policy create --resource-group odoo-rg \
--account-name STORAGE_ACCOUNT --policy @lifecycle.json
Les sauvegardes de plus de 30 jours sont supprimées. Avec le versioning, « supprimé » veut d'abord dire « gardé comme version précédente ». La version précédente reste encore 30 jours, puis part. Le soft delete la garde ensuite 14 jours de plus. Une nouvelle politique peut mettre jusqu'à 24 heures à s'appliquer. Cette commande remplace la politique de cycle de vie que le compte avait avant.
Laisser la VM écrire, et seulement écrire
Azure n'a pas de rôle intégré qui peut seulement écrire des blobs. Vous en créez donc un. Il autorise deux actions : écrire un blob, et en ajouter un nouveau. Pas de lecture, pas de liste, pas de suppression. Enregistrez ceci sous odoo-backup-writer.json, avec l'ID de votre abonnement :
{
"Name": "Odoo Backup Writer",
"IsCustom": true,
"Description": "Upload Odoo backups. No read, list or delete.",
"Actions": [],
"NotActions": [],
"DataActions": [
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/write",
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/add/action"
],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/SUBSCRIPTION_ID/resourceGroups/odoo-rg"
]
}
az account show --query id --output tsv affiche l'ID de votre abonnement. Créez le rôle, et donnez-le à l'identité de la VM, sur le container de sauvegarde uniquement :
az role definition create --role-definition odoo-backup-writer.json
PRINCIPAL_ID=$(az vm identity show --resource-group odoo-rg --name odoo-vm \
--query principalId --output tsv)
CONTAINER_SCOPE="$(az storage account show --resource-group odoo-rg \
--name STORAGE_ACCOUNT --query id --output tsv)/blobServices/default/containers/your-odoo-backups"
az role assignment create --assignee-object-id "$PRINCIPAL_ID" \
--assignee-principal-type ServicePrincipal \
--role "Odoo Backup Writer" --scope "$CONTAINER_SCOPE"
Un nouveau rôle et son attribution peuvent mettre quelques minutes à fonctionner.
La VM peut envoyer des fichiers, mais elle ne peut ni lister, ni lire, ni supprimer quoi que ce soit dans le container. Si quelqu'un entre dans le serveur, il ne peut ni lire vos anciennes sauvegardes ni les effacer. Écraser un fichier est permis, mais le versioning garde l'ancienne copie.
Si votre envoi échoue avec une erreur de permission (403), l'outil d'envoi a besoin de plus que ces deux actions. Donnez alors plutôt à l'identité de la VM le rôle intégré Storage Blob Data Contributor, sur le même scope de container. Ce rôle peut lire et supprimer les fichiers actuels. Il ne peut pas supprimer les anciennes versions, donc le versioning et le soft delete gardent toujours vos copies.
En option : verrouiller les sauvegardes pour une durée fixée
Si vos règles internes demandent plus, une retention policy basée sur le temps bloque les suppressions pendant un nombre de jours fixé, même pour un admin :
az storage container immutability-policy create \
--account-name STORAGE_ACCOUNT --container-name your-odoo-backups --period 14
La policy démarre « unlocked », vous pouvez donc encore la modifier ou la retirer pendant vos tests. Une fois que vous l'avez verrouillée dans le portail (Container > Access policy > Lock policy), vous ne pouvez plus la retirer. Gardez une durée plus courte que la règle de cycle de vie de 30 jours. Testez-la d'abord sur un compte de test.
Installer AzCopy sur la VM
curl -sSL -O https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y azcopy
Sur Debian 12, mettez config/debian/12/ dans l'adresse. AzCopy utilise la managed identity de la VM quand AZCOPY_AUTO_LOGIN_TYPE=MSI est défini. Vous ne stockez jamais de clé ni de mot de passe sur le serveur.
Le script de sauvegarde
Créez d'abord le dossier local :
sudo mkdir -p /backups
sudo chown odoo:odoo /backups
Enregistrez ceci sous /usr/local/bin/odoo-backup.sh et lancez sudo chmod 755 dessus :
#!/bin/bash
# /usr/local/bin/odoo-backup.sh, run as the odoo user
set -euo pipefail
DB=yourdb
DAY=$(date +%F)
DIR=/backups/$DAY
mkdir -p "$DIR"
pg_dump -Fc "$DB" > "$DIR/$DB.dump"
tar -czf "$DIR/$DB-filestore.tar.gz" -C /var/lib/odoo/filestore "$DB"
AZCOPY_AUTO_LOGIN_TYPE=MSI azcopy copy "$DIR/*" "https://STORAGE_ACCOUNT.blob.core.windows.net/your-odoo-backups/$DAY"
find /backups -mindepth 1 -maxdepth 1 -type d -mtime +3 -exec rm -rf {} +
Avec Azure Database for PostgreSQL, pg_dump doit se connecter par le réseau. Remplacez la ligne pg_dump par :
pg_dump -h YOUR_DB_SERVER.postgres.database.azure.com -U odoo -Fc "$DB" > "$DIR/$DB.dump"
Puis donnez à l'utilisateur odoo son mot de passe dans un fichier .pgpass, dans son dossier personnel :
sudo -u odoo -H bash -c 'echo "YOUR_DB_SERVER.postgres.database.azure.com:5432:*:odoo:a-long-random-password" > ~/.pgpass && chmod 600 ~/.pgpass'
Le * permet à la même ligne de servir pour toutes les bases, y compris celle du test de restauration.
Le lancer chaque nuit
Créez /etc/systemd/system/odoo-backup.service :
[Unit]
Description=Odoo backup to Blob Storage
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
User=odoo
ExecStart=/usr/local/bin/odoo-backup.sh
Et /etc/systemd/system/odoo-backup.timer :
[Unit]
Description=Run the Odoo backup every night
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
Activez-le, puis lancez-le une fois à la main et vérifiez le résultat :
sudo systemctl daemon-reload
sudo systemctl enable --now odoo-backup.timer
sudo systemctl start odoo-backup.service
journalctl -u odoo-backup.service -n 20
Depuis votre propre ordinateur, vérifiez que les fichiers sont arrivés. Votre propre compte a besoin d'un rôle sur les données pour les voir, même si vous êtes propriétaire de l'abonnement. Donnez-vous une fois l'accès en lecture au container :
az role assignment create --role "Storage Blob Data Reader" \
--assignee "$(az account show --query user.name --output tsv)" \
--scope "$CONTAINER_SCOPE"
az storage blob list --account-name STORAGE_ACCOUNT \
--container-name your-odoo-backups --auth-mode login --output table
Tester une restauration
La VM de production ne peut pas lire le container. C'est voulu. Le test de restauration tourne donc sur une deuxième VM, avec sa propre identité et un accès en lecture seule. Créez la VM comme plus haut, avec --name odoo-restore-vm et sa propre IP publique (ou aucune). Installez-y Odoo avec le guide VPS, et AzCopy comme plus haut. Puis donnez à son identité l'accès en lecture au container :
RESTORE_ID=$(az vm identity show --resource-group odoo-rg --name odoo-restore-vm \
--query principalId --output tsv)
az role assignment create --assignee-object-id "$RESTORE_ID" \
--assignee-principal-type ServicePrincipal \
--role "Storage Blob Data Reader" --scope "$CONTAINER_SCOPE"
Sur la VM de test, en tant qu'utilisateur odoo, récupérez la sauvegarde d'une nuit et restaurez-la :
mkdir -p /tmp/restore && cd /tmp/restore
AZCOPY_AUTO_LOGIN_TYPE=MSI azcopy copy "https://STORAGE_ACCOUNT.blob.core.windows.net/your-odoo-backups/2026-10-25/*" .
createdb -O odoo yourdb_restored
pg_restore -d yourdb_restored --no-owner --role=odoo yourdb.dump
mkdir -p /var/lib/odoo/filestore/yourdb_restored
tar -xzf yourdb-filestore.tar.gz -C /var/lib/odoo/filestore/yourdb_restored --strip-components=1
Si la copie de test utilise Azure Database for PostgreSQL, ajoutez -h YOUR_DB_SERVER.postgres.database.azure.com -U odoo à createdb et pg_restore.
Avant de démarrer Odoo sur la copie, neutralisez-la. Une copie de la production garde vos serveurs de messagerie et vos tâches planifiées, elle peut donc envoyer des e-mails à de vrais clients. En tant qu'utilisateur odoo, lancez :
odoo neutralize -c /etc/odoo/odoo.conf -d yourdb_restored
Utilisez odoo-bin au lieu de odoo si vous faites tourner Odoo depuis les sources. Cela désactive dans la copie les serveurs de messagerie sortants, les actions planifiées et les moyens de paiement. Notre guide sur la copie de la production vers le staging explique ce qu'elle couvre et ce qu'elle oublie.
Puis connectez-vous à yourdb_restored et ouvrez quelques pièces jointes. Notre guide sur comment savoir si une sauvegarde Odoo se restaurera explique le test complet.
Recevoir une alerte avant que le disque soit plein
Les logs, le filestore et les sauvegardes locales grossissent. Azure ne voit pas le remplissage de votre disque, sauf si la VM lui envoie ce chiffre. L'Azure Monitor Agent s'en charge. Une data collection rule (DCR) lui dit quoi envoyer, et où.
Créez un workspace Log Analytics pour garder les chiffres, et installez l'agent :
az monitor log-analytics workspace create --resource-group odoo-rg \
--workspace-name odoo-logs --location westeurope
WS_ID=$(az monitor log-analytics workspace show --resource-group odoo-rg \
--workspace-name odoo-logs --query id --output tsv)
VM_ID=$(az vm show --resource-group odoo-rg --name odoo-vm --query id --output tsv)
az vm extension set --ids "$VM_ID" \
--name AzureMonitorLinuxAgent --publisher Microsoft.Azure.Monitor \
--enable-auto-upgrade true
L'agent se connecte avec la managed identity de la VM. Enregistrez ceci sous odoo-disk-dcr.json. Mettez la valeur de $WS_ID à la place de WORKSPACE_ID, et utilisez votre région :
{
"location": "westeurope",
"kind": "Linux",
"properties": {
"dataSources": {
"performanceCounters": [
{
"name": "odooDisk",
"streams": ["Microsoft-Perf"],
"samplingFrequencyInSeconds": 60,
"counterSpecifiers": ["\\Logical Disk(*)\\% Free Space"]
}
]
},
"destinations": {
"logAnalytics": [
{
"name": "odooLogs",
"workspaceResourceId": "WORKSPACE_ID"
}
]
},
"dataFlows": [
{
"streams": ["Microsoft-Perf"],
"destinations": ["odooLogs"]
}
]
}
}
Créez la règle et reliez-la à la VM :
SUB_ID=$(az account show --query id --output tsv)
DCR_ID="/subscriptions/$SUB_ID/resourceGroups/odoo-rg/providers/Microsoft.Insights/dataCollectionRules/odoo-disk"
az rest --method put \
--url "https://management.azure.com${DCR_ID}?api-version=2022-06-01" \
--body @odoo-disk-dcr.json
az monitor data-collection rule association create \
--name odoo-disk --resource "$VM_ID" --rule-id "$DCR_ID"
Après environ cinq minutes, vérifiez que les chiffres arrivent. Dans le portail, ouvrez la VM, puis Logs, et lancez :
Perf
| where ObjectName == "Logical Disk" and CounterName == "% Free Space"
| summarize arg_max(TimeGenerated, CounterValue) by InstanceName
Vous devez voir / avec son espace libre en pourcentage.
Créez un action group qui vous envoie un e-mail, puis l'alerte. Elle se déclenche quand l'espace libre sur / passe sous 20 %, c'est-à-dire quand le disque est plein à plus de 80 % :
az monitor action-group create --resource-group odoo-rg \
--name odoo-alerts --short-name odoo \
--action email admin [email protected]
az monitor scheduled-query create --resource-group odoo-rg \
--name odoo-disk-80 --scopes "$VM_ID" \
--condition "min 'CounterValue' from 'DiskFree' < 20" \
--condition-query DiskFree="Perf | where ObjectName == 'Logical Disk' and CounterName == '% Free Space' and InstanceName == '/'" \
--evaluation-frequency 5m --window-size 15m \
--action-groups odoo-alerts --severity 2
Savoir quand Odoo est en panne
Une alerte disque ne vous dira pas que le site a cessé de répondre. Un standard test Application Insights vérifie votre page de connexion depuis plusieurs endroits du monde.
Créez une ressource Application Insights qui utilise le même workspace :
az monitor app-insights component create --resource-group odoo-rg \
--app odoo-uptime --location westeurope --workspace "$WS_ID"
Puis dans le portail :
- Ouvrez odoo-uptime, puis Availability, puis Add Standard test.
- Mettez l'URL
https://your-domain/web/login. Laissez les retries activés, ainsi que le contrôle du certificat SSL. - Choisissez au moins cinq emplacements de test, et enregistrez.
- Dans le menu du test, choisissez Open Rules (Alerts) page. Modifiez la règle et ajoutez l'action group
odoo-alerts. Sans cela, vous ne voyez les alertes que dans le portail, sans e-mail.
E-mails sortants
Azure bloque les e-mails sortants sur le port 25 depuis les VM, sauf si l'abonnement est un Enterprise Agreement ou un Microsoft Customer Agreement pour entreprise. Les e-mails d'Odoo envoyés ainsi expirent. Envoyez-les plutôt par un service SMTP sur le port 587. Azure ne bloque pas le port 587, quel que soit votre type d'abonnement. Votre fournisseur de messagerie actuel convient.
Azure Communication Services peut aussi envoyer des e-mails en SMTP :
- Créez une ressource Email Communication Services, ajoutez votre domaine et vérifiez-le avec les enregistrements DNS qu'elle vous donne. Reliez-la à une ressource Communication Services.
- Enregistrez une application dans Microsoft Entra ID et créez-lui un client secret.
- Donnez à cette application le rôle Communication and Email Service Owner sur la ressource Communication Services.
- Dans la ressource Communication Services, ouvrez SMTP Usernames et ajoutez un nom d'utilisateur lié à l'application.
- Dans Odoo, activez le mode développeur. Allez dans Settings > Technical > Outgoing Mail Servers. Mettez le serveur
smtp.azurecomm.net, le port 587, le chiffrement TLS (STARTTLS). Le nom d'utilisateur est le SMTP username de l'étape 4. Le mot de passe est le client secret de l'application.
Les pièges Odoo sur tout serveur, Azure compris
Websocket. Depuis Odoo 16, le chat et les mises à jour en direct passent par le port 8072. nginx doit y envoyer /websocket, avec les en-têtes d'upgrade.
Proxy mode. Odoo ne fait confiance aux en-têtes transmis que si proxy_mode = True et que la requête contient X-Forwarded-Host. Sans les deux, vos liens sortent en http://.
Gestionnaire de bases. Mettez list_db = False et un admin_passwd solide.
Workers. Mettez workers au-dessus de 0, réglé selon la mémoire. Odoo démarre alors le worker du chat sur gevent_port.
Dans odoo.conf :
proxy_mode = True
list_db = False
admin_passwd = a-long-random-string
workers = 4
gevent_port = 8072
Dans nginx, à côté de votre bloc location / :
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
location /websocket {
proxy_pass http://127.0.0.1:8072;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Forwarded-Host $http_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;
}
Le bloc map va dans la section http, en dehors de server.
Derrière Application Gateway
Vous n'avez pas besoin d'un load balancer pour une seule VM. Si vous utilisez quand même Application Gateway :
- Application Gateway gère seul les websockets. Gardez nginx derrière lui, pour que
/websocketaille toujours vers 8072. - Il envoie
X-Forwarded-ProtoetX-Forwarded-For, et l'hôte d'origine dansX-Original-Host. Il n'envoie pasX-Forwarded-Host, et sans lui, Odoo ignore les autres. nginx doit donc l'ajouter. - Il termine le HTTPS, donc nginx voit du HTTP simple. Si la gateway n'écoute qu'en HTTPS, dites à Odoo que la requête était en HTTPS.
Dans les deux blocs location de nginx, utilisez :
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
$host fonctionne si la gateway garde le nom d'hôte d'origine, ce qu'elle fait par défaut. Puis autorisez le port 80 dans odoo-web-nsg depuis le sous-réseau de la gateway uniquement, pas depuis tout internet.
Avant la mise en ligne
- La VM est d'une taille x86 d'usage général (pas de la série B), avec un disque Premium SSD
- Odoo tourne avec
workersau-dessus de 0, réglé selon la mémoire du serveur /websocketva vers le port 8072, et le chat fonctionneproxy_mode = True, et les liens dans les e-mails commencent parhttps://list_db = Falseet unadmin_passwdsolide- Seuls les ports 80 et 443 sont ouverts à internet, le port 8069 expire, et vous vous connectez via Bastion
- Avec Azure Database for PostgreSQL : accès privé,
db_sslmode = require, etpg_trgmautorisé - Le certificat SSL se renouvelle tout seul
- Les PDF s'impriment (wkhtmltopdf fonctionne)
- Les e-mails de test arrivent, envoyés sur le port 587
- Les logs tournent, l'e-mail de l'alerte disque fonctionne, et le test d'uptime est au vert
- Le timer de sauvegarde a tourné, et les fichiers sont dans Blob Storage
- Une sauvegarde a été restaurée sur une autre VM, et les pièces jointes s'ouvrent
Gardez Azure, confiez-nous le travail Odoo
Vous pouvez garder Odoo dans votre abonnement Azure sans le gérer vous-même. Avec bring your own server, la VM reste dans votre abonnement et dans la région de votre choix. Nous faisons tourner Odoo dessus : déploiements depuis Git, staging, sauvegardes, mises à jour et l'aide d'experts Odoo. Vous gardez la VM en marche et assez grande. Notre logiciel se connecte depuis votre VM vers l'extérieur, vous n'ouvrez donc aucun port pour nous.
Skysize est conçu par d'anciens ingénieurs d'Odoo et certifié ISO 27001.
Parlez à un expert en hébergement Odoo
FAQ
Odoo peut-il tourner sur Azure ? Oui. Utilisez une VM x86 d'usage général avec un disque Premium SSD, Postgres sur la VM ou sur Azure Database for PostgreSQL, et des sauvegardes vers Blob Storage.
Puis-je utiliser Azure Database for PostgreSQL pour Odoo ?
Oui. Utilisez l'accès privé, autorisez l'extension pg_trgm, et créez pour Odoo un utilisateur de base de données qui peut créer des bases. Connectez-vous sur le port 5432, pas via PgBouncer. Les sauvegardes du serveur ne couvrent pas le filestore, sauvegardez-le aussi.
Quelle taille de VM Azure est la meilleure pour Odoo ? Une taille avec assez de mémoire pour vos workers et Postgres, et un CPU stable. Une taille de la série D comme Standard_D2s_v5 est un bon début. Évitez les VM de la série B en production.
Odoo peut-il tourner sur les VM Arm d'Azure ? Odoo lui-même, oui, mais vérifiez que wkhtmltopdf fonctionne avant la mise en ligne. Notre logiciel bring your own server tourne uniquement sur x86, choisissez donc une taille Intel ou AMD si vous pensez l'utiliser.
De quels droits la VM Odoo a-t-elle besoin pour les sauvegardes ? Seulement l'écriture et l'ajout de blobs sur votre container de sauvegarde, via un rôle personnalisé sur la managed identity de la VM. Les restaurations utilisent une deuxième VM avec Storage Blob Data Reader.
Dois-je ouvrir le port 22 ? Pas à internet. Azure Bastion se connecte à la VM depuis l'intérieur du VNet, et vous vous connectez avec Entra ID.
Pourquoi Odoo n'envoie-t-il pas d'e-mails depuis ma VM Azure ? Azure bloque le port 25 sur la plupart des types d'abonnement. Envoyez par votre fournisseur de messagerie ou par Azure Communication Services sur le port 587.