SSD Nodes Learn 🎉 VPS od $5.50/mies.
Przewodniki Matt ConnorAutor: Matt Connor · Zaktualizowano 2026-08-13

Mealie na własnym VPS: instalacja przez Docker Compose

Instrukcja uruchomienia menedżera przepisów Mealie na serwerze VPS przy użyciu Docker Compose. Konfiguracja obejmuje automatyczne pobieranie danych, listy zakupów oraz TLS.

Funkcje własnego menedżera przepisów

Własny menedżer przepisów przechowuje dane w bazie na posiadanym serwerze, a Mealie jest rozwiązaniem najczęściej wybieranym w gospodarstwach domowych. Po wklejeniu adresu strony z przepisem, Mealie odczytuje składniki, instrukcje, liczbę porcji oraz czas przygotowania, pomijając opisy i reklamy. W kolekcji zapisywane są wyłącznie informacje o potrawie.

Pozostałe funkcje aplikacji są ograniczone. Dostępny jest tygodniowy plan posiłków, do którego przeciąga się przepisy, oraz lista zakupów generowana na podstawie tego planu. Każdy użytkownik otrzymuje własne dane logowania. Całość działa w jednym kontenerze i pozostaje w stanie spoczynku między żądaniami, dzięki czemu nawet skromny VPS obsługuje aplikację bez zauważalnego obciążenia.

Niniejszy przewodnik wykorzystuje Docker Compose. Jeśli pojęcia services: oraz volumes: są nieznane, należy najpierw zapoznać się z budową plików Docker Compose, ponieważ poniższa konfiguracja składa się z jednego pliku compose oraz czterech poleceń.

Instalacja Mealie przy użyciu Docker Compose

Mealie publikuje swoje obrazy w rejestrze kontenerów GitHub. Według stanu na lipiec 2026 roku, aktualną stabilną wersją jest v3.22.0. Należy przypiąć konkretną wersję zamiast używać latest: przy latest, docker compose pull w dowolnym dniu może wymusić migrację bazy danych, na którą system nie jest przygotowany.

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:

Dwie linie wymagają uwagi przed uruchomieniem.

Port zapisano jako 127.0.0.1:9925:9000, a nie 9925:9000. Kontener nasłuchuje wewnątrz na porcie 9000, a host mapuje na niego port 9925. Powiązanie tego mapowania z adresem loopback sprawia, że Nginx może połączyć się z Mealie, natomiast dostęp z Internetu jest zablokowany. Docker automatycznie dodaje własne reguły do filtra pakietów, więc zwykłe 9925:9000 jest osiągalne z zewnątrz, nawet jeśli zapora sieciowa wskazuje, że port jest zamknięty. Warto zrozumieć ten mechanizm: zobacz dlaczego opublikowane porty Docker ignorują ufw.

BASE_URL musi być dokładnym adresem publicznym, którego będziesz używać, wraz ze schematem i bez ukośnika na końcu. Mealie generuje na jego podstawie linki do resetowania hasła oraz zaproszenia. Ustawienie wartości http://localhost:9925 spowoduje, że wysłane zaproszenie będzie zawierać link działający wyłącznie na samym serwerze.

Uruchom usługę i obserwuj pierwszy start.

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

Pierwsze uruchomienie tworzy bazę danych SQLite i przeprowadza migracje, co trwa kilka sekund. Gdy logi się ustabilizują i przestaną wyświetlać komunikaty o migracjach, sprawdź działanie aplikacji lokalnie.

curl -I http://127.0.0.1:9925

Kod 200 OK oznacza, że aplikacja działa. Connection refused oznacza, że kontener nie jest uruchomiony: wykonaj sudo docker compose ps i odczytaj kod wyjścia. Kontener, który zatrzymał się z kodem 137, został zabity z powodu przekroczenia limitu pamięci 1000M, co zdarza się w najmniejszych planach taryfowych.

Pierwsze logowanie i wyłączenie otwartej rejestracji

Domyślne konto to changeme@example.com z hasłem MyPassword. Należy się na nie zalogować, a następnie natychmiast zmienić oba parametry, ponieważ ta para jest podana w dokumentacji i znajduje się w bazach każdego skanera.

