SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor

Mealie на VPS: встановлення через Docker Compose

Розгорніть Mealie на власному VPS через Docker Compose: імпортуйте рецепт за посиланням, створюйте плани харчування та списки покупок, налаштуйте nginx, TLS і резервні копії.

Що робить self-hosted менеджер рецептів

Self-hosted менеджер рецептів зберігає ваші рецепти в базі даних на сервері, який належить вам. У більшості домогосподарств для цього обирають Mealie. Ви вставляєте адресу сторінки з рецептом, а Mealie зчитує з неї інгредієнти, етапи приготування, кількість порцій і час приготування, відкидаючи опис та рекламу. У вашій колекції залишається сам рецепт.

Решта застосунку невелика. Є тижневий план харчування, до якого можна перетягувати рецепти, і список покупок, сформований на основі цього плану. Кожна людина, яка готує, отримує власний обліковий запис. Усе працює в одному контейнері та простоює між запитами, тому помірний VPS працює з ним без помітного навантаження.

У цьому посібнику використовується Docker Compose. Якщо терміни services: і volumes: вам незнайомі, спочатку прочитайте як влаштовані файли Docker Compose, оскільки все нижче — це один compose-файл і чотири команди.

Встановлення Mealie за допомогою Docker Compose

Mealie публікує свої образи в реєстрі контейнерів GitHub. Станом на жовтень 2026 року поточний стабільний тег — v3.28.0. Фіксуйте версію замість використання latest: із latest звичайний docker compose pull в інший день може перемістити вас через міграцію бази даних, до якої ви не готові.

sudo mkdir -p /srv/mealie
cd /srv/mealie
sudo nano docker-compose.yml
services:
  mealie:
    image: ghcr.io/mealie-recipes/mealie:v3.28.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:

Перед запуском варто перевірити два рядки.

Порт записано як 127.0.0.1:9925:9000, а не як 9925:9000. Контейнер слухає порт 9000 усередині, а хост перенаправляє на нього порт 9925. Прив’язка цього відображення до loopback-адреси дає змогу nginx підключатися до Mealie, але не дає доступу з інтернету. Docker додає власні правила до packet filter, тому звичайний 9925:9000 доступний ззовні, навіть коли firewall повідомляє, що порт закритий. Це важливо зрозуміти один раз: див. чому опубліковані порти Docker ігнорують ufw.

BASE_URL має бути точною публічною адресою, яку ви використовуватимете, зі схемою та без кінцевого слеша. Mealie формує на її основі посилання для скидання пароля та запрошень. Якщо встановити http://localhost:9925, запрошення, яке ви надішлете партнеру, міститиме посилання, що працює лише на самому сервері.

Запустіть контейнер і стежте за першим запуском.

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

Під час першого запуску створюється база даних SQLite і виконуються міграції. Це займає кілька секунд. Коли журнал стабілізується й рядки міграцій більше не з’являються, перевірте застосунок локально.

curl -I http://127.0.0.1:9925

200 OK означає, що застосунок працює. Connection refused означає, що контейнер не запущений: виконайте sudo docker compose ps і перевірте код завершення. Контейнер, який завершив роботу з кодом 137, було примусово зупинено через перевищення обмеження пам’яті 1000M. Це трапляється на тарифах із найменшими ресурсами.

Перший вхід і вимкнення відкритої реєстрації

Обліковий запис за замовчуванням — changeme@example.com, пароль — MyPassword. Увійдіть за допомогою цього облікового запису, а потім одразу змініть адресу електронної пошти для входу та пароль, оскільки цю пару надруковано в документації, а отже, вона є в кожному сканері.

