SSD Nodes Learn 🎉 VPS mula $5.50/buwan
Mga Gabay Matt ConnorNi Matt Connor · Na-update 2026-08-13

Mealie sa VPS: Self-Hosted Recipe Manager gamit ang Docker

Ipatakbo ang Mealie sa sarili mong VPS gamit ang Docker Compose. I-paste ang recipe link para sa malinis na steps, meal plan, shopping list, nginx, TLS, at backups.

Ano ang ginagawa ng self-hosted recipe manager

Iniimbak ng self-hosted recipe manager ang iyong mga recipe sa database sa server na pagmamay-ari mo, at ang Mealie ang karaniwang pinipili ng karamihan sa mga household. I-paste ang address ng recipe page, at binabasa ng Mealie mula rito ang mga ingredient, hakbang, dami ng servings, at oras ng pagluluto. Iniiwan nito ang kuwento at mga advertisement. Ang napupunta sa iyong collection ay ang recipe mismo.

Simple lang ang natitirang bahagi ng app. May weekly meal plan kung saan maaari mong i-drag ang mga recipe, at may shopping list na ginagawa batay sa planong iyon. May sariling login ang bawat taong nagluluto. Tumatakbo ang lahat sa isang container at idle ito kapag walang request, kaya kayang patakbuhin ito ng isang modest VPS nang hindi gaanong naaapektuhan ang resources.

Gumagamit ang gabay na ito ng Docker Compose. Kung bago sa iyo ang mga terminong services: at volumes:, basahin muna ang kung paano binubuo ang Docker Compose files, dahil ang lahat ng nasa ibaba ay nasa isang compose file at gumagamit ng apat na command.

Mag-install ng Mealie gamit ang Docker Compose

Ipinapublish ng Mealie ang mga image nito sa GitHub container registry. Noong July 2026, ang kasalukuyang stable tag ay v3.22.0. Mag-pin ng version sa halip na gamitin ang latest: kapag latest, maaaring ilipat ka ng docker compose pull sa database migration na hindi mo pa napaghandaan sa ibang araw.

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:

May dalawang linyang dapat suriin bago mo ito simulan.

Nakasulat ang port bilang 127.0.0.1:9925:9000 at hindi bilang 9925:9000. Nakikinig ang container sa port 9000 sa loob, at mina-map ng host ang port 9925 papunta rito. Kapag itinali ang map na iyon sa loopback address, maa-access ito ng nginx ngunit hindi ng internet. Gumagawa ang Docker ng sarili nitong rules sa packet filter, kaya naa-access mula sa labas ang isang plain 9925:9000 kahit sinasabi ng firewall mong sarado ang port. Mahalagang maunawaan ang behavior na ito: tingnan ang kung bakit hindi sinusunod ng ufw ang mga published Docker port.

Dapat eksaktong public address na gagamitin mo ang BASE_URL, kasama ang scheme at walang trailing slash. Ginagamit ito ng Mealie sa paggawa ng password reset links at invitation links. Kung itatakda mo ito sa http://localhost:9925, ang invitation na ipapadala mo sa iyong partner ay maglalaman ng link na gumagana lamang sa server mismo.

Simulan ito at i-monitor ang unang boot.

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

Sa unang pagsisimula, ginagawa ang SQLite database at pinapatakbo ang migrations. Tumatagal ito nang ilang segundo. Kapag tumigil na ang log sa pag-print ng migration lines, suriin ang app nang lokal.

curl -I http://127.0.0.1:9925

Ibig sabihin ng 200 OK ay gumagana na ang app. Ibig sabihin ng Connection refused ay hindi tumatakbo ang container: patakbuhin ang sudo docker compose ps at basahin ang exit code. Ang container na huminto gamit ang code 137 ay pinatay dahil lumampas ito sa 1000M memory limit. Nangyayari ito sa pinakamaliliit na plan.

Unang pag-login at pag-disable ng open signup

Ang default account ay changeme@example.com at ang password ay MyPassword. Mag-login gamit ang mga ito, pagkatapos ay palitan agad ang dalawa dahil naka-print ang pares na ito sa documentation at kasama na ito sa bawat scanner.

Sadyang ganoon ang ALLOW_SIGNUP: "false" sa compose file. Kapag bukas ang signup, maaaring gumawa ng account ang sinumang makahanap ng address sa iyong recipe box. Kapag sarado ito, magdadagdag ka ng mga tao mula sa admin area, na gagawa ng invitation link na ikaw mismo ang magpapadala sa kanila. Ginagawa ang link na iyon mula sa BASE_URL, kaya mahalaga ang value nito. Kung magpapatakbo ka ng ilang app sa iisang server at gusto mong iisa ang password para sa lahat, maaaring ipaubaya ng Mealie ang login nito sa external identity provider gaya ng self-hosted na Authentik instance.

Pinapangkat ng Mealie ang mga user sa isang household. Ibinabahagi ng lahat ng nasa isang household ang recipe collection, meal plan, at shopping list, na angkop para sa isang pamilya. Ang magkakahiwalay na household sa iisang server ay may magkakahiwalay na collection, na angkop para sa shared housing kapag walang nagkakasundo tungkol sa bagoong.