Ustawienie ALLOW_SIGNUP: "false" w pliku compose jest celowe. Przy otwartej rejestracji każda osoba, która znajdzie adres, może utworzyć konto w Twoim zbiorze przepisów. Po jej zamknięciu użytkowników dodaje się z poziomu panelu administratora, co generuje link zaproszenia przesyłany samodzielnie. Link ten jest tworzony na podstawie BASE_URL, dlatego ta wartość ma znaczenie. Jeśli na tym samym serwerze uruchomionych jest kilka aplikacji i wymagane jest używanie jednego hasła do wszystkich, Mealie może przekazać proces logowania do zewnętrznego dostawcy tożsamości, takiego jak własna instancja Authentik.

Mealie grupuje użytkowników w gospodarstwa domowe. Wszyscy członkowie jednego gospodarstwa współdzielą kolekcję przepisów, plan posiłków oraz listę zakupów, co jest rozwiązaniem pożądanym w rodzinie. Osobne gospodarstwa na tym samym serwerze utrzymują odrębne kolekcje, co sprawdza się w przypadku współdzielonego mieszkania, gdy lokatorzy nie mogą dojść do porozumienia w kwestii dodatków do potraw.

Importer, czyli powód uruchomienia tej usługi

Otwórz kolekcję przepisów, wybierz opcję utworzenia przepisu z adresu URL i wklej link. Mealie pobiera stronę i wyszukuje ustrukturyzowane dane przepisu, czyli blok czytelny dla maszyn, który większość witryn kulinarnych osadza na potrzeby wyszukiwarek. Gdy ten blok jest obecny, import przebiega czysto i natychmiastowo.

Możesz również importować z obrazu lub wklejonego tekstu, co pozwala na obsługę zdjęcia strony z książki kucharskiej. Te dane przechodzą przez wolniejszą ścieżkę i wymagają późniejszej weryfikacji, ponieważ odręcznie zapisane ułamki łatwo błędnie odczytać.

Import zbiorczy uruchamia się z tego samego ekranu: wklej listę adresów, po jednym w linii, a Mealie przetworzy je w tle. Kolekcja dwustu zakładek zostanie przeniesiona w jednej sesji.

Plany posiłków i lista zakupów

Planer posiłków to kalendarz. Przeciągnij przepis na wybrany dzień, aby go zaplanować. Lista zakupów automatycznie zbiera składniki z zaplanowanych przepisów w jeden zestaw i łączy duplikaty, dzięki czemu dwa przepisy wymagające cebuli generują jedną pozycję zamiast dwóch.

Lista jest aktywną stroną dostępną na telefonie podczas zakupów. Ponieważ dane znajdują się na własnym serwerze, wszyscy domownicy widzą tę samą listę w tym samym czasie, a odznaczenie mleka przez jedną osobę powoduje jego usunięcie z ekranu pozostałych użytkowników.

Umieszczenie nginx i TLS przed aplikacją

Mealie obsługuje wyłącznie zwykły protokół HTTP i nie posiada własnych mechanizmów obsługi certyfikatów. Należy zakończyć szyfrowanie TLS w nginx przed aplikacją. W pierwszej kolejności należy skierować rekord DNS typu A na serwer, ponieważ proces uzyskiwania certyfikatu weryfikuje tę nazwę.

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 wyświetla syntax is ok oraz test is successful, co stanowi zabezpieczenie. Przeładowanie konfiguracji należy wykonać dopiero po pomyślnej weryfikacji, ponieważ przeładowanie błędnej konfiguracji pozostawia działającą poprzednią wersję i ukrywa błąd aż do następnego restartu.

client_max_body_size 64M jest wymagane, ponieważ domyślna wartość w nginx wynosi 1 MB. Przesyłanie zdjęcia przepisu lub przywracanie kopii zapasowej przez przeglądarkę wysyła większy obiekt, a bez tej linii otrzymasz 413 Request Entity Too Large z poziomu nginx, a nie z Mealie, przez co dziennik aplikacji nie wykaże żadnego zdarzenia.