ALLOW_SIGNUP: "false" у compose-файлі задано навмисно. Якщо реєстрацію відкрито, будь-хто, хто знайде адресу, може створити обліковий запис у вашому сховищі рецептів. Якщо реєстрацію закрито, ви додаєте людей з адміністративної панелі, яка створює посилання-запрошення, що ви надсилаєте їм самостійно. Це посилання формується з BASE_URL, тому це значення має значення. Якщо зрештою ви запускатимете кілька застосунків на одному сервері й захочете використовувати один пароль для всіх них, Mealie може передавати дані для входу зовнішньому постачальнику ідентифікації, наприклад self-hosted інстансу Authentik.

Mealie додає користувачів до household, а household належать до group. Усі користувачі одного household спільно використовують план харчування та список покупок — саме це потрібно родині. Колекція рецептів ширша: household спільно використовують свої рецепти, теги й категорії з усіма іншими household у тій самій group. Тому окремі household на одному сервері мають окремі плани й списки, але готують за одними й тими самими рецептами. Це підходить і для спільного житла, де ніхто не може домовитися щодо анчоусів. Якщо користувачам потрібні повністю окремі колекції, створіть для них окремі group, оскільки між group нічого не спільне.

Імпортер, заради якого це налаштовують

Відкрийте колекцію рецептів, виберіть створення рецепта з URL і вставте посилання. Mealie завантажить сторінку та шукатиме структуровані дані рецепта — машиночитний блок, який більшість сайтів із рецептами вбудовує для пошукових систем. Якщо цей блок є, імпорт виконується швидко й без додаткового опрацювання.

Якщо налаштувати AI provider, можна також імпортувати рецепт із зображення або вставленого звичайного тексту. Це підходить, зокрема, для фотографії сторінки з кулінарної книги. Для імпорту зображень потрібен provider, який підтримує їх розпізнавання. Без provider ці способи імпорту недоступні. Вони працюють повільніше, а результат потрібно перевірити, оскільки рукописний дріб легко прочитати неправильно.

Масовий імпорт запускається на цьому самому екрані: вставте список адрес, по одній у кожному рядку, і Mealie обробить їх у фоновому режимі. Колекцію з двохсот закладок можна перенести за один сеанс.

Плани харчування та список покупок

Планувальник харчування — це календар. Перетягніть рецепт на потрібний день, і його буде заплановано. Після цього список покупок збирає інгредієнти із запланованих рецептів в один список і об’єднує дублікати. Тому двом рецептам, для яких потрібна цибуля, відповідає один рядок, а не два.

У магазині список відкритий на телефоні як актуальна сторінка. Оскільки його зберігає ваш власний сервер, усі члени домогосподарства одночасно бачать той самий список. Якщо одна людина позначає молоко як придбане, воно зникає з екрана іншої людини.

Налаштуйте nginx і TLS перед застосунком

Mealie працює через звичайний HTTP і не має власних засобів роботи із сертифікатами. Завершуйте TLS у nginx, розміщеному перед Mealie. Спочатку додайте DNS-запис A для сервера, оскільки під час отримання сертифіката перевіряється це ім’я.

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

Виведення nginx -t, syntax is ok і test is successful підтверджує коректність конфігурації. Виконуйте перезавантаження лише після успішної перевірки. Якщо конфігурація має помилки, після перезавантаження nginx продовжить працювати зі старою конфігурацією, а помилка стане помітною лише під час наступного запуску.

client_max_body_size 64M потрібен, оскільки стандартне значення nginx становить 1 MB. Завантаження фотографії рецепта або відновлення резервної копії через браузер передає тіло запиту більшого розміру. Без цього рядка nginx повертає 413 Request Entity Too Large, а не Mealie, тому в журналі застосунку взагалі не буде відповідного запису.

Після цього отримайте сертифікат. Цей крок і таймер його поновлення описано в розділі отримання сертифіката Let's Encrypt для nginx за допомогою certbot.

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

Certbot змінює server block, щоб він прослуховував порт 443, і додає перенаправлення з порту 80. Відкрийте сайт через https:// і переконайтеся, що браузер приймає сертифікат. Якщо Mealie завантажується, але його власні посилання перенаправляють вас на http://, параметр BASE_URL досі має значення http. Виправте його, а потім виконайте sudo docker compose up -d, щоб повторно створити контейнер із новим значенням.

