SSD Nodes Learn Hosting plans →
Guides Matt ConnorPar Matt Connor · Mis à jour le 2026-08-28

Installer Mealie sur un VPS avec Docker Compose

Installez Mealie sur votre VPS avec Docker Compose : importez une recette par URL, créez des menus et listes de courses, puis ajoutez nginx, TLS et les sauvegardes.

Ce que fait un gestionnaire de recettes auto-hébergé

Un gestionnaire de recettes auto-hébergé conserve vos recettes dans une base de données sur un serveur dont vous avez la maîtrise, et Mealie est celui que la plupart des foyers finissent par choisir. Vous collez l’adresse d’une page de recette, puis Mealie en extrait les ingrédients, les étapes, le nombre de portions et le temps de cuisson. Il ignore le récit et la publicité. Votre collection ne contient que la recette.

Le reste de l’application est minimal. Un planning hebdomadaire permet d’y glisser des recettes. Une liste de courses est générée à partir de ce planning. Chaque personne qui cuisine dispose de son propre compte. L’ensemble s’exécute dans un seul conteneur et reste inactif entre deux requêtes. Un VPS modeste suffit donc largement.

Ce guide utilise Docker Compose. Si les termes services: et volumes: ne vous sont pas familiers, commencez par comprendre la structure des fichiers Docker Compose, car tout ce qui suit tient dans un seul fichier Compose et quatre commandes.

Installer Mealie avec Docker Compose

Mealie publie ses images dans le registre de conteneurs GitHub. En juillet 2026, le tag stable actuel est v3.22.0. Épinglez une version au lieu d’utiliser latest : avec latest, un docker compose pull un jour sans rapport peut vous faire passer à travers une migration de base de données que vous n’étiez pas prêt à appliquer.

sudo mkdir -p /srv/mealie
cd /srv/mealie
sudo nano docker-compose.yml
services:
  mealie:
    image: ghcr.io/mealie-recipes/mealie:v3.22.0
    container_name: mealie
    restart: always
    ports:
      - "127.0.0.1:9925:9000"
    deploy:
      resources:
        limits:
          memory: 1000M
    volumes:
      - mealie-data:/app/data/
    environment:
      ALLOW_SIGNUP: "false"
      PUID: 1000
      PGID: 1000
      TZ: Europe/Amsterdam
      BASE_URL: https://recipes.example.com

volumes:
  mealie-data:

Deux lignes méritent d’être examinées avant le démarrage.

Le port est écrit sous la forme 127.0.0.1:9925:9000, et non 9925:9000. Le conteneur écoute sur le port 9000 en interne, et l’hôte redirige le port 9925 vers celui-ci. Lier cette redirection à l’adresse loopback permet à nginx d’atteindre Mealie, mais empêche Internet d’y accéder. Docker ajoute ses propres règles au packet filter. Ainsi, un simple 9925:9000 est accessible depuis l’extérieur même si votre firewall indique que le port est fermé. Il est utile de comprendre ce comportement une fois : voir pourquoi les ports Docker publiés ignorent ufw.

BASE_URL doit être l’adresse publique exacte que vous utiliserez, avec le schéma et sans slash final. Mealie construit les liens de réinitialisation du mot de passe et les liens d’invitation à partir de cette adresse. Si vous la définissez sur http://localhost:9925, l’invitation envoyée à votre partenaire contiendra un lien qui ne fonctionnera que sur le serveur lui-même.

Démarrez le service et surveillez le premier boot.

sudo docker compose up -d
sudo docker compose logs -f mealie

Le premier démarrage crée la base de données SQLite et exécute les migrations, ce qui prend quelques secondes. Lorsque le journal se stabilise et cesse d’afficher des lignes de migration, vérifiez l’application en local.

curl -I http://127.0.0.1:9925

Un 200 OK signifie que l’application fonctionne. Connection refused signifie que le conteneur n’est pas en cours d’exécution : exécutez sudo docker compose ps et consultez le code de sortie. Un conteneur arrêté avec le code 137 a été tué parce qu’il a dépassé la limite mémoire de 1000M, ce qui arrive sur les offres les plus petites.

Première connexion et désactivation des inscriptions ouvertes