Następnie należy wydać certyfikat. Ten krok oraz harmonogram jego odnawiania zostały opisane w wydawanie certyfikatu Let's Encrypt dla nginx przy użyciu certbot.

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

Certbot modyfikuje blok serwera, aby nasłuchiwał na porcie 443 i dodaje przekierowanie z portu 80. Należy załadować stronę przez https:// i potwierdzić, że przeglądarka akceptuje certyfikat. Jeśli Mealie się ładuje, ale własne odnośniki kierują na http://, oznacza to, że BASE_URL nadal zawiera http i wymaga poprawy, po której należy wykonać sudo docker compose up -d w celu odtworzenia kontenera z nową wartością.

Udostępnianie Mealie w podkatalogu, takim jak example.com/recipes, nie działa, ponieważ frontend nie może być serwowany z poziomu podkatalogu. Należy użyć subdomeny.

Kopie zapasowe i proces przywracania danych

Wszystkie dane Mealie znajdują się w /app/data/ wewnątrz kontenera, co stanowi wolumen mealie-data. Skopiowanie tego wolumenu oznacza skopiowanie przepisów, obrazów oraz bazy danych.

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

Nazwa wolumenu zawiera prefiks będący nazwą projektu, a nazwą projektu jest katalog zawierający plik compose. Z poziomu /srv/mealie wolumenem jest mealie_mealie-data, dlatego pierwszym poleceniem jest docker volume ls: należy użyć nazwy wyświetlonej przez system, a nie nazwy z tego przewodnika. Zatrzymanie kontenera przed wykonaniem kopii jest istotne, ponieważ SQLite często wykonuje operacje zapisu, co może prowadzić do przywrócenia nieczytelnej kopii w przypadku kopiowania działającej bazy.

Mealie posiada również własną stronę tworzenia kopii zapasowych w panelu administracyjnym, która generuje przenośne archiwum zawierające bazę danych w formacie JSON oraz obrazy. Należy używać tej metody podczas przenoszenia danych między serwerami, ponieważ jest ona odporna na zmiany wersji, w przeciwieństwie do bezpośredniego kopiowania plików. Przywracanie danych tą metodą jest z założenia procesem destrukcyjnym: usuwa bieżącą bazę danych przed załadowaniem archiwum i nie można go cofnąć. Po zakończeniu operacji użytkownik zostaje wylogowany.

Żadna kopia nie stanowi zabezpieczenia, jeśli znajduje się na tym samym serwerze. Archiwum należy regularnie przesyłać w inne miejsce, do czego służą szyfrowane kopie zapasowe poza serwerem przy użyciu restic.

Aktualizacja Mealie

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

Zwiększ przypisaną wersję w pliku, a następnie pobierz obraz i odtwórz kontener. Migracje uruchamiają się przy pierwszym starcie nowego obrazu. Przed zmianą wersji głównej wykonaj kopię zapasową wolumenu, ponieważ nieudana migracja może pozostawić bazę danych w stanie nieobsługiwanym przez poprzednią wersję obrazu. Zapoznaj się z informacjami o wydaniu dla wszystkich wersji pomiędzy obecnie używaną a docelową.

Gdy importer zawodzi

Niektóre witryny nie publikują żadnych ustrukturyzowanych danych przepisów, przez co Mealie importuje jedynie tytuł z pustą listą składników. Tego problemu nie da się rozwiązać poprzez konfigurację. W takim przypadku należy ręcznie wkleić tekst przepisu.

Inne błędy wynikają z mechanizmów ochrony przed botami, które znajdują się przed witryną z przepisami. Zamiast treści przepisu, Mealie otrzymuje stronę z wyzwaniem (challenge). Mealie podszywa się pod przeglądarkę i rotuje swój user agent, aby ograniczyć to zjawisko. Jeśli witryna nadal odmawia dostępu, udokumentowane opcje obejmują skierowanie scrapera przez proxy o lepszej reputacji adresu IP lub uruchomienie instancji FlareSolverr, która rozwiązuje wyzwanie w rzeczywistej przeglądarce. Obie opcje są nieobowiązkowe i konfiguruje się je za pomocą zmiennych środowiskowych kontenera.