Розміщення Mealie у підшляху, наприклад example.com/recipes, не працює, оскільки frontend не може працювати з підшляху. Використовуйте піддомен.

Резервні копії та фактична поведінка відновлення

Усе, чим володіє Mealie, зберігається в /app/data/ усередині контейнера. Це том mealie-data. Скопіюйте цей том — і разом скопіюєте рецепти, зображення та базу даних. Власна документація Mealie називає зупинку контейнера та копіювання цієї папки найкращим способом резервного копіювання інсталяції SQLite.

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

Назва тому містить назву проєкту як префікс. Назва проєкту — це назва каталогу, у якому розташований compose-файл. У /srv/mealie том має назву mealie_mealie-data, тому першою командою є docker volume ls: використовуйте назву, яку вона виводить, а не назву з цього посібника. Спочатку потрібно зупинити контейнер, оскільки SQLite досить часто виконує запис, і копія активної бази може відновитися як непридатна для читання.

У Mealie також є власна сторінка резервного копіювання в адміністративній області. Вона створює zip-архів, який містить базу даних у форматі database.json. Не покладайтеся на цей архів під час переходу на іншу версію: його потрібно відновлювати тією самою версією Mealie, якою його створено. Відновлення з несумісною версією завершується помилкою. Щоб перенести дані на інший сервер, запустіть на новому сервері ту саму зафіксовану версію, а потім скопіюйте туди том або відновіть архів. Відновлення архіву навмисно має руйнівний характер: воно видаляє поточну базу даних перед завантаженням архіву, і скасувати цю дію неможливо. Після завершення сеанси буде завершено.

Жодна з цих копій не є резервною, якщо вона зберігається на тому самому сервері. Регулярно передавайте архів в інше місце. Саме для цього призначене шифроване резервне копіювання за межі сервера за допомогою restic.

Оновлення Mealie

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

Змініть зафіксовану версію у файлі, потім завантажте новий образ і повторно створіть контейнер. Міграції виконуються під час першого запуску нового образу. Перед переходом на нову основну версію створіть копію тому, оскільки міграція, яка завершилася помилкою на півдорозі, може залишити базу даних, яку попередній образ більше не відкриє. Ознайомтеся з нотатками до випусків для всіх версій між поточною та новою.

Якщо імпорт не вдається

Деякі сайти взагалі не публікують структуровані дані рецептів, тому Mealie імпортує назву з порожнім списком інгредієнтів. Це не можна виправити налаштуванням. У такому разі вставте текст рецепта вручну.

Інші помилки спричинені захистом від ботів перед сайтом із рецептами. Замість рецепта цей захист повертає Mealie сторінку перевірки. Mealie вже імітує браузер і змінює user agent, щоб зменшити кількість таких випадків. Якщо сайт усе одно відхиляє запит, у документації наведено два варіанти: спрямувати scraper через proxy з кращою репутацією IP-адреси або запустити екземпляр FlareSolverr, який проходить перевірку у звичайному браузері. Обидва варіанти необов’язкові. Обидва налаштовуються через змінні середовища контейнера.

Якщо імпорт не вдається через те, що сервер взагалі не може підключитися до сайту, це інша проблема. Перевірте підключення із сервера за допомогою curl -I https://the-site.example/recipe і прочитайте рядок зі статусом, перш ніж звинувачувати scraper.

Де це застосовується

