Skip to content

Auto-hébergement ​

Ce guide vous mène d'un serveur nu à une instance Mankomail en service, sur laquelle vous pouvez vous connecter. Il s'appuie sur le fichier Docker Compose de référence livré avec le code source, compose.reference.yaml.

Ce que vous installez ​

Une instance auto-hébergée se compose de trois éléments :

  • Le conteneur applicatif : l'API, les workers de fond et l'interface web, dans un seul processus.
  • PostgreSQL : tout l'état de l'instance y vit — boîtes, workflows, exécutions, et la file de tâches elle-même.
  • Un stockage objet compatible S3 : les corps de mails et les pièces jointes. Le fichier Compose de référence fait tourner MinIO ; n'importe quel point d'accès compatible S3 peut le remplacer.

Il n'y a ni Redis, ni courtier de messages, ni ordonnanceur séparé à faire tourner.

Prérequis ​

MinimumConfortable
Docker Engine2428 ou plus
plugin docker composev2.20v2.39 ou plus
Mémoire vive4 Go8 Go
Processeur2 cœurs4 cœurs
Disque20 Goenviron 1,5 × la taille des boîtes synchronisées

Le miroir stocke les corps de mails et les pièces jointes tels quels. Par défaut, Mankomail synchronise les 12 derniers mois de chaque boîte (BACKFILL_MONTHS) ; baisser cette valeur est le premier levier si l'espace disque est compté.

Vous n'avez besoin ni de Node.js, ni de pnpm, ni de PostgreSQL sur la machine : tout tourne dans des conteneurs.

Il vous faut aussi :

  • un nom de domaine qui pointe vers le serveur, pour le HTTPS ;
  • un reverse proxy qui termine le TLS (Caddy, nginx, Traefik…). L'application ne parle pas TLS elle-même.

Démarrage rapide ​

  1. Clonez le dépôt et créez le fichier .env à partir de l'exemple commenté :

    bash
    git clone <repository-url> instance && cd instance
    cp .env.example .env
  2. Générez les secrets :

    bash
    openssl rand -hex 16   # pour POSTGRES_PASSWORD
    openssl rand -hex 16   # pour STORAGE_SECRET_ACCESS_KEY
    openssl rand -hex 32   # pour ENCRYPTION_KEY
  3. Modifiez .env pour que chacune de ces variables y figure une seule fois, avec vos valeurs :

    ini
    POSTGRES_PASSWORD=<valeur générée>
    STORAGE_ACCESS_KEY_ID=storage
    STORAGE_SECRET_ACCESS_KEY=<valeur générée>
    ENCRYPTION_KEY=<valeur générée>
    PUBLIC_BASE_URL=https://mail.example.com
    BOOTSTRAP_ADMIN_EMAIL=vous@example.com
    BOOTSTRAP_ADMIN_PASSWORD=<au moins 12 caractères>
  4. Construisez l'image, démarrez la pile et vérifiez qu'elle est prête :

    bash
    docker compose -f compose.reference.yaml up -d --build
    curl -s localhost:3000/readyz

Le premier --build compile l'image et prend quelques minutes. Les migrations de la base s'appliquent d'elles-mêmes au démarrage de l'application.

La suite de cette page explique chaque étape, et les quelques endroits où une installation déraille d'habitude.

Les variables obligatoires ​

Le fichier Compose de référence refuse de démarrer si l'une de ces variables manque dans .env :

VariableCe que c'estComment la produire
POSTGRES_PASSWORDMot de passe de la base PostgreSQLopenssl rand -hex 16
STORAGE_ACCESS_KEY_IDClé d'accès du stockage objetUn identifiant au choix
STORAGE_SECRET_ACCESS_KEYSecret du stockage objetopenssl rand -hex 16
ENCRYPTION_KEYLa clé d'instance qui chiffre les identifiants stockésopenssl rand -hex 32
PUBLIC_BASE_URLL'adresse publique que tapent vos utilisateurs, par exemple https://mail.example.comVotre domaine

Chaque variable lue par l'application accepte aussi une forme <NOM>_FILE qui pointe vers un fichier, pour les secrets Docker ou Kubernetes.