Le compte par défaut est changeme@example.com et son mot de passe est MyPassword. Connectez-vous avec ce compte, puis modifiez immédiatement ces deux valeurs, car cette combinaison figure dans la documentation et se retrouve donc dans tous les scanners.

La valeur ALLOW_SIGNUP: "false" dans le fichier Compose est volontaire. Lorsque les inscriptions sont ouvertes, toute personne qui trouve l’adresse peut créer un compte dans votre gestionnaire de recettes. Lorsqu’elles sont désactivées, vous ajoutez les utilisateurs depuis l’interface d’administration. Celle-ci génère un lien d’invitation que vous leur envoyez vous-même. Ce lien est construit à partir de BASE_URL, d’où l’importance de cette valeur. Si vous finissez par exécuter plusieurs applications sur le même serveur et souhaitez utiliser un seul mot de passe pour toutes, Mealie peut déléguer l’authentification à un fournisseur d’identité externe, tel qu’une instance Authentik auto-hébergée.

Mealie regroupe les utilisateurs dans un foyer. Tous les membres d’un même foyer partagent la collection de recettes, le planning des repas et la liste de courses, ce qui convient à une famille. Des foyers distincts sur le même serveur conservent des collections séparées, ce qui convient à une colocation lorsque personne ne parvient à se mettre d’accord sur les anchois.

L’importation, qui est la raison d’utiliser Mealie

Ouvrez la collection de recettes, choisissez de créer une recette à partir d’une URL, puis collez un lien. Mealie récupère la page et recherche les données de recette structurées, c’est-à-dire le bloc lisible par machine que la plupart des sites de recettes intègrent pour les moteurs de recherche. Lorsque ce bloc est présent, l’importation est propre et immédiate.

Vous pouvez aussi importer une image ou du texte brut que vous collez. Cela permet notamment d’importer la photographie d’une page de livre de recettes. Ces importations suivent un chemin plus lent et doivent être vérifiées ensuite, car une fraction manuscrite est facile à mal interpréter.

Les importations en masse s’effectuent depuis le même écran : collez une liste d’adresses, une par ligne, et Mealie les traite en arrière-plan. Une collection de deux cents favoris est ainsi importée en une seule fois.

Plans de repas et liste de courses

Le planificateur de repas est un calendrier. Faites glisser une recette sur un jour pour la planifier. La liste de courses récupère ensuite les ingrédients des recettes planifiées dans une seule liste et regroupe les doublons. Ainsi, deux recettes qui utilisent des oignons produisent une seule ligne au lieu de deux.

La liste est une page active que vous pouvez consulter sur votre téléphone dans le magasin. Comme elle est hébergée sur votre propre serveur, tous les membres du foyer voient la même liste en temps réel. Lorsqu’une personne coche le lait, celui-ci disparaît de l’écran des autres.

Placer nginx et TLS devant l’application

Mealie utilise HTTP en clair et ne gère pas lui-même les certificats. Terminez TLS dans nginx, placé devant Mealie. Commencez par faire pointer un enregistrement DNS de type A vers votre serveur, car l’étape de création du certificat vérifie ce nom.

sudo apt update && sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/mealie
server {
    listen 80;
    server_name recipes.example.com;

    client_max_body_size 64M;

    location / {
        proxy_pass http://127.0.0.1:9925;
        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;
    }
}
sudo ln -s /etc/nginx/sites-available/mealie /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

L’affichage de nginx -t et de syntax is ok, ainsi que de test is successful, valide la configuration. Ne rechargez nginx qu’après cette validation. Le rechargement d’une configuration incorrecte conserve l’ancienne configuration active et masque l’erreur jusqu’au prochain redémarrage.

client_max_body_size 64M est nécessaire, car la valeur par défaut de nginx est de 1 MB. L’envoi d’une photo de recette ou la restauration d’une sauvegarde depuis le navigateur transmet un body plus volumineux. Sans cette directive, nginx renvoie une erreur 413 Request Entity Too Large, et non Mealie. Le journal de l’application ne contient donc aucun message.

Créez ensuite le certificat. Cette étape et son timer de renouvellement sont décrits dans créer un certificat Let’s Encrypt pour nginx avec certbot.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d recipes.example.com

