Workload · Running a family recipe book

Self-hosted Mealie: your recipes and meal plans on a server you control

To self-host Mealie, you run its official Docker image on a Linux server, keep it private until you have replaced the built-in admin password, then give it a web address of its own. Here is how to do that in an evening, and how to keep your recipes safe afterwards.

The short version
  1. Recipes, meal plans and shopping lists for the whole household
  2. One Docker container, with SQLite storing everything
  3. Private on 127.0.0.1 until the default password is changed
  4. Backup zips you download from the admin page
  5. AI recipe imports only if you switch them on

What you are setting up

Mealie keeps your recipes, plans your week's meals and turns the plan into a shopping list. You can paste a link to a recipe page and Mealie pulls in the ingredients and steps, or type in your grandmother's card by hand. Everyone in the house gets their own login.

Under the hood it is a single Docker container. Its built-in database is SQLite, a database that lives in one file, and the docs call it ideal for 1 to 20 users when not many of them save changes at the same moment. That describes almost every family, so this guide uses it. If you later need many people editing at once, or the fuzzy search that only PostgreSQL offers, Mealie's own backup and restore lets you move across.

The server that fits

Mealie is one small job, which is what the compact cartridge servers on our dedicated server page are for: a whole machine for one service, with all of its cores, memory and disks yours. The Docker image is built for 64-bit Intel and AMD processors and 64-bit ARM; 32-bit ARM is not supported. Pick one of the x86 cartridges, not the ARM one: that cartridge can only be given Ubuntu 16.04 or 18.04, which are too old for current Docker.

A few things make a beginner's first evening easier here. You can wipe and reinstall the operating system yourself in the control panel, again and again, so a wrong first attempt costs nothing. On rack servers and blades, and on two cartridge models (m510 and m710x), there is a console with the screen and the power button, which still works if a firewall mistake locks you out of SSH. The port is unmetered, so recipe photos going back and forth never show up on the invoice. One thing to know up front. You manage the server; we keep the hardware and the network running. If Mealie will share the box with other things you host, such as a Joplin sync server or Paperless-ngx, pick one of the everyday single-processor servers instead.

Up and running in an evening

  1. Reinstall the server with Ubuntu or Debian, then put Docker on it: the Docker Engine, at release 28 at least, plus the Compose plugin. Version 28 matters for one reason: from that release, a port you bind to 127.0.0.1 really is reachable only from the server itself.
  2. Switch on the firewall, allowing SSH only. The first code block sets IPV6=yes before adding the rule, so the rule covers IPv6 as well, and uses --force so pasting the next line cannot answer the confirmation prompt by accident.
  3. Create a folder for Mealie and an empty mealie.env file that only root can read (mode 600). It is where any password Mealie needs goes, such as your email login.
  4. Save the compose file from the second block as docker-compose.yaml in that folder. Put the newest release from the project's README in place of the version tag, your time zone in TZ, and your future address in BASE_URL.
  5. Start it and confirm it is listening on 127.0.0.1 only, as the last two lines of the first block show.
# on the server, as root
apt-get install -y ufw
sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw
ufw allow OpenSSH
ufw --force enable
mkdir -p /opt/mealie && cd /opt/mealie
install -m 600 /dev/null mealie.env
nano docker-compose.yaml        # paste the file below, then save
docker compose up -d
ss -ltnp | grep 9925            # should show 127.0.0.1:9925 and nothing else
services:
  mealie:
    image: ghcr.io/mealie-recipes/mealie:v3.29.0
    container_name: mealie
    restart: always
    ports:
      - "127.0.0.1:9925:9000"
    deploy:
      resources:
        limits:
          memory: 1000M
    volumes:
      - mealie-data:/app/data/
    env_file: mealie.env
    environment:
      ALLOW_SIGNUP: "false"
      PUID: 1000
      PGID: 1000
      TZ: Europe/London
      BASE_URL: https://recipes.example.com

volumes:
  mealie-data:

The official file publishes 9925:9000 with no address, which opens the port on every address the server has, IPv4 and IPv6. Docker's own rules let that IPv4 traffic past ufw, and the IPv6 traffic too when Docker's IPv6 networking is switched on (otherwise ufw does filter IPv6). Adding 127.0.0.1: in front keeps Mealie private while you set it up. The memory limit comes straight from the docs, which recommend one so Python does not hold on to more memory than it needs.

Will anyone else be able to sign in?

Not if you follow this order. Every new Mealie starts with the same admin login, published in its docs: changeme@example.com and MyPassword. That is why the port stays on 127.0.0.1 until you have changed it. From your own computer, open a private tunnel that logs in as you, not as a service account: ssh -N -L 8080:127.0.0.1:9925 you@your-server. Leave that window open and browse to http://localhost:8080.

Sign in with the default details. Mealie then walks you through a short setup where you enter your name, email and a password of your own. Skipped it? Then update your email and password on your profile page right away. Afterwards, /admin/site-settings shows whether your configuration checks out.

Leave ALLOW_SIGNUP set to "false", which has been the default since v1.4.0, so strangers cannot create accounts. Invite your family instead: a user with the Invite permission can generate invitation links, or you add people under /admin/manage/users. Recipes stay private to logged-in users unless you open up the group, open up the household and switch on its option to show recipes to people outside your group, and mark the recipe public. The one exception is sharing: the Share button on a recipe creates a private link, and whoever has it can open that recipe without logging in.

Giving it a proper web address

Point a name such as recipes.example.com at the server, then run a web server on the server itself that handles HTTPS and passes visitors to 127.0.0.1:9925. Caddy is a gentle first choice because it fetches the certificate for you, and our Nginx Proxy Manager guide shows a point-and-click option. Mealie needs the whole name to itself; its FAQ says it cannot run under a path like /recipes.