Mealie — вдалий перший self-hosted застосунок для дому, оскільки люди, з якими ви живете, користуватимуться ним без додаткових нагадувань. За призначенням він схожий на власну фототеку з Immich, але значно легший, і належить до ширшого переліку сервісів, які варто розгорнути у себе цього року. Один невеликий сервер може працювати з обома застосунками. Immich — не єдиний кандидат на цю другу роль. Якщо ви ще визначаєтеся, вимоги до пам’яті та команди резервного копіювання для PhotoPrism і Immich достатньо відрізняються, щоб ознайомитися з ними, перш ніж віддати під це решту дискового простору. Якщо разом із вечерями домогосподарство зберігає десь свої плани й нотатки, self-hosted робочий простір AFFiNE знову розгортається через compose-файл, але потребує чотирьох контейнерів і значно більше пам’яті, ніж Mealie. Спочатку перевірте, скільки ресурсів залишилося на сервері. А якщо домогосподарство хоче вести облік тренувань разом із вечерями, openGym зберігатиме дані про тренування та потребуватиме той самий зафіксований tag, compose-файл і сертифікат, які ви щойно налаштували. Вечір після вечері теж має власний варіант такого сценарію: Halcyon перетворює наявну бібліотеку Jellyfin на відеопрокат 1990-х, яким можна прогулюватися, тобто додає ще один невеликий контейнер перед сервісом, який ви вже запускаєте, а не ще одну базу даних для резервного копіювання. Не всі сервіси цієї категорії призначені для дому. Якщо такий самий підхід знадобиться для робочих завдань, self-hosted служба підтримки Chatwoot знову потребуватиме того самого зафіксованого tag і сертифіката, а також Postgres, Redis і налаштованої вихідної пошти. Це значно вимогливіший сервіс, ніж сховище рецептів, тому для нього варто виділити окремий сервер.

FAQ

Чому не вдається імпортувати URL-адресу рецепта?

Є дві поширені причини. Або сторінка не містить структурованих даних рецепта, тому scraper нічого не знаходить і ви отримуєте лише назву без інгредієнтів, або захисний шар від ботів перед сайтом повертає сторінку перевірки замість рецепта. У другому випадку Mealie можна спрямувати через proxy з кращою репутацією IP-адреси або на self-hosted екземпляр FlareSolverr, який проходить перевірку в реальному браузері. Перш ніж щось змінювати, переконайтеся, що сервер взагалі може отримати доступ до сторінки, за допомогою curl -I.

Чи потрібен PostgreSQL, чи достатньо SQLite?

Для домашнього використання достатньо SQLite, і саме він використовується за замовчуванням. Перейдіть на PostgreSQL, якщо каталог даних розташований у network attached storage, оскільки SQLite у мережевій файловій системі спричиняє помилки блокування бази даних і може пошкодити файл. Для відновлення в PostgreSQL користувач бази даних має бути superuser, оскільки під час відновлення всі дані видаляються перед завантаженням архіву.

Чи можна запускати Mealie без доменного імені?

Так, у власній мережі. Встановіть BASE_URL на адресу, яку ви фактично вводитимете, наприклад http://192.168.1.20:9925, і не налаштовуйте nginx. Посилання для запрошень і скидання пароля формуються з BASE_URL, тому неправильне значення створить посилання, які ніхто інший не зможе відкрити. Не відкривайте доступ до сервісу через інтернет із використанням звичайного HTTP, оскільки тоді облікові дані для входу передаватимуться відкритим текстом.

Як надати членам сім’ї окремі облікові записи?

Залиште ALLOW_SIGNUP зі значенням "false" і додайте користувачів в адміністративній області. Після цього буде створено посилання для запрошення, яке можна їм надіслати. Додайте всіх, хто користується однією кухнею, до одного household, щоб вони спільно використовували план харчування та список покупок. Рецепти в будь-якому разі доступні всім household у групі, тому для окремих колекцій потрібні окремі групи.

Що станеться з рецептами, якщо я припиню запускати Mealie?

Вони залишаться у вас. Резервна копія з адміністративного розділу записує дані у форматі JSON. Mealie також може експортувати рецепти як звичайні markdown-файли, які можна читати в будь-якому текстовому редакторі без додаткового програмного забезпечення. Виконайте експорт заздалегідь і перевірте, що файл відкривається.

Чи була ця стаття корисною?