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.
I-install ang Mealie gamit ang Docker Compose
Ipinopublish ng Mealie ang mga image nito sa GitHub container registry. Noong October 2026, ang kasalukuyang stable tag ay v3.28.0. Mag-pin ng bersyon sa halip na gumamit ng latest: kapag latest, maaaring malipat ka sa isang database migration sa docker compose pull na hindi mo pa napaghandaan.
sudo mkdir -p /srv/mealie
cd /srv/mealie
sudo nano docker-compose.ymlservices:
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:May dalawang linyang dapat suriin bago mo ito simulan.
Ang port ay nakasulat bilang 127.0.0.1:9925:9000 at hindi bilang 9925:9000. Nakikinig ang container sa 9000 sa loob, at ina-map ng host ang 9925 dito. Kapag itinali ang map na ito sa loopback address, maaabot ng nginx ang Mealie ngunit hindi ito maaabot mula sa internet. Nagsusulat ang Docker ng sarili nitong rules sa packet filter, kaya maaabot mula sa labas ang isang simpleng 9925:9000 kahit sinasabi ng firewall mo na sarado ang port. Mahalagang maunawaan ito nang isang beses: tingnan ang kung bakit binabalewala ng mga published Docker port ang ufw.
Ang BASE_URL ay dapat eksaktong public address na gagamitin mo, kasama ang scheme at walang trailing slash. Ginagamit ito ng Mealie sa pagbuo ng mga link para sa password reset at invitation. Itakda ito sa http://localhost:9925; kung hindi, ang invitation na ipapadala mo sa iyong partner ay maglalaman ng link na gagana lamang sa server mismo.
Simulan ito at i-monitor ang unang boot.
sudo docker compose up -d
sudo docker compose logs -f mealieSa unang pagsisimula, ginagawa ang SQLite database at pinapatakbo ang mga migration. Tumatagal ito nang ilang segundo. Kapag huminto na ang paglabas ng mga migration line sa log, suriin ang app nang lokal.
curl -I http://127.0.0.1:9925Ibig sabihin ng 200 OK ay gumagana 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 na may 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 ito, pagkatapos ay palitan agad ang dalawang ito, dahil naka-print ang pares na ito sa documentation at dahil dito ay kasama ito sa bawat scanner.
Ang ALLOW_SIGNUP: "false" sa compose file ay sinadya. Kapag bukas ang signup, maaaring gumawa ng account ang sinumang makahanap ng address sa iyong recipe box. Kapag isinara ito, magdadagdag ka ng mga tao mula sa admin area, na bubuo ng invitation link na ikaw mismo ang magpapadala sa kanila. Binubuo ang link na iyon mula sa BASE_URL, kaya mahalaga ang value na ito. Kung magpapatakbo ka ng ilang app sa iisang server at gusto mo ng iisang password para sa lahat, maaaring ipasa ng Mealie ang login nito sa isang external identity provider gaya ng self-hosted na Authentik instance.
Inilalagay ng Mealie ang mga user sa isang household, at ang mga household ay nasa loob ng isang group. Ibinabahagi ng lahat ng nasa iisang household ang meal plan at shopping list, na angkop para sa isang pamilya. Mas malawak ang recipe collection: ibinabahagi ng mga household ang kanilang recipes, tags, at categories sa lahat ng ibang household sa parehong group. Kaya ang magkakahiwalay na household sa isang server ay may magkakahiwalay na plan at listahan, pero gumagamit ng parehong recipes. Ang setup na ito ay angkop pa rin sa isang flatshare kung saan walang nagkakasundo tungkol sa anchovies. Kung kailangan ng mga tao ng ganap na magkakahiwalay na collection, ilagay sila sa magkakahiwalay na group, dahil walang ibinabahagi sa pagitan ng mga group.
Ang importer, na siyang dahilan kung bakit ito pinapatakbo
Buksan ang collection ng mga recipe, piliing gumawa ng recipe mula sa URL, at i-paste ang link. Kinukuha ni Mealie ang page at hinahanap ang structured recipe data—ang machine-readable na block na inilalagay ng karamihan sa mga recipe site para sa mga search engine. Kapag naroon ang block na ito, malinis at agad ang import.
Kung magko-configure ka ng AI provider, maaari ka ring mag-import mula sa isang image o plain text na iyong ipo-paste. Kasama rito ang larawan ng isang pahina mula sa cookbook. Kailangan ng image import ng provider na nakakabasa ng mga image. Kung walang provider, hindi available ang mga import na ito. Dumadaan ang mga ito sa mas mabagal na proseso at kailangang i-check pagkatapos, dahil madaling mapagkamalan ang handwritten fraction.
Maaari ding magsagawa ng bulk import mula sa parehong screen: mag-paste ng listahan ng mga address, tig-iisa sa bawat linya, at ipoproseso ni Mealie ang mga ito sa background. Maaaring mailipat sa isang session ang collection na may dalawang daang bookmark.
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/mealieserver {
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 nginxAng 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.comIsinusulat 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
Nasa /app/data/ sa loob ng container ang lahat ng pagmamay-ari ng Mealie. Ito ang mealie-data volume. Kapag kinopya mo ang volume na ito, magkakasama mong nakopya ang recipes, images, at database. Ayon sa sariling documentation ng Mealie, ang pagpapatigil sa container at pagkopya sa folder na ito ang pinakamainam na paraan para mag-back up ng SQLite install.
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 mealieNagsisimula ang pangalan ng volume sa project 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 pangalan na ipinapakita nito, hindi ang pangalan sa gabay na ito. Mahalaga munang ihinto ang container dahil madalas nasa kalagitnaan ng pagsusulat ang SQLite. Kung live copy ang gagamitin, maaaring hindi ito ma-restore nang mabasa.
May sarili ring backup page ang Mealie sa admin area. Gumagawa ito ng zip archive na naglalaman ng database bilang database.json. Huwag umasa rito para sa paglipat sa ibang version. Kailangang i-restore ang archive gamit ang parehong Mealie version na gumawa nito. Kapag hindi tugma ang version, hihinto ang restore na may error. Para maglipat sa ibang server, patakbuhin muna ang parehong pinned version sa bagong server. Pagkatapos, kopyahin ang volume doon o i-restore ang archive. Destructive ang pag-restore nito ayon sa disenyo: dine-delete muna nito ang kasalukuyang database bago i-load ang archive, at hindi na ito maa-undo. Ma-la-log out ka kapag natapos ito.
Hindi backup ang alinman sa dalawang kopya habang nasa parehong server lang 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 mealieItaas 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 para sa isang household ang Mealie, dahil gagamitin ito ng mga kasama mo sa bahay kahit hindi mo sila hilingang gamitin ito. 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 sulit i-self-host ngayong taon. Kayang patakbuhin ng iisang maliit na server ang dalawang ito. Hindi lang Immich ang maaaring gamitin para sa pangalawang gawain, at kung nagpapasya ka pa, sapat na magkaiba ang memory requirements at backup commands ng PhotoPrism at Immich para sulit itong basahin bago mo ilaan ang natitirang disk space. Kung nagtatago rin ang household ng mga plano at tala bukod sa mga hapunan nito, ang self-hosted na AFFiNE workspace ay isa na namang compose-file exercise, pero nangangailangan ito ng apat na container at mas malaking memory kaysa sa hinihingi ng Mealie, kaya tingnan muna kung ano pa ang available sa server. At kung gusto rin ng household na subaybayan ang training nito bukod sa mga hapunan, pinamamahalaan ng openGym ang mga workout at nangangailangan ito ng parehong pinned tag, compose file, at certificate na katatapos mo lang i-configure. May sarili ring bersyon nito ang gabi pagkatapos ng hapunan, dahil binabago ng Halcyon ang isang umiiral na Jellyfin library para maging rental shop noong 1990s na maaari mong libutin, na isa pang maliit na container sa harap ng serbisyong pinapatakbo mo na sa halip na isa na namang database na kailangang i-back up. Hindi lahat ng nasa pamilyang ito ay household app, at kung kailangan mong gamitin ang parehong setup para sa trabaho, ang self-hosted na Chatwoot support desk ay nangangailangan muli ng parehong pinned tag at certificate, kasama ang Postgres, Redis, at gumaganang outbound mail sa likod nito. Mas mabigat itong tenant kaysa sa isang recipe box at dapat bigyan ng sarili nitong server.
FAQ
Bakit nabibigo ang pag-import ng URL ng recipe?
May dalawang karaniwang sanhi. Maaaring walang structured recipe data na inilalabas ang page, kaya walang makita ang scraper at title lamang ang makukuha nang walang ingredients. Maaari ring magbalik ang bot-protection layer sa harap ng site ng challenge page sa halip na recipe. Para sa pangalawang 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 maaabot 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 ang SQLite sa network filesystem ay nagdudulot ng locked-database errors at maaaring makasira sa file. Sa PostgreSQL, kailangang superuser ang database user para sa restore, dahil binubura 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 ang maling value ay nagbubuo 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 ng sarili nilang login ang pamilya ko?
Iwanang nakatakda ang ALLOW_SIGNUP sa "false" at magdagdag ng mga tao mula sa admin area. Magbubuo ito ng invitation link na maaari mong ipadala sa kanila. Ilagay sa iisang household ang lahat ng gumagamit ng parehong kusina upang magkapareho sila ng meal plan at shopping list. Ibinabahagi ang mga recipe sa bawat household sa grupo sa alinmang paraan, kaya kailangan ng magkahiwalay na grupo ang mga taong nangangailangan ng magkahiwalay na collection.
Ano ang mangyayari sa mga recipe ko kung ititigil ko ang pagpapatakbo ng Mealie?
Mapapanatili mo ang mga ito. Isinusulat ng admin backup ang data mo bilang JSON. Maaari ring i-export ng Mealie ang mga recipe 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.