That web server is a normal program on the host, so the firewall blocks it until you allow it: type ufw allow 80,443/tcp to let web visitors in, and until then nobody can reach the site. Thanks to the earlier setting, IPv6 visitors get through as well. Make sure BASE_URL matches the address you chose; Mealie uses it for its notifications.

Email is optional. It only sends invitations and password resets. To use it, add SMTP_HOST, SMTP_PORT (587 unless your provider says otherwise), SMTP_FROM_EMAIL, SMTP_USER and SMTP_PASSWORD to mealie.env, one NAME=value per line. Wrap the password in single quotes, as in SMTP_PASSWORD='your password', so Compose takes characters like $ and # literally. Then restart with docker compose up -d. The FAQ warns that some large mail services no longer accept plain SMTP logins and suggests an SMTP relay in that case.

Do you want the AI features?

Only if they are worth it to you; Mealie works fully without them. Once you set an AI provider in your group settings, it can tidy up ingredient lists, read a recipe from a page its normal importer cannot parse, and build a recipe from pasted text, a photo of a recipe card or a cooking video. Photos need a model that understands images, and videos need one that transcribes audio.

Any service that speaks the OpenAI API works. You can use an OpenAI API key, or point Mealie at a model you run yourself, such as Ollama, and the docs explain both. Keep in mind that whatever you import through AI is sent to the provider you picked.

Keeping your recipes safe

Older wording in the FAQ talks about automatic daily backups, but current releases schedule none: a backup exists only when you make one. Go to Admin Settings, then Backups, and create one. Each backup is a single zip with your whole site in it, and you can download it straight to your computer, which is exactly where the docs want it: somewhere other than the server. Make one before every update and on a regular schedule you will actually keep. The same page uploads and restores a backup, but restoring deletes everything currently in Mealie, cannot be undone and signs you out, so be sure first.

With SQLite, every recipe, photo and setting lives in the /app/data folder, and the docs call stopping Mealie and copying that folder the best way to back up. The third block does that, with Mealie offline only while the archive is written; copy the archive off the server with scp or rsync afterwards. Its second half puts an archive back: put your own archive's name in ARCHIVE first, and the line that follows stops Mealie, empties the volume, unpacks and starts it again only if that file exists. Restore only onto the same Mealie version the archive came from. The paths assume your folder is called mealie, which makes the volume mealie_mealie-data; docker volume ls and docker volume inspect show the real name and location.

# on the server, as root
cd /opt/mealie
docker volume inspect mealie_mealie-data     # check the Mountpoint

# make an archive
docker compose stop
tar -czf /root/mealie-data-$(date +%F).tar.gz -C /var/lib/docker/volumes/mealie_mealie-data/_data .
docker compose start

# restore one (same Mealie version only); this replaces what is there now
ARCHIVE=/root/mealie-data-YYYY-MM-DD.tar.gz      # your archive's name
test -f "$ARCHIVE" && docker compose stop && find /var/lib/docker/volumes/mealie_mealie-data/_data -mindepth 1 -delete && tar -xzf "$ARCHIVE" -C /var/lib/docker/volumes/mealie_mealie-data/_data && docker compose start

Updating without surprises

Mealie's team asks you to read the release notes before every upgrade, and to pin a version number rather than using latest, so updates happen when you choose. Download a fresh backup, then run docker compose down, change the version in your compose file, and run docker compose pull followed by docker compose up -d.

Mealie is free software under the AGPL-3.0 licence. Here is how we read it in general terms, which is not legal advice: using it as it comes, or running a changed copy that nobody but you uses, asks nothing of you. If you give copies to anyone else, changed or unchanged, the source has to go with them. And if you change the code and other people use your version over a network, you have to offer them that source.

When a whole server is more than you need

Be honest about the size of the job. A recipe book for one family is light work, and a whole machine makes the most sense when Mealie lives alongside other services you host, or when you simply want your household's data on hardware nobody else uses. There is also only one Mealie and one database, so your safety net is the backups you keep elsewhere, not a second server.

Questions people ask

What username and password does a new Mealie use?
According to the current installation checklist, a new install signs in with changeme@example.com and MyPassword. Earlier versions used a different username. Change both the first time you sign in, while Mealie is reachable only through your SSH tunnel.
Can I run Mealie without Docker?
The FAQ says you can, but recommends against it, because keeping Python, Node and npm versions in line by hand is painful and upgrades in that setup are unsupported. Docker is the route the project documents and the one this guide follows.
Is SQLite good enough for my family?
Very likely. The docs describe SQLite as the ideal choice for 1 to 20 users when concurrent edits are limited. Its one real limit for home use is network storage: keep the data on the server's own disks, because the docs warn SQLite on network-attached storage can corrupt or lock.
Do I have to pay for an AI service to use Mealie?
No. Every core feature works with no AI provider at all. The AI imports and the AI ingredient parser need one, and you can use any OpenAI-compatible service, including a model you host yourself.
How do I add my partner and kids?
Keep public sign-up off and send each person an invitation link, which any user with the Invite permission can generate. As the admin you can also create and manage accounts under Settings, Admin Settings, Users.
Where are Mealie's backups kept?
Inside the container's /app/data/backups folder, on the server's disks. That is not safe on its own, so download each zip from the Backups page, or copy the archive from the steps above to another computer.

Get a server for your family's recipes

Choose a compact x86 server and put Ubuntu or Debian on it; once it is handed over, you can have your own Mealie running in an evening.

Find your server

Read next