La liste complète des variables, avec leurs valeurs par défaut, est dans Variables d'environnement.

Variables absentes du fichier Compose

Le fichier Compose de référence transmet au conteneur applicatif une liste explicite de variables. Une variable ajoutée à .env n'atteint l'application que si elle figure sous services.app.environment dans le fichier Compose. Pour en poser une autre, ajoutez-la à cet endroit, ou dans un fichier Compose supplémentaire (voir Évaluer sur votre poste).

La clé de chiffrement ​

ENCRYPTION_KEY chiffre (AES-256-GCM) les jetons OAuth et les mots de passe IMAP des boîtes connectées, ainsi que les clés des fournisseurs d'IA et des autres connexions.

  • Elle accepte 64 caractères hexadécimaux (openssl rand -hex 32) ou 32 octets encodés en base64 (openssl rand -base64 32).
  • Elle ne se régénère pas. Si vous la perdez, tous les identifiants stockés deviennent illisibles et chaque membre doit reconnecter ses boîtes.
  • Rangez-la dans un gestionnaire de mots de passe le jour où vous la générez.
  • Sans clé valide, l'instance ne peut enregistrer aucune clé de fournisseur d'IA.

DANGER

Une ENCRYPTION_KEY invalide n'empêche pas l'application de démarrer : l'instance journalise un avertissement et tourne sans chiffrement des identifiants. Vérifiez toujours les journaux de démarrage (voir Lire les journaux de démarrage) avant de connecter une boîte.

PUBLIC_BASE_URL ​

PUBLIC_BASE_URL n'est pas l'adresse d'écoute de l'application : c'est l'adresse que joignent vos utilisateurs. Mankomail s'en sert pour construire :

  • les URI de redirection OAuth, par exemple <PUBLIC_BASE_URL>/api/v1/oauth/google/callback ;
  • les liens des invitations et des mails d'approbation ;
  • l'URL de notification du push Microsoft Graph ;
  • la politique de sécurité du contenu (CSP) de l'interface web, canal temps réel compris.

Elle doit être exactement l'URL publique — schéma, hôte et port compris — sans / final. Une valeur fausse laisse l'instance démarrer normalement, puis fait échouer la connexion des boîtes chez le fournisseur, sur une URI de redirection qui ne correspond pas.

Les variables de dimensionnement et de comportement ​

Ces variables ont des valeurs par défaut raisonnables. Les plus utiles à l'installation :

VariableDéfautQuand la modifier
BACKFILL_MONTHS12Profondeur d'historique synchronisée pour chaque boîte. 3 suffit pour évaluer le produit.
POLL_INTERVAL_SECONDS300Intervalle du sondage de secours. Les notifications push accélèrent la synchronisation ; le sondage la garantit.
WORKER_CONCURRENCY4Nombre de tâches traitées en parallèle. Gardez-le sous DATABASE_POOL_MAX.
DATABASE_POOL_MAX10Connexions à la base par processus applicatif.
SEND_ENABLEDtrueCoupe-circuit des envois pour toute l'instance. Passez-le à false sur toute copie d'une instance de production.
SEND_MAX_PER_HOUR100Nombre maximal de mails envoyés par heure, par boîte.
APP_BIND127.0.0.1Interface sur laquelle le port de l'application est publié. Laissez-la telle quelle derrière un reverse proxy.
APP_PORT3000Port local de l'application.
BRAND_NAMEMankomailNom du produit affiché dans l'interface et renvoyé par /healthz.

Construire ou récupérer l'image ​

Construisez l'image à partir des sources :

bash
docker compose -f compose.reference.yaml build

Si vous utilisez plutôt une image publiée, renseignez sa référence dans la variable APP_IMAGE de .env.

Le conteneur applicatif tourne avec un utilisateur non-root, sur un système de fichiers en lecture seule, sans aucune capability Linux et avec no-new-privileges. Si vous ajoutez un composant qui écrit sur disque, donnez-lui un tmpfs ou un volume.

Démarrer l'instance ​

bash
docker compose -f compose.reference.yaml up -d

