SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-13

Cara Pasang Mealie di VPS Menggunakan Docker Compose

Ketahui langkah mudah memasang Mealie pada VPS anda menggunakan Docker Compose. Urus resipi, rancang hidangan, dan jana senarai beli-belah dengan pelayan peribadi anda.

Fungsi pengurus resipi yang dihoskan sendiri

Pengurus resipi yang dihoskan sendiri menyimpan resipi anda dalam pangkalan data pada pelayan milik anda, dan Mealie merupakan pilihan utama kebanyakan isi rumah. Anda hanya perlu menampal alamat laman resipi dan Mealie akan membaca bahan-bahan, langkah-langkah, hasil hidangan serta masa memasak daripadanya, kemudian membuang cerita latar belakang dan iklan. Apa yang disimpan dalam koleksi anda hanyalah maklumat makanan tersebut.

Selebihnya, aplikasi ini bersaiz kecil. Terdapat perancang hidangan mingguan yang membolehkan anda mengheret resipi ke dalamnya, serta senarai beli-belah yang dibina berdasarkan rancangan tersebut. Setiap individu yang memasak mendapat log masuk sendiri. Kesemuanya berjalan dalam satu kontena, dan ia berada dalam keadaan melahu antara permintaan, jadi VPS yang sederhana mampu menampungnya tanpa sebarang bebanan.

Panduan ini menggunakan Docker Compose. Jika istilah services: dan volumes: baharu bagi anda, baca cara fail Docker Compose disusun terlebih dahulu, kerana segala yang dinyatakan di bawah terdiri daripada satu fail compose dan empat arahan.

Memasang Mealie dengan Docker Compose

Mealie menerbitkan imejnya ke dalam GitHub container registry. Setakat Julai 2026, tag stabil semasa ialah v3.22.0. Tetapkan versi (pin) dan jangan gunakan latest: dengan latest, docker compose pull pada hari yang tidak dijangka boleh menyebabkan migrasi pangkalan data berlaku tanpa persediaan anda.

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:

Dua baris perlu diperiksa sebelum anda memulakannya.

Port ditulis sebagai 127.0.0.1:9925:9000 dan bukannya 9925:9000. Kontena mendengar pada port 9000 di dalam, dan hos memetakan 9925 kepadanya. Mengikat pemetaan tersebut kepada alamat loopback bermakna Nginx boleh mencapai Mealie manakala internet tidak boleh. Docker menulis peraturannya sendiri ke dalam penapis paket, jadi 9925:9000 biasa boleh dicapai dari luar walaupun firewall anda menyatakan port tersebut ditutup. Kejutan ini perlu difahami sekali: lihat mengapa port Docker yang diterbitkan mengabaikan ufw.

BASE_URL mestilah alamat awam tepat yang akan anda gunakan, lengkap dengan skema dan tanpa garis miring (trailing slash) di hujung. Mealie membina pautan tetapan semula kata laluan dan pautan jemputan daripadanya. Tetapkannya kepada http://localhost:9925 dan jemputan yang anda hantar kepada pasangan anda akan mengandungi pautan yang hanya berfungsi pada pelayan itu sendiri.

Mulakan ia dan perhatikan but pertama.

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

Permulaan pertama mencipta pangkalan data SQLite dan menjalankan migrasi, yang mengambil masa beberapa saat. Apabila log menjadi stabil dan berhenti mencetak baris migrasi, periksa aplikasi secara setempat.

curl -I http://127.0.0.1:9925

200 OK bermakna aplikasi sedang berjalan. Connection refused bermakna kontena tidak berjalan: jalankan sudo docker compose ps dan baca kod keluar (exit code). Kontena yang berhenti dengan kod 137 telah dimatikan kerana melebihi had memori 1000M, yang sering berlaku pada pelan paling kecil.

Log masuk pertama dan mematikan pendaftaran terbuka

Akaun lalai ialah changeme@example.com dengan kata laluan MyPassword. Log masuk menggunakan akaun tersebut, kemudian tukar kedua-duanya dengan segera, kerana pasangan tersebut dicetak dalam dokumentasi dan oleh itu diketahui oleh setiap pengimbas.