Certbot réécrit le server block pour écouter sur 443 et ajoute une redirection depuis le port 80. Ouvrez le site avec https:// et vérifiez que le navigateur accepte le certificat. Si Mealie se charge, mais que ses propres liens vous redirigent vers http://, alors BASE_URL contient encore http. Corrigez cette valeur, puis exécutez sudo docker compose up -d pour recréer le conteneur avec la nouvelle valeur.

Servir Mealie sous un sous-chemin comme example.com/recipes ne fonctionne pas, car le frontend ne peut pas être servi depuis un sous-chemin. Utilisez un sous-domaine.

Sauvegardes et fonctionnement réel d’une restauration

Tout ce que Mealie utilise se trouve dans /app/data/ à l’intérieur du conteneur. Il s’agit du volume mealie-data. Copiez ce volume pour copier ensemble les recettes, les images et la base de données.

sudo docker volume ls
sudo docker compose stop mealie
sudo docker run --rm -v mealie_mealie-data:/data -v "$PWD":/backup \
  alpine tar czf /backup/mealie-data.tgz -C /data .
sudo docker compose start mealie

Le nom du volume commence par le nom du projet. Le nom du projet correspond au répertoire qui contient le fichier Compose. Depuis /srv/mealie, le volume est mealie_mealie-data. C’est pourquoi la première commande est docker volume ls : utilisez le nom qu’elle affiche, et non celui indiqué dans ce guide. Il est important d’arrêter le conteneur avant la copie. SQLite est assez souvent en cours d’écriture pour qu’une copie à chaud puisse être restaurée sous la forme d’une base illisible.

Mealie possède également sa propre page de sauvegarde dans l’interface d’administration. Elle crée une archive portable contenant la base de données au format JSON ainsi que vos images. Utilisez-la pour déplacer Mealie entre des serveurs. Elle résiste à un changement de version qu’une simple copie des fichiers pourrait ne pas supporter. La restauration d’une archive est destructive par conception : elle supprime la base de données actuelle avant de charger l’archive et cette opération est irréversible. Vous êtes déconnecté une fois la restauration terminée.

Aucune de ces copies ne constitue une sauvegarde tant qu’elle reste sur le même serveur. Transférez régulièrement l’archive vers un autre emplacement. C’est précisément le rôle de sauvegardes chiffrées sur un serveur distant avec restic.

Mise à jour de Mealie

cd /srv/mealie
sudo nano docker-compose.yml
sudo docker compose pull
sudo docker compose up -d
sudo docker compose logs -f mealie

Augmentez la version épinglée dans le fichier, puis téléchargez la nouvelle image et recréez le conteneur. Les migrations s’exécutent au premier démarrage de la nouvelle image. Copiez le volume avant de changer de version majeure, car une migration qui échoue à mi-parcours peut laisser une base de données que l’ancienne image ne pourra plus ouvrir. Lisez les notes de version pour toutes les versions comprises entre votre version actuelle et la nouvelle.

En cas d’échec de l’importation

Certains sites ne publient aucune donnée structurée de recette. Mealie importe alors le titre, mais la liste des ingrédients reste vide. Ce comportement ne peut pas être corrigé par la configuration. Saisissez plutôt le texte de la recette manuellement.

D’autres échecs sont dus à la protection contre les bots placée devant le site de recettes. Celui-ci répond à Mealie avec une page de vérification au lieu de la recette. Mealie se fait déjà passer pour un navigateur et fait tourner son user agent pour limiter ce problème. Si le site refuse toujours la requête, les options documentées consistent à faire passer le scraper par un proxy dont la réputation de l’adresse IP est meilleure, ou à exécuter une instance de FlareSolverr qui résout la vérification dans un vrai navigateur. Ces deux options sont facultatives et se configurent avec des variables d’environnement sur le conteneur.

Un import qui échoue parce que votre serveur ne peut pas du tout joindre le site relève d’un autre problème. Testez la connexion depuis le serveur avec curl -I https://the-site.example/recipe et lisez la ligne d’état avant d’incriminer le scraper.

Où cette application s’insère