L'ordre de démarrage est garanti par des contrôles de santé :

  1. PostgreSQL doit accepter les connexions.
  2. MinIO doit être prêt, puis une tâche ponctuelle crée le bucket et le rend privé.
  3. L'application démarre, puis applique les migrations de la base sous un verrou consultatif PostgreSQL.

Il n'y a pas d'étape de migration à lancer à part. Plusieurs répliques peuvent démarrer en même temps : une seule migre, les autres attendent.

PostgreSQL et MinIO ne publient aucun port : ils ne sont joignables que depuis le réseau Compose. Le port de l'application n'est publié que sur 127.0.0.1.

Lire les journaux de démarrage ​

bash
docker compose -f compose.reference.yaml logs app | head -40

Cherchez ces lignes :

Ligne de journalCe qu'elle prouve
database schema is up to dateLes migrations sont appliquées.
authentication is ready avec "credentialsEncryption":"enabled"ENCRYPTION_KEY a été acceptée. Si la ligne indique disabled, arrêtez-vous et corrigez la clé avant de connecter la moindre boîte.
bootstrap admin createdLe compte du premier administrateur existe.
Server listening at http://0.0.0.0:3000L'application écoute.

Quelques lignes indiquant que PostgreSQL n'accepte pas encore de connexions, juste après le démarrage, sont normales : l'application attend sa base.

Vérifier la santé ​

Deux points d'accès, aux rôles différents :

bash
curl -s localhost:3000/healthz
curl -s localhost:3000/readyz
  • /healthz (vivacité) répond 200 avec status, brand, version et uptimeSeconds. Il ne touche à rien d'extérieur.
  • /readyz (disponibilité) vérifie la base et les migrations. Il répond 200 avec "status":"ready", ou 503 avec "status":"not_ready" et la vérification en échec.

Branchez votre superviseur de processus sur /healthz, pas sur /readyz : une courte panne de la base ne doit pas faire redémarrer en boucle des processus sains. L'image déclare d'ailleurs un HEALTHCHECK Docker sur /healthz.

Le premier administrateur ​

Renseignez BOOTSTRAP_ADMIN_EMAIL et BOOTSTRAP_ADMIN_PASSWORD avant le premier démarrage. Le compte est créé au démarrage, avec le rôle administrateur.

  • Le mot de passe doit compter au moins 12 caractères. Un mot de passe plus court est refusé avec un avertissement dans les journaux, et aucun compte n'est créé.
  • Le mécanisme devient inerte dès qu'un membre existe : laisser les deux variables dans .env ne réinitialise aucun mot de passe et ne crée pas de second compte. Vous pouvez les retirer ensuite.

Il n'y a pas d'inscription publique. Les membres suivants arrivent sur invitation, depuis Administration › Membres.

Placer un reverse proxy devant ​

L'application ne parle pas TLS. Placez devant elle un reverse proxy qui termine le HTTPS et transmet à 127.0.0.1:3000.

Ce n'est pas facultatif. En mode production — celui du fichier Compose de référence — le cookie de session porte l'attribut Secure, et la route de connexion refuse une requête qui n'est pas arrivée en HTTPS, avec l'erreur auth.https_required. L'application reconnaît un HTTPS terminé au proxy grâce à l'en-tête X-Forwarded-Proto.

Avec Caddy, qui obtient le certificat tout seul :

caddyfile
mail.example.com {
    encode gzip
    reverse_proxy 127.0.0.1:3000
}

Avec nginx, transmettez la montée en WebSocket (le canal temps réel vit sur /api/v1/ws) et le schéma d'origine :