Ang importer, na siyang pangunahing dahilan kung bakit ito pinapatakbo

Buksan ang collection ng mga recipe, piliing gumawa ng recipe mula sa URL, at mag-paste ng link. Kinukuha ni Mealie ang page at hinahanap ang structured recipe data, ang machine-readable block na karaniwang inilalagay ng mga recipe site para sa mga search engine. Kapag naroon ang block na iyon, malinis at agad natatapos ang import.

Maaari ka ring mag-import mula sa image o plain text na iyong i-paste. Saklaw nito ang litrato ng page mula sa isang cookbook. Mas mabagal ang prosesong ito, at kailangan itong suriin pagkatapos dahil madaling mabasa nang mali ang handwritten fraction.

Tumatakbo rin ang bulk import mula sa parehong screen: mag-paste ng listahan ng mga address, tig-isa bawat linya, at pinoproseso ni Mealie ang mga ito sa background. Maaaring mailipat ang collection na may dalawang daang bookmark sa isang session.

Mga meal plan at shopping list

Ang meal planner ay isang calendar. I-drag ang isang recipe papunta sa isang araw para maisama ito sa meal plan. Kinokolekta ng shopping list ang mga ingredient mula sa mga recipe sa meal plan at pinagsasama ang magkakaparehong item. Kaya kung may dalawang recipe na parehong nangangailangan ng sibuyas, isang linya lamang ang lalabas sa halip na dalawa.

Live na page ang listahan sa phone mo habang namimili ka. Dahil nasa sarili mong server ito, iisang listahan ang nakikita ng lahat sa bahay nang sabay-sabay. Kapag minarkahan ng isang tao ang gatas bilang nabili na, mawawala rin ito sa screen ng ibang tao.

Maglagay ng nginx at TLS sa harap

Plain HTTP lang ang ginagamit ng Mealie at wala itong sariling certificate handling. I-terminate ang transport layer security (TLS) sa nginx na nasa harap nito. Magturo muna ng DNS A record sa server mo, dahil bini-verify ng certificate step ang pangalan na iyon.

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

Ang pag-print ng nginx -t at syntax is ok at test is successful ang gate. Mag-reload lamang kapag pumasa ito, dahil kapag nag-reload ng sirang configuration, mananatiling tumatakbo ang luma at hindi mapapansin ang error hanggang sa susunod na restart.

Kailangan ang client_max_body_size 64M dahil 1 MB ang default ng nginx. Kapag nag-upload ng recipe photo o nag-restore ng backup sa browser, mas malaki rito ang ipinapadalang body. Kung wala ang line na ito, makakakuha ka ng 413 Request Entity Too Large mula sa nginx, hindi mula sa Mealie, kaya walang lalabas sa application log.

Pagkatapos, i-issue ang certificate. Saklaw sa pag-issue ng Let's Encrypt certificate para sa nginx gamit ang certbot ang hakbang na ito at ang renewal timer nito.

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

Isinusulat muli ng Certbot ang server block para makinig sa 443 at nagdaragdag ng redirect mula sa port 80. I-load ang site gamit ang https:// at tiyaking tinatanggap ng browser ang certificate. Kung naglo-load ang Mealie pero dinadala ka ng sarili nitong links sa http://, nakatakda pa rin ang BASE_URL sa http. Kailangang itama ito, at pagkatapos ay gamitin ang sudo docker compose up -d para muling likhain ang container gamit ang bagong value.

Hindi gumagana ang pag-serve ng Mealie sa ilalim ng subpath gaya ng example.com/recipes, dahil hindi maihahatid ang frontend mula sa subpath. Gumamit ng subdomain.

Mga Backup, at kung ano talaga ang ginagawa ng restore

Lahat ng pagmamay-ari ng Mealie ay nasa /app/data/ sa loob ng container, at ito ang mealie-data volume. Kapag kinopya mo ang volume na ito, sabay mong nakokopya ang recipes, images, at database.

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

May project name bilang prefix ang volume name, at ang project name ay ang directory na naglalaman ng compose file. Mula sa /srv/mealie, ang volume ay mealie_mealie-data, kaya docker volume ls ang unang command: gamitin ang pangalang ipinapakita nito, hindi ang pangalan sa guide na ito. Mahalagang ihinto muna ang container, dahil madalas na nasa kalagitnaan ng pagsusulat ang SQLite at maaaring maging unreadable ang isang live copy kapag ni-restore.

May sarili ring backup page ang Mealie sa admin area. Gumagawa ito ng portable archive na naglalaman ng database bilang JSON kasama ng images. Gamitin ito kapag lilipat sa ibang server, dahil nananatili itong gumagana sa version change na maaaring hindi kayanin ng raw file copy. Destructive ang pag-restore nito ayon sa disenyo: dine-delete muna nito ang kasalukuyang database bago i-load ang archive, at hindi na ito maaaring i-undo. Mala-log out ka kapag natapos ito.

Hindi backup ang alinman sa dalawang kopya habang nasa iisang server lamang ang mga ito. I-push ang archive sa ibang lokasyon ayon sa schedule. Ito ang gamit ng encrypted off-server backups gamit ang restic.