ALLOW_SIGNUP: "false" dalam fail compose adalah disengajakan. Dengan pendaftaran terbuka, sesiapa sahaja yang menemui alamat tersebut boleh mencipta akaun dalam kotak resipi anda. Dengan pendaftaran ditutup, anda menambah orang daripada kawasan pentadbir, yang menjana pautan jemputan untuk anda hantar sendiri kepada mereka. Pautan tersebut dibina daripada BASE_URL, itulah sebabnya nilai tersebut penting. Jika anda akhirnya menjalankan beberapa aplikasi pada pelayan yang sama dan mahukan satu kata laluan untuk kesemuanya, Mealie boleh menyerahkan log masuknya kepada pembekal identiti luaran seperti instans Authentik yang dihoskan sendiri.

Mealie mengumpulkan pengguna ke dalam satu isi rumah. Semua orang dalam satu isi rumah berkongsi koleksi resipi, pelan hidangan dan senarai beli-belah, iaitu apa yang diingini oleh sesebuah keluarga. Isi rumah yang berasingan pada pelayan yang sama mengekalkan koleksi yang berasingan, iaitu apa yang diingini oleh rakan serumah apabila tiada siapa yang bersetuju tentang ikan bilis.

Pengimport, iaitu sebab utama untuk menjalankan ini

Buka koleksi resipi, pilih untuk mencipta resipi daripada URL, dan tampal pautan tersebut. Mealie akan mengambil halaman tersebut dan mencari data resipi berstruktur, iaitu blok boleh baca mesin yang disematkan oleh kebanyakan laman resipi untuk enjin carian. Apabila blok tersebut tersedia, proses import adalah bersih dan serta-merta.

Anda juga boleh mengimport daripada imej atau teks biasa yang anda tampal, yang merangkumi gambar halaman daripada buku masakan. Proses tersebut melalui laluan yang lebih perlahan dan memerlukan semakan selepas itu, memandangkan pecahan tulisan tangan mudah disalah baca.

Import pukal dijalankan daripada skrin yang sama: tampal senarai alamat, satu bagi setiap baris, dan Mealie akan memprosesnya di latar belakang. Koleksi dua ratus penanda buku boleh dipindahkan dalam satu sesi.

Pelan makan dan senarai beli-belah

Perancang makan ialah sebuah kalendar. Seret resipi ke atas mana-mana hari untuk merancangnya. Senarai beli-belah kemudian mengumpulkan bahan-bahan daripada resipi yang dirancang ke dalam satu senarai dan menggabungkan item yang sama, jadi dua resipi yang memerlukan bawang akan menghasilkan satu baris sahaja dan bukannya dua.

Senarai ini merupakan halaman langsung pada telefon anda semasa di kedai. Oleh kerana pelayan anda sendiri yang menyimpannya, semua orang dalam isi rumah melihat senarai yang sama pada masa yang sama, dan apabila seorang individu menanda susu sebagai selesai, ia akan hilang daripada skrin orang lain.

Letakkan nginx dan TLS di hadapan

Mealie menggunakan HTTP biasa dan tidak mempunyai pengendalian sijilnya sendiri. Tamatkan transport layer security (TLS) dalam nginx di hadapannya. Halakan rekod DNS A ke pelayan anda terlebih dahulu, kerana langkah sijil akan mengesahkan nama tersebut.

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 mencetak syntax is ok dan test is successful adalah langkah penentu. Lakukan reload hanya selepas ia lulus, kerana melakukan reload pada konfigurasi yang rosak akan membiarkan konfigurasi lama terus berjalan dan menyembunyikan kesilapan sehingga but semula yang seterusnya.

client_max_body_size 64M diletakkan di situ kerana tetapan lalai nginx ialah 1 MB. Memuat naik foto resipi atau memulihkan sandaran melalui pelayar akan menghantar badan permintaan yang lebih besar daripada itu, dan tanpa baris tersebut anda akan mendapat ralat 413 Request Entity Too Large daripada nginx, bukan daripada Mealie, jadi log aplikasi tidak menunjukkan apa-apa langsung.