Import, który kończy się niepowodzeniem z powodu braku łączności serwera z witryną, jest odrębnym problemem. Przed przypisaniem winy scraperowi, należy przetestować połączenie z poziomu serwera za pomocą curl -I https://the-site.example/recipe i sprawdzić kod stanu w odpowiedzi.

Miejsce w architekturze

Mealie to dobra pierwsza aplikacja do samodzielnego hostowania w gospodarstwie domowym, ponieważ domownicy będą z niej korzystać bez dodatkowej zachęty. Jest to zadanie o podobnym charakterze co prowadzenie własnej biblioteki zdjęć za pomocą Immich, choć znacznie mniej obciążające dla zasobów. Aplikacja ta wpisuje się w szerszą listę rzeczy, które warto hostować samodzielnie w tym roku. Jeden niewielki serwer może obsłużyć oba te rozwiązania. Immich nie jest jedynym kandydatem do tego drugiego zadania. Jeśli decyzja jeszcze nie zapadła, minimalne wymagania pamięciowe oraz polecenia kopii zapasowych dla PhotoPrism i Immich różnią się na tyle, że warto zapoznać się z nimi przed przydzieleniem pozostałej części dysku.

FAQ

Dlaczego importowanie przepisu z adresu URL kończy się niepowodzeniem?

Istnieją dwie częste przyczyny. Albo strona nie publikuje ustrukturyzowanych danych przepisu, przez co scraper nic nie znajduje i otrzymujesz tytuł bez składników, albo warstwa ochrony przed botami przed stroną zwraca stronę z wyzwaniem zamiast przepisu. W drugim przypadku Mealie można skierować na proxy z lepszą reputacją adresu lub na samodzielnie hostowaną instancję FlareSolverr, która rozwiązuje wyzwanie w prawdziwej przeglądarce. Przed wprowadzeniem jakichkolwiek zmian potwierdź za pomocą curl -I, czy Twój serwer w ogóle ma dostęp do tej strony.

Czy potrzebuję PostgreSQL, czy wystarczy SQLite?

SQLite wystarcza do użytku domowego i jest ustawieniem domyślnym. Przejdź na PostgreSQL, gdy katalog danych znajduje się na sieciowej pamięci masowej (NAS), ponieważ SQLite w systemie plików sieciowych generuje błędy zablokowanej bazy danych i może uszkodzić plik. Przywracanie kopii zapasowej w PostgreSQL wymaga, aby użytkownik bazy danych posiadał uprawnienia superużytkownika, ponieważ proces przywracania usuwa wszystko przed załadowaniem archiwum.

Czy mogę uruchomić Mealie bez nazwy domeny?

Tak, we własnej sieci. Ustaw BASE_URL na adres, który faktycznie będziesz wpisywać, na przykład http://192.168.1.20:9925, i pomiń nginx. Linki do zaproszeń i resetowania hasła są tworzone na podstawie BASE_URL, więc błędna wartość spowoduje wygenerowanie linków, których nikt inny nie będzie mógł otworzyć. Nie wystawiaj usługi do Internetu przez zwykłe HTTP, ponieważ dane logowania są wtedy przesyłane otwartym tekstem.

Jak nadać członkom rodziny własne loginy?

Pozostaw ALLOW_SIGNUP ustawione na "false" i dodaj osoby z poziomu panelu administratora, co wygeneruje link zaproszenia, który im wyślesz. Umieść wszystkich, którzy dzielą kuchnię, w tym samym gospodarstwie domowym, aby współdzielili przepisy, plan posiłków i listę zakupów. Oddzielne gospodarstwa domowe na jednym serwerze zachowują odrębne kolekcje.

Co stanie się z moimi przepisami, jeśli przestanę używać Mealie?

Pozostaną dostępne. Kopia zapasowa administratora zapisuje dane w formacie JSON, a Mealie potrafi również eksportować przepisy jako zwykłe pliki markdown, które pozostają czytelne w każdym edytorze tekstu bez konieczności używania jakiegokolwiek oprogramowania. Wykonaj eksport, zanim będzie on potrzebny, i sprawdź, czy możesz go otworzyć.