Pag-update ng Mealie

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

Itaas ang naka-pin na version sa file, pagkatapos ay i-pull at i-recreate ang container. Tumatakbo ang mga migration sa unang pag-start ng bagong image. Gumawa ng kopya ng volume bago magpalit ng major version, dahil kapag nabigo sa kalagitnaan ang migration, maaaring maiwan ang database na hindi na mabubuksan ng dating image. Basahin ang release notes para sa lahat ng release sa pagitan ng kasalukuyan mong version at ng bagong version.

Kapag nabigo ang importer

May ilang site na hindi naglalabas ng structured recipe data. Dahil dito, nag-i-import ang Mealie ng title na walang laman ang ingredient list. Hindi ito maaayos sa configuration. I-paste na lang nang mano-mano ang text ng recipe.

Ang ibang failure ay dulot ng bot protection sa harap ng recipe site. Challenge page ang ibinabalik nito sa Mealie sa halip na ang recipe. Ginagaya na ng Mealie ang browser at pinapalitan nito ang user agent upang mabawasan ang ganitong problema. Kapag tumanggi pa rin ang site, ang mga dokumentadong option ay ipadaan ang scraper sa proxy na may mas magandang address reputation, o magpatakbo ng FlareSolverr instance na lumulutas sa challenge gamit ang totoong browser. Optional ang dalawang ito, at parehong kino-configure sa pamamagitan ng environment variables sa container.

Ibang problema naman kung nabigo ang import dahil hindi talaga maabot ng server mo ang site. I-test ito mula sa server gamit ang curl -I https://the-site.example/recipe at basahin ang status line bago sisihin ang scraper.

Kung saan ito nababagay

Magandang unang self-hosted application ang Mealie para sa isang household dahil gagamitin ito ng mga kasama mo sa bahay kahit hindi mo sila kailangang sabihan. Kapareho ito ng uri ng gawain ng pagpapatakbo ng sarili mong photo library gamit ang Immich, pero mas magaan, at kabilang ito sa mas malawak na listahan ng mga application na sulit i-self-host ngayong taon. Kayang patakbuhin ng isang maliit na server ang dalawang ito. Hindi lamang Immich ang puwedeng gamitin para sa ikalawang gawain, at kung nagpapasya ka pa, magkakaiba nang sapat ang memory floor at backup command ng PhotoPrism at Immich para sulit itong basahin bago mo ilaan ang natitirang disk space.

FAQ

Bakit nabibigo ang pag-import ng recipe URL?

May dalawang karaniwang dahilan. Maaaring walang structured recipe data ang page, kaya walang makita ang scraper at title lang ang makukuha nang walang ingredients. Maaari ring magbalik ng challenge page ang bot-protection layer sa harap ng site sa halip na ang recipe. Para sa ikalawang kaso, maaaring ituro ang Mealie sa proxy na may mas magandang address reputation, o sa self-hosted na FlareSolverr instance na lumulutas sa challenge gamit ang totoong browser. Tiyaking naaabot ng server mo ang page gamit ang curl -I bago magbago ng anuman.

Kailangan ko ba ng PostgreSQL, o sapat na ang SQLite?

Sapat na ang SQLite para sa isang household, at ito ang default. Lumipat sa PostgreSQL kapag nasa network attached storage ang data directory, dahil nagdudulot ang SQLite sa network filesystem ng locked-database errors at maaaring masira ang file. Sa PostgreSQL, kailangang superuser ang database user para sa restore, dahil buburahin muna ng restore ang lahat bago i-load ang archive.

Maaari ko bang patakbuhin ang Mealie nang walang domain name?

Oo, sa sarili mong network. Itakda ang BASE_URL sa address na aktuwal mong ita-type, gaya ng http://192.168.1.20:9925, at huwag nang gumamit ng nginx. Binubuo ang invitation at password reset links mula sa BASE_URL, kaya kapag mali ang value, makakagawa ito ng links na hindi mabubuksan ng iba. Huwag itong ilantad sa internet gamit ang plain HTTP, dahil ipapadala nang walang encryption ang login.

Paano ko bibigyan ang pamilya ko ng sarili nilang login?

Iwanang nakatakda ang ALLOW_SIGNUP sa "false" at magdagdag ng mga tao mula sa admin area. Gagawa ito ng invitation link na maaari mong ipadala sa kanila. Ilagay sa iisang household ang lahat ng gumagamit ng parehong kusina para mag-share sila ng recipes, meal plan, at shopping list. Ang magkakahiwalay na household sa iisang server ay may magkakahiwalay na collection.

Ano ang mangyayari sa mga recipe ko kung ititigil ko ang pagpapatakbo ng Mealie?

Mailalabas mo ang mga ito. Isinusulat ng admin backup ang data mo bilang JSON. Maaari ring mag-export ang Mealie ng recipes bilang plain markdown files, na mananatiling mababasa sa anumang text editor kahit walang software. Gumawa ng isang export bago mo ito kailanganin at tiyaking mabubuksan mo ito.