在 VPS 上用 Docker Compose 自架 Mealie 食譜管理器
學會在 VPS 以 Docker Compose 部署 Mealie,貼上食譜網址即可擷取乾淨步驟,並設定餐點計畫、購物清單、nginx、TLS 與備份。
自架食譜管理工具的功能
自架食譜管理工具會將食譜儲存在自有伺服器的資料庫中,而 Mealie 是多數家庭最後會選用的工具。您只要貼上食譜網頁的網址,Mealie 就會讀取其中的食材、步驟、份量與烹調時間,並排除故事內容與廣告。最後加入收藏的只有食譜內容。
應用程式的其他功能很精簡。您可以將食譜拖曳到每週餐點計畫中,購物清單則會依據該計畫建立。每位下廚者都能使用自己的登入帳號。所有功能都在單一容器中執行,沒有請求時幾乎不會使用資源,因此一般 VPS 就能穩定承載。
本指南使用 Docker Compose。如果您不熟悉 services: 與 volumes:,請先閱讀 Docker Compose 檔案的組成方式,因為以下內容就是一個 compose 檔案與四個命令。
使用 Docker Compose 安裝 Mealie
Mealie 會將映像檔發布至 GitHub container registry。截至 2026 年 7 月,目前的穩定標籤為 v3.22.0。請固定版本,不要使用 latest:使用 latest 時,某天無關的 docker compose pull 可能會讓版本跨越尚未準備好的資料庫 migration。
sudo mkdir -p /srv/mealie
cd /srv/mealie
sudo nano docker-compose.ymlservices:
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:啟動前,有兩行內容值得先確認。
連接埠寫成 127.0.0.1:9925:9000,而不是 9925:9000。容器內部監聽 9000,主機則將 9925 對應至該連接埠。將此對應綁定至 loopback 位址後,nginx 可以連到 Mealie,但網際網路無法連入。Docker 會自行將規則寫入 packet filter,因此即使防火牆表示該連接埠已關閉,單純使用 9925:9000 仍可能讓外部連線。這項差異值得了解一次:請參閱 為什麼已發布的 Docker 連接埠會忽略 ufw。
BASE_URL 必須是你實際使用的完整公開位址,包含 scheme,且結尾不得有斜線。Mealie 會以此建立密碼重設連結與邀請連結。若將它設為 http://localhost:9925,你傳給伴侶的邀請會包含只在伺服器本機有效的連結。
啟動服務,並監看第一次啟動過程。
sudo docker compose up -d
sudo docker compose logs -f mealie第一次啟動時會建立 SQLite 資料庫並執行 migrations,這需要幾秒鐘。日誌穩定下來且不再輸出 migration 行後,從本機檢查應用程式。
curl -I http://127.0.0.1:9925出現 200 OK 表示應用程式已啟動。出現 Connection refused 表示容器未執行:執行 sudo docker compose ps 並查看 exit code。若容器以 code 137 停止,表示因超過 1000M 的記憶體限制而遭終止;這種情況會發生在資源最小的方案上。
首次登入並關閉開放註冊
預設帳號是 changeme@example.com,密碼是 MyPassword。使用這組資訊登入後,立即變更帳號與密碼,因為這組組合已印在文件中,因此所有掃描器都知道。
compose 檔案中的 ALLOW_SIGNUP: "false" 是刻意如此設定的。開放註冊時,任何找到該位址的人都能在你的食譜庫中建立帳號。關閉註冊後,請從管理區域新增使用者;系統會產生邀請連結,再由你自行傳送給對方。該連結會根據 BASE_URL 建立,因此這個值很重要。如果你最後在同一台伺服器上執行多個應用程式,並希望所有應用程式共用一組密碼,Mealie 可以將登入交給外部身分識別提供者,例如 自行託管的 Authentik 執行個體。
Mealie 會將使用者分組到同一個家庭。相同家庭中的所有人會共用食譜收藏、用餐計畫與購物清單,這符合家庭的使用方式。同一台伺服器上的不同家庭則各自保有獨立收藏,適合合租者在沒有人同意加入鯷魚時使用。
匯入器,這就是執行這項操作的原因
開啟食譜集合,選擇從 URL 建立食譜,然後貼上連結。Mealie 會擷取頁面,並尋找結構化食譜資料,也就是多數食譜網站為搜尋引擎嵌入的機器可讀區塊。若存在該區塊,匯入會立即完成,內容也通常很準確。
您也可以從圖片或貼上的純文字匯入,適合處理食譜書頁面的照片。這些內容會經過較慢的處理流程,完成後需要檢查,因為手寫的分數很容易被誤判。
批次匯入也可在同一個畫面執行:每行貼上一個網址,Mealie 會在背景逐一處理。一次即可匯入包含 200 個書籤的集合。
膳食計畫與購物清單
膳食規劃器是一個行事曆。將食譜拖曳到某一天後,就會完成安排。接著,購物清單會收集已安排食譜中的食材,合併重複項目,讓兩份都需要洋蔥的食譜只產生一行,而不是兩行。
購物時,您可以在手機上開啟這份即時清單。由於清單儲存在您自己的伺服器上,家中所有人都能同時看到相同內容;其中一人勾選牛奶後,牛奶也會從其他人的畫面移除。
將 nginx 與 TLS 放在前端
Mealie 使用純 HTTP,且本身不處理憑證。在前端的 nginx 中終止傳輸層安全性(TLS)。先將 DNS A 記錄指向伺服器,因為憑證程序會驗證該網域名稱。
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 nginxnginx -t 輸出 syntax is ok 與 test is successful 是必要條件。只有通過後才能重新載入,因為重新載入錯誤的設定會讓舊設定繼續執行,直到下次重新啟動才會顯現問題。
加入 client_max_body_size 64M 是因為 nginx 的預設值為 1 MB。透過瀏覽器上傳食譜照片或還原備份時,請求本文可能超過此大小。若未加入該設定,nginx 會回傳 413 Request Entity Too Large,而不是由 Mealie 回傳,因此應用程式日誌完全不會顯示相關記錄。
接著申請憑證。該步驟及其續期計時器已在 使用 certbot 為 nginx 申請 Let's Encrypt 憑證 中說明。
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d recipes.example.comCertbot 會改寫 server block,使其監聽 443,並加入從 port 80 轉址的設定。透過 https:// 載入網站,確認瀏覽器接受該憑證。如果 Mealie 能載入,但其中的連結將你導向 http://,表示 BASE_URL 仍設定為 http。請修正該值,然後執行 sudo docker compose up -d,以新值重新建立容器。
Mealie 無法透過 example.com/recipes 這類子路徑提供服務,因為前端無法從子路徑提供內容。請改用子網域。
備份,以及還原實際執行的內容
Mealie 使用的所有資料都位於容器內的 /app/data/,也就是 mealie-data volume。複製這個 volume,就能一併複製食譜、圖片和資料庫。
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 mealievolume 名稱會以專案名稱作為前綴,而專案名稱就是存放 compose file 的目錄。從 /srv/mealie 可得知 volume 是 mealie_mealie-data,因此第一個指令是 docker volume ls:請使用該指令輸出的名稱,不要直接使用本指南中的名稱。先停止容器很重要,因為 SQLite 經常處於寫入狀態;直接複製可能導致還原後的資料無法讀取。
Mealie 也在管理區提供自己的備份頁面,可建立可攜式封存檔,將資料庫以 JSON 儲存,並一併包含圖片。若要在伺服器之間搬移,請使用此功能,因為即使版本變更仍可使用;直接複製原始檔案則不一定能做到。還原封存檔的設計本身具有破壞性:載入封存檔前會刪除目前的資料庫,而且無法復原。還原完成後,系統會將你登出。
備份檔放在同一台伺服器上時,兩種複本都不能算是備份。請依排程將封存檔推送到其他位置,這正是 使用 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提高檔案中的固定版本,然後執行 pull 並重新建立容器。新 image 第一次啟動時會執行資料庫遷移。進行主要版本變更前,請先複製 volume,因為遷移若中途失敗,會留下舊 image 無法再開啟的資料庫。請閱讀目前版本與新版本之間所有版本的發行說明。
匯入失敗時
有些網站完全不發布結構化食譜資料,因此 Mealie 只會匯入標題,食材清單則為空白。這不是能透過設定解決的問題。請改為手動貼上食譜文字。
其他失敗原因可能是食譜網站前方的機器人防護。該防護會回傳挑戰頁面給 Mealie,而不是食譜內容。Mealie 已經會模擬瀏覽器,並輪換 user agent,以降低觸發防護的機率。網站仍拒絕存取時,文件記載的選項包括:讓 scraper 透過 IP 信譽較佳的 proxy 傳送請求,或執行 FlareSolverr instance,使用真實瀏覽器解決挑戰。兩者都是選用功能,並且都透過容器上的 environment variables 設定。
如果匯入失敗是因為伺服器完全無法連線到該網站,則是另一個問題。請在該主機上使用 curl -I https://the-site.example/recipe 測試,先讀取狀態列,再判斷是否為 scraper 的問題。
適用情境
Mealie 很適合作為家庭第一個自架應用程式,因為同住的人不必特別要求就會使用它。它與執行 使用 Immich 建立自己的相片庫屬於相同類型的工作,但整體更輕量,也列在今年值得自架的服務之中。同一台小型伺服器即可同時執行兩者。第二項工作不一定要使用 Immich;如果你仍在選擇,PhotoPrism 與 Immich 的記憶體最低需求和備份指令差異足以讓你在用完其餘磁碟空間前先閱讀比較。
FAQ
為什麼匯入食譜 URL 會失敗?
常見原因有兩個。頁面可能沒有發布結構化食譜資料,因此 scraper 找不到內容,最後只取得標題而沒有食材;或者網站前方的 bot protection layer 回傳 challenge page,而不是食譜內容。遇到第二種情況時,可以讓 Mealie 使用位址信譽較佳的 proxy,或使用自行託管的 FlareSolverr instance,在真實瀏覽器中解決 challenge。變更設定前,先使用 curl -I 確認伺服器確實能連線到該頁面。
我需要 PostgreSQL,還是 SQLite 就足夠?
家用環境使用 SQLite 就足夠,SQLite 也是預設選項。當資料目錄位於 network attached storage 時,請改用 PostgreSQL,因為 SQLite 透過 network filesystem 使用時會產生資料庫鎖定錯誤,並可能損毀檔案。使用 PostgreSQL 還原時,資料庫使用者必須是 superuser,因為還原程序會先刪除所有內容,再載入 archive。
沒有網域名稱也能執行 Mealie 嗎?
可以,只要是在自己的網路中使用。將 BASE_URL 設為實際會輸入的位址,例如 http://192.168.1.20:9925,並略過 nginx。邀請連結與密碼重設連結都是根據 BASE_URL 建立,因此設定錯誤會產生其他人無法開啟的連結。請勿透過未加密的 HTTP 將服務暴露到網際網路,否則登入資訊會以明文傳送。
如何為家人建立各自的登入帳號?
保留 ALLOW_SIGNUP 的設定為 "false",再從管理區域新增使用者。系統會產生邀請連結,供你傳送給對方。共用廚房的所有人應加入同一個 household,這樣才能共用食譜、餐點計畫與購物清單。同一台伺服器上的不同 household 會各自保有獨立的內容集合。
停止執行 Mealie 後,我的食譜會怎樣?
食譜仍然可以取出。管理區域的備份功能會將資料寫成 JSON;Mealie 也能將食譜匯出為純文字 markdown 檔案,即使沒有任何軟體,也能使用文字編輯器讀取。請在真正需要之前先執行一次匯出,並確認檔案可以開啟。