Mealie est une bonne première application auto-hébergée pour un foyer, car les personnes avec qui vous vivez l’utiliseront sans que vous ayez à le leur demander. C’est le même type d’usage que votre propre photothèque avec Immich, mais en beaucoup plus léger. L’application s’inscrit aussi dans la liste plus large des services qui valent la peine d’être auto-hébergés cette année. Un seul petit serveur peut héberger les deux. Immich n’est pas le seul candidat pour ce second usage. Si vous hésitez encore, les besoins minimaux en mémoire et les commandes de sauvegarde de PhotoPrism et Immich diffèrent suffisamment pour mériter une lecture avant de consacrer le reste du disque à cette installation. Si le foyer conserve aussi ses projets et ses notes, en plus de ses repas, un espace de travail AFFiNE auto-hébergé repose une nouvelle fois sur le même exercice avec un fichier Compose. Il nécessite toutefois quatre conteneurs et nettement plus de mémoire que Mealie. Vérifiez donc d’abord les ressources encore disponibles sur le serveur. Si le foyer veut aussi suivre ses entraînements, en plus de ses repas, openGym conserve les séances d’entraînement et utilise le même tag épinglé, le même fichier Compose et le même certificat que ceux que vous venez de configurer. Le moment qui suit le dîner a aussi sa propre déclinaison, puisque Halcyon transforme une bibliothèque Jellyfin existante en vidéoclub des années 1990 que vous pouvez parcourir, avec un conteneur supplémentaire placé devant un service que vous utilisez déjà, plutôt qu’une nouvelle base de données à sauvegarder. Tout ce qui appartient à cette famille n’est pas une application pour foyer. Si cette même habitude doit un jour servir au travail, un service d’assistance Chatwoot auto-hébergé reprend le même tag épinglé et le même certificat, avec Postgres, Redis et un envoi de courriers fonctionnel en arrière-plan. Il s’agit d’un service beaucoup plus lourd qu’une application de recettes et il mérite son propre serveur.

FAQ

Pourquoi l’importation d’une URL de recette échoue-t-elle ?

Deux causes sont fréquentes. Soit la page ne publie aucune donnée structurée de recette : le scraper ne trouve rien et vous obtenez un titre sans ingrédients. Soit une couche de protection contre les bots placée devant le site renvoie une page de challenge au lieu de la recette. Dans le second cas, vous pouvez configurer Mealie pour utiliser un proxy avec une meilleure réputation d’adresse IP, ou une instance FlareSolverr auto-hébergée qui résout le challenge dans un navigateur réel. Vérifiez d’abord que votre serveur peut atteindre la page avec curl -I avant de modifier quoi que ce soit.

Ai-je besoin de PostgreSQL ou SQLite suffit-il ?

SQLite suffit pour un usage familial et constitue le moteur par défaut. Passez à PostgreSQL lorsque le répertoire de données se trouve sur un stockage réseau, car SQLite sur un système de fichiers réseau provoque des erreurs de base verrouillée et peut corrompre le fichier. Avec PostgreSQL, la restauration nécessite que l’utilisateur de la base de données soit un superuser, car la restauration supprime tout avant de charger l’archive.

Puis-je exécuter Mealie sans nom de domaine ?

Oui, sur votre propre réseau. Définissez BASE_URL avec l’adresse que vous saisirez réellement, par exemple http://192.168.1.20:9925, et n’utilisez pas nginx. Les liens d’invitation et de réinitialisation du mot de passe sont générés à partir de BASE_URL. Une valeur incorrecte produit donc des liens que personne d’autre ne peut ouvrir. N’exposez pas Mealie sur Internet en HTTP simple, car les identifiants de connexion sont alors transmis en clair.

Comment donner à ma famille ses propres comptes ?

Laissez ALLOW_SIGNUP défini sur "false" et ajoutez les personnes depuis l’espace d’administration. Mealie génère alors un lien d’invitation que vous pouvez leur envoyer. Placez toutes les personnes qui partagent une cuisine dans le même foyer afin qu’elles partagent les recettes, le planning des repas et la liste de courses. Plusieurs foyers sur un même serveur conservent des collections séparées.

Que deviennent mes recettes si j’arrête d’utiliser Mealie ?

Elles restent disponibles. La sauvegarde d’administration exporte vos données au format JSON. Mealie peut également exporter les recettes sous forme de fichiers markdown simples, lisibles dans n’importe quel éditeur de texte, sans aucun logiciel supplémentaire. Effectuez un export avant d’en avoir besoin et vérifiez que vous pouvez l’ouvrir.