Kemudian, keluarkan sijil tersebut. Langkah itu dan pemasa pembaharuannya diliputi dalam mengeluarkan sijil Let's Encrypt untuk nginx dengan certbot.

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

Certbot menulis semula blok pelayan untuk mendengar pada 443 dan menambah ubah hala (redirect) daripada port 80. Muatkan laman tersebut melalui https:// dan sahkan pelayar menerima sijil tersebut. Jika Mealie dimuatkan tetapi pautan aplikasinya sendiri menghantar anda ke http://, maka BASE_URL masih menyatakan http dan perlu diperbetulkan, diikuti dengan sudo docker compose up -d untuk mencipta semula kontena dengan nilai baharu tersebut.

Menghidangkan Mealie di bawah subpath seperti example.com/recipes tidak akan berfungsi, kerana frontend tidak boleh dihidangkan daripada subpath. Gunakan subdomain.

Sandaran, dan perkara yang sebenarnya dilakukan oleh pemulihan

Segala data milik Mealie berada di dalam /app/data/ di dalam kontena, iaitu volum mealie-data. Salin volum tersebut dan anda telah menyalin resipi, imej, dan pangkalan data secara serentak.

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

Nama volum membawa nama projek sebagai awalan, dan nama projek ialah direktori yang menyimpan fail compose. Daripada /srv/mealie, volum tersebut ialah mealie_mealie-data, itulah sebabnya arahan pertama ialah docker volume ls: gunakan nama yang dipaparkan, bukan nama dalam panduan ini. Menghentikan kontena terlebih dahulu adalah penting, kerana SQLite sering berada dalam proses penulisan sehingga salinan secara langsung (live copy) mungkin tidak boleh dibaca semasa pemulihan.

Mealie juga mempunyai halaman sandaran sendiri di kawasan pentadbir, yang menulis arkib mudah alih yang mengandungi pangkalan data dalam format JSON bersama imej anda. Gunakan kaedah ini untuk berpindah antara pelayan, kerana ia mampu bertahan terhadap perubahan versi yang mungkin tidak dapat dilakukan oleh salinan fail mentah. Memulihkan arkib adalah bersifat destruktif mengikut reka bentuknya: ia memadamkan pangkalan data semasa sebelum memuatkan arkib, dan tindakan ini tidak boleh dibatalkan. Anda akan dilog keluar apabila proses tersebut selesai.

Kedua-dua salinan tersebut bukanlah sandaran selagi ia berada pada pelayan yang sama. Hantar arkib ke lokasi lain mengikut jadual, iaitu tujuan bagi sandaran luar pelayan yang disulitkan dengan restic.

Mengemas kini Mealie

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

Tingkatkan versi yang disematkan (pinned version) di dalam fail, kemudian lakukan pull dan cipta semula bekas tersebut. Migrasi akan dijalankan pada permulaan pertama imej baharu. Buat salinan volum sebelum melakukan perubahan versi utama, kerana migrasi yang gagal di pertengahan jalan akan menyebabkan pangkalan data tidak dapat dibuka oleh imej versi sebelumnya. Baca nota keluaran (release notes) bagi setiap versi antara versi semasa anda dengan versi baharu.

Apabila pengimport gagal

Sesetengah laman web tidak menerbitkan data resipi berstruktur langsung, dan Mealie kemudian mengimport tajuk dengan senarai ramuan yang kosong. Ini bukanlah sesuatu yang boleh diselesaikan melalui konfigurasi. Sebaliknya, tampal teks resipi secara manual.

Kegagalan lain berpunca daripada perlindungan bot di hadapan laman web resipi, yang membalas Mealie dengan halaman cabaran (challenge page) dan bukannya resipi. Mealie sudah pun menyamar sebagai pelayar dan menukar user agent untuk mengurangkan perkara ini. Apabila sesebuah laman web masih menolak, pilihan yang didokumentasikan adalah dengan menghantar pengikis (scraper) melalui proksi yang mempunyai reputasi alamat yang lebih baik, atau menjalankan instans FlareSolverr yang menyelesaikan cabaran tersebut dalam pelayar sebenar. Kedua-duanya adalah pilihan, dan kedua-duanya ditetapkan melalui pemboleh ubah persekitaran (environment variables) pada kontena.