nginx
server {
    listen 443 ssl;
    server_name mail.example.com;
    # ssl_certificate et ssl_certificate_key : votre certificat

    # Les pièces jointes du webmail peuvent atteindre 25 Mo.
    client_max_body_size 30m;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

L'application pose elle-même ses en-têtes de sécurité (Strict-Transport-Security en production, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, et une politique de sécurité du contenu sur les pages HTML).

Faire confiance au proxy

Par défaut, l'application fait confiance aux en-têtes X-Forwarded-* (TRUST_PROXY=true), ce qui est juste derrière un proxy. Si vous exposez directement le port de l'application, posez TRUST_PROXY=false : sinon, un client peut falsifier son adresse IP et contourner la limitation de débit du formulaire de connexion. Derrière un proxy, gardez APP_BIND=127.0.0.1.

Vérifiez ensuite que PUBLIC_BASE_URL est bien l'adresse HTTPS servie par le proxy, par exemple https://mail.example.com, et redémarrez l'application si vous l'avez modifiée :

bash
docker compose -f compose.reference.yaml up -d app

Évaluer sur votre poste ​

Pour essayer Mankomail sur votre poste sans certificat, faites-le tourner sur http://localhost:3000 en acceptant un cookie de session sans l'attribut Secure. Créez un fichier compose.local.yaml à côté du fichier de référence :

yaml
services:
  app:
    environment:
      COOKIE_SECURE: 'false'

Renseignez PUBLIC_BASE_URL=http://localhost:3000 dans .env, puis démarrez les deux fichiers ensemble :

bash
docker compose -f compose.reference.yaml -f compose.local.yaml up -d

DANGER

COOKIE_SECURE=false fait circuler le cookie de session en clair. Ne l'utilisez que sur une machine ou un réseau que vous maîtrisez, jamais pour une instance de production.

Utiliser un stockage S3 externe ​

Le fichier Compose de référence fait tourner MinIO, mais tout stockage objet compatible S3 convient. Pour utiliser le vôtre :

  1. Créez un bucket privé chez votre fournisseur, et une clé d'accès limitée à ce bucket. L'application ne crée pas le bucket.
  2. Faites une copie de compose.reference.yaml et, dans la copie :
    • supprimez les services minio et createbucket, ainsi que le volume minio-data ;
    • retirez createbucket de la liste depends_on du service app ;
    • dans services.app.environment, renseignez STORAGE_ENDPOINT avec le point d'accès de votre fournisseur, STORAGE_REGION avec la région du bucket, et STORAGE_FORCE_PATH_STYLE avec la valeur qu'attend votre fournisseur (true pour la plupart des services compatibles S3, qui n'offrent pas de nom DNS par bucket).
  3. Dans .env, renseignez STORAGE_BUCKET, STORAGE_ACCESS_KEY_ID et STORAGE_SECRET_ACCESS_KEY.

Utilisez un bucket par instance : l'application ne préfixe pas les clés de ses objets.

Première connexion ​

Ouvrez <PUBLIC_BASE_URL> dans un navigateur et connectez-vous avec l'adresse e-mail et le mot de passe de l'administrateur initial. Vous arrivez sur la page Boîtes.

Si la connexion indique que l'instance exige HTTPS, la requête n'a pas atteint l'application en HTTPS : vérifiez le reverse proxy et son en-tête X-Forwarded-Proto (voir Placer un reverse proxy devant).

Étapes suivantes ​

  1. Déclarez l'application OAuth de votre fournisseur de messagerie. Mankomail n'embarque pas d'application Google ou Microsoft partagée : votre organisation déclare la sienne. En tant qu'administrateur, ouvrez Administration › Applications OAuth : l'écran affiche l'URI de redirection à recopier dans la console du fournisseur. Suivez Google ou Microsoft. Pour tout autre fournisseur, utilisez IMAP, qui ne demande aucune application.
  2. Connectez une boîte depuis la page Boîtes. Voir Boîtes et miroir.
  3. Configurez un fournisseur d'IA pour les nœuds IA. En tant qu'administrateur, ouvrez Connexions, section Intelligence artificielle. Voir OpenAI, Anthropic, Mistral, Ollama et les autres intégrations.
  4. Invitez vos collègues depuis Administration › Membres.
  5. Construisez votre premier workflow : tutoriel pas à pas.

Avant de considérer l'installation comme terminée :

  • gardez une copie de ENCRYPTION_KEY ailleurs que sur le serveur ;
  • prenez une sauvegarde et restaurez-la une fois — voir Sauvegardes ;
  • lisez comment mettre à jour et superviser l'instance.