Journal indexDockup / field note
Note / self-host-mealie

How to Self-Host Mealie in 2026: Recipe Imports, Users and Backups

A practical Mealie self-hosting guide covering Docker, ports, persistent data, TLS, security, backups and the failures that block production use. Step by step.

The shortest Mealie demo proves that a process listens on port 9000. Production needs stronger evidence. It must pass this scenario even after the container has been replaced: import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes.

Mealie is being deployed for a clear purpose: recipes, meal plans and shopping lists. Its most common deployment trap is that recipe images vanish because /app/data is not persistent, so public URL handling and durable state receive the same attention as image startup.

Draw the Mealie runtime boundary

The smallest responsible Mealie topology contains one private listener on 9000, an ingress route and a documented state boundary. The network contract for Mealie is Postgres for a multi-user production deployment and SMTP for invitations. Keep private endpoints on internal DNS, permit only required outbound calls and give Mealie a scoped service credential.

Validate the topology by asking a clean client to import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes. Watch recipe imports, image storage, database queries, background tasks and simultaneous household users while it runs. The result tells you whether the next improvement belongs in memory, storage, networking or a separate worker instead of encouraging arbitrary container sizing.

Capacity and upgrade checks

An idle health check says little about Mealie. Watch recipe imports, image storage, database queries, background tasks and simultaneous household users, then alert on the symptom users experience: failure of the action “import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes”. Keep liveness local and cheap; let readiness report migrations or initialization without causing a restart storm.

The risky upgrade area is that database migrations and ingredient-parser changes can affect stored recipes, so test imports and existing records. Read release notes, snapshot state, deploy the target version against a restored copy and repeat the acceptance action. If recipe images vanish because /app/data is not persistent, correlate the client request with the first relevant application log rather than deleting state or adding redirects blindly.

The Mealie release gate

A release candidate for Mealie earns traffic by completing a fixed scenario: import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes. Capture the image digest, effective non-secret configuration, public origin and timestamps for that scenario. The test data should be disposable but realistic enough to exercise the same path as users.

Run it after replacing the runtime, then rebuild the service from database, recipe images, assets and application settings. Recovery passes when recipes, images, users, meal plans and shopping lists return and a known recipe renders correctly. Compare resource measurements for recipe imports, image storage, database queries, background tasks and simultaneous household users with the prior release and investigate meaningful drift before promotion.

Finally, exercise this controlled failure: temporarily deny the test identity access to Postgres for a multi-user production deployment and SMTP for invitations. Verify that Mealie explains the failure, does not damage existing state and resumes after the valid condition returns. Save a redacted log excerpt and the recovery time. Together these checks cover behavior, durability and operability rather than just process uptime.

Build a replaceable Mealie container

Keep the initial Mealie invocation reproducible enough to review in a pull request.

docker run -d \
  --name mealie \
  --restart unless-stopped \
  -p 127.0.0.1:9000:9000 \
  -v mealie-data:/app/data \
  -e BASE_URL=https://app.example.com \
  ghcr.io/mealie-recipes/mealie:latest

Do not rely on latest after real data exists. Capture the working digest, container user and mount ownership. Follow the application log through a complete test — import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes — and note any migrations before putting the route behind production traffic.

Find every durable byte in Mealie

Inventory every durable artifact: database, recipe images, assets and application settings. Mount /app/data before bootstrap, write harmless sample data and replace the container to prove that path is actually persistent. Include configuration that changes how stored data is interpreted, not only the largest directory.

Set retention, copy backups off-host and run a clean-room restore. The Mealie drill is complete when recipes, images, users, meal plans and shopping lists return and a known recipe renders correctly. If snapshots are part of the plan, use PITR versus snapshot guidance to document what each mechanism can recover.

Route Mealie without lying about HTTPS

Set BASE_URL to the external HTTPS origin. Send the chosen hostname to container port 9000, forward the original host and HTTPS scheme, and avoid publishing a second direct origin.

Test Mealie from a clean external client. Separate ingress failure from the known application boundary — recipe images vanish because /app/data is not persistent. A certificate, DNS or 502 error belongs to routing; a request that reaches Mealie and fails later belongs to application state, capacity or its supporting requirement. The custom-domain TLS guide covers the first group.

Reduce the authority held by Mealie

After first login, review what an anonymous visitor, ordinary user and administrator can each do. The Mealie failure to avoid is leaving sign-up open or keeping the first admin password unchanged. The intended policy is to replace the first admin password, close sign-up when enrollment ends and protect private household data.

BASE_URL is configuration rather than a secret; keep its value explicit while protecting the separate credentials used by Mealie. Keep dependency accounts separate from human accounts, deny unused egress where practical and cap work influenced by recipe imports, image storage, database queries, background tasks and simultaneous household users.

A Dockup deployment still needs an Mealie acceptance test

Routing, certificates, service replacement and attached storage are reasonable automation targets. Dockup handles those for Mealie and can provision the related managed database or connect to services on a customer's own server.

What it should not invent is the Mealie trust policy. After deployment, set BASE_URL to the external HTTPS origin, enforce this boundary — replace the first admin password, close sign-up when enrollment ends and protect private household data — and verify the result of this scenario: import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes. The outcome is one-click infrastructure with an application-specific acceptance test.

Frequently asked questions

What does Mealie need for a production deployment?

Route the Mealie container on port 9000 through one HTTPS origin. The supporting network requirement is Postgres for a multi-user production deployment and SMTP for invitations. Do not call Mealie ready until you can import a recipe URL, verify its image, add it to a meal plan and generate a shopping list from several recipes.

Which Mealie data belongs in a backup?

Persist /app/data and include database, recipe images, assets and application settings in the same recovery manifest. A clean Mealie restore passes only when recipes, images, users, meal plans and shopping lists return and a known recipe renders correctly.

Does Mealie require HTTPS behind a reverse proxy?

Use HTTPS for the public Mealie origin and keep port 9000 on the internal route. Apply the Mealie setting correctly: set BASE_URL to the external HTTPS origin. For Mealie, HTTPS protects credentials or user content in transit and keeps origin-sensitive client behavior consistent.

How should a Mealie upgrade be tested?

Restore current Mealie state into an isolated deployment, apply the candidate version and repeat its acceptance transaction. Pay particular attention because database migrations and ingredient-parser changes can affect stored recipes, so test imports and existing records. Keep the previous Mealie image until its data-migration and rollback boundary are understood.