Import yang gagal kerana pelayan anda tidak dapat mencapai laman web tersebut sama sekali adalah masalah yang berbeza. Uji perkara itu dari pelayan dengan curl -I https://the-site.example/recipe dan baca baris status sebelum menyalahkan pengikis.

Kedudukannya

Mealie ialah aplikasi layan diri (self-hosted) yang sesuai untuk permulaan bagi sesebuah isi rumah, kerana ahli keluarga anda akan menggunakannya tanpa perlu disuruh. Ia mempunyai skop kerja yang sama seperti mengendalikan pustaka foto anda sendiri dengan Immich, walaupun jauh lebih ringan, dan ia terletak dalam senarai yang lebih luas mengenai perkara yang berbaloi untuk dihoskan sendiri pada tahun ini. Sebuah pelayan kecil boleh menampung kedua-duanya. Immich bukanlah satu-satunya calon untuk tugas kedua itu, dan jika anda masih membuat keputusan, keperluan memori dan arahan sandaran bagi PhotoPrism serta Immich mempunyai perbezaan yang cukup ketara untuk dibaca sebelum anda memperuntukkan baki ruang cakera anda.

FAQ

Mengapa import URL resipi gagal?

Terdapat dua punca biasa. Sama ada halaman tersebut tidak menerbitkan data resipi berstruktur, menyebabkan pengikis (scraper) tidak menemui apa-apa dan anda mendapat tajuk tanpa bahan, atau lapisan perlindungan bot di hadapan tapak tersebut memaparkan halaman cabaran dan bukannya resipi. Bagi kes kedua, Mealie boleh dihalakan ke proksi dengan reputasi alamat yang lebih baik, atau ke instans FlareSolverr yang dihoskan sendiri yang menyelesaikan cabaran tersebut dalam pelayar sebenar. Pastikan pelayan anda boleh mencapai halaman tersebut dengan curl -I sebelum mengubah apa-apa.

Adakah saya perlukan PostgreSQL, atau adakah SQLite mencukupi?

SQLite mencukupi untuk kegunaan isi rumah, dan ia merupakan tetapan lalai. Beralihlah kepada PostgreSQL apabila direktori data berada pada storan rangkaian (NAS), kerana SQLite melalui sistem fail rangkaian akan menghasilkan ralat pangkalan data terkunci dan boleh merosakkan fail tersebut. Pemulihan di bawah PostgreSQL memerlukan pengguna pangkalan data menjadi superuser, kerana proses pemulihan memadamkan segala-galanya sebelum memuatkan arkib.

Bolehkah saya menjalankan Mealie tanpa nama domain?

Boleh, dalam rangkaian anda sendiri. Tetapkan BASE_URL kepada alamat yang akan anda taip, contohnya http://192.168.1.20:9925, dan langkau nginx. Pautan jemputan dan tetapan semula kata laluan dibina daripada BASE_URL, jadi nilai yang salah akan menghasilkan pautan yang tidak boleh dibuka oleh orang lain. Jangan dedahkannya kepada internet melalui HTTP biasa, kerana maklumat log masuk akan dihantar dalam bentuk teks jelas (clear text).

Bagaimanakah cara saya memberikan ahli keluarga log masuk mereka sendiri?

Biarkan ALLOW_SIGNUP ditetapkan kepada "false" dan tambah orang daripada kawasan pentadbir, yang akan menghasilkan pautan jemputan untuk anda hantar kepada mereka. Letakkan semua orang yang berkongsi dapur dalam isi rumah yang sama supaya mereka berkongsi resipi, pelan makan dan senarai beli-belah. Isi rumah yang berasingan pada satu pelayan akan mengekalkan koleksi yang berasingan.

Apakah yang berlaku kepada resipi saya jika saya berhenti menjalankan Mealie?

Data anda boleh dikeluarkan. Sandaran pentadbir menulis data anda sebagai JSON, dan Mealie juga boleh mengeksport resipi sebagai fail markdown biasa, yang kekal boleh dibaca dalam mana-mana penyunting teks tanpa memerlukan sebarang perisian. Lakukan satu eksport sebelum anda memerlukannya dan pastikan anda boleh membukanya.