New releases
Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.
Tandoor organizes household recipes with ingredients, cooking steps and images, plans meals on a calendar, and turns planned dishes into shared shopping lists. This recipe runs Tandoor with PostgreSQL, persistent media and regenerated static files; external AI and storage services are optional and unconfigured.
Tandoor is a household recipe library with ingredients, preparation steps, photographs, cookbooks, a meal calendar and shared shopping lists. It suits families who want to plan meals and reuse a common collection on their own server. It replaces parts of Paprika Recipe Manager, Recipe Keeper and AnyList; it does not bundle their paid apps or cloud services. Compared with Mealie, it offers another approach to recipe organization, meal planning and shopping, with a different license.
Tandoor is source-available, not OSI-approved open source. Its license is GNU AGPL v3 with the Commons Clause selling restriction. Personal and internal use are allowed, but the license does not grant the right to sell the software or services whose value derives substantially from it, including hosting and related consulting/support. Review the actual license before offering a service. The recipe files use MIT; the logo’s upstream notice and license are preserved in assets/NOTICE and assets/LICENSE.
This recipe uses the official Tandoor 2.7.2 image, PostgreSQL 18.6 and an Alpine 3.22.2 initialization/archive helper. The application includes Nginx and Gunicorn and runs as UID/GID 65534; initialization prepares only the media/static volume roots. The database and media are persistent, while static assets are regenerated from the pinned image at startup. External AI providers, storage integrations, social identity providers and SMTP are not configured.
The web interface supports English and Russian. The official related-project directory lists the third-party kitshn client for Android and iOS; it is not installed or tested here. There is no desktop client in this recipe. Untare is listed upstream as discontinued and is not the recommended mobile option.
Local username/password login uses the browser authentication API. Bundled django-allauth providers support OIDC and SAML, and a reverse-proxy user-header mode exists; the recipe leaves all three disabled. No embedded second factor is enabled in this build. Use a properly configured identity provider if you need MFA, and never enable remote-user authentication behind a proxy that accepts an identity header from a visitor.
The security assessment records warnings. The first visitor to /setup/ can create the owner, so bootstrap through loopback or an SSH tunnel before opening the proxy or LAN access. Ordinary signup is explicitly disabled. Permit trusted accounts, restrict server-side import access to sensitive internal services, protect the volumes and encrypt off-server backups.
Uploaded images are served by Nginx without per-file authorization. Marking a recipe private protects the recipe API, but does not make a known image URL private. Do not store sensitive photographs. Recipes, household membership, meal plans and integration credentials live in PostgreSQL and backups; the media archive and .env are equally sensitive.
Upstream 2.7.2 has a known setup redirect bug (#4907): revisiting /setup/ after the owner exists returns HTTP 500. Use /account/login/ for ordinary access. The recipe does not patch upstream authentication or treat that error as a successful protection check; the smoke test checks the actual closed-signup configuration instead.
The amd64 recovery scenario creates an owner through the native CSRF form, signs in, stores a private recipe with an ingredient, instructions, keyword and uploaded image, deletes all three volumes and verifies restored data and the stored image hash. arm64, meal-plan timing, shopping synchronization, URL imports, identity providers, mail, AI and mobile clients remain untested. Five CRITICAL package findings across the pinned images remain visible in the security snapshot.
Allow at least 1 CPU, 1 GiB RAM and 5 GiB disk; 2 GiB RAM gives more room for PostgreSQL and two Gunicorn workers. These are deployment estimates, not a load-test guarantee. Home and VPS deployment are supported after safe bootstrap; the reliable level remains partial because external monitoring, resource limits and backup scheduling are operator tasks.
Sources: Docker installation, configuration, authentication, SAML provider, and 2.7.2 release notes.
These are stored results of separate checks, not real-time data. An unknown status means the check has not been performed yet.
Recipe version compared with the latest known upstream release. A version number, not a reading of what changed.
Result of a dedicated Docker image scan, not a Compose configuration check.
A new major version is found by comparing version numbers. A compatibility verdict is entered by hand after reading the release notes and the migration steps.
Upstream Compose changes relative to the verified recipe.
Pinned image tags checked for newer versions.
From observation to action
The recipe already pins the latest known release. The steps below show the evidence retained for that version.
2.7.22.7.2Open this release on GitHub ↗ The link is evidence to review, not proof of compatibility.
The version numbers do not cross a major compatibility boundary. No compatibility verdict has been recorded.
No image-tag change is currently planned.
Change the tag and restart. Release-specific migration steps still come from the release notes and installation guide.
No version change is currently planned. The recipe includes a backup procedure. Restore has been tested.
An exact Fully verified check for this target was recorded on 2026-10-29.
The status shows how fully the published recipe meets each level's requirements.
A minimal setup for a local network or access through a VPN.
The recipe covers every requirement at this level.
A public deployment with protected access and backups.
The recipe covers every requirement at this level.
A setup designed for predictable operations and observability.
You still need to add: external monitoring, cpu and memory limits.
Tailored to your server
Answer five questions and download a ready-to-run Tandoor bundle.
Read the full guide first: it explains external access, backups, and data locations.
cp .env.example .envdocker compose up -ddocker compose psUse Ubuntu 24.04/26.04 LTS or Debian 12/13 with Docker Engine and Compose v2.24 or newer, installed from Docker’s instructions. Run commands in this recipe directory. Install openssl; Python 3 and curl are needed for the smoke test. Docker access grants administrative control of the host.
cp .env.example .env
chmod 600 .env
openssl rand -hex 32 # TANDOOR_SECRET_KEY
openssl rand -hex 24 # TANDOOR_DB_PASSWORD
Paste different generated values into .env. The web entrypoint rejects template secrets and a secret key shorter than 50 characters before starting HTTP. The owner password is created through the native setup form. Keep the port on loopback until that owner exists.
docker compose --env-file .env config --quiet
docker compose --env-file .env pull
docker compose --env-file .env up -d --wait --wait-timeout 600
docker compose ps --all
Leave the public proxy closed. Open a tunnel from your computer:
ssh -L 8089:127.0.0.1:8089 user@server
Visit http://localhost:8089/setup/ and create the owner with a unique password, then use http://localhost:8089/account/login/. Setup creates the initial space and a placeholder email address; configure SMTP before verifying a real address or relying on email password recovery. Public signup stays disabled. Do not revisit /setup/: upstream 2.7.2 has a known redirect error there after a user exists. Enable a firewall, operating-system updates and encrypted off-server backups before opening HTTPS.
Bootstrap over the tunnel first. Then replace 127.0.0.1 in the web port mapping with the server’s private address. Add that address to TANDOOR_ALLOWED_HOSTS, and set TANDOOR_CSRF_TRUSTED_ORIGINS to its exact origin, for example http://192.168.1.10:8089. Recreate the services and restrict access to trusted clients or a VPN. Plain HTTP still carries credentials and household data unencrypted.
Point recipes.example.com at the server. Keep the app on loopback, set TANDOOR_ALLOWED_HOSTS=localhost,127.0.0.1,recipes.example.com and TANDOOR_CSRF_TRUSTED_ORIGINS=https://recipes.example.com, then run docker compose up -d --wait --wait-timeout 600. Forward the original Host and X-Forwarded-Proto. Tandoor trusts the forwarded protocol header, so prevent untrusted direct access to that backend. Keep remote-user authentication disabled unless a trusted authenticating proxy strips all client-supplied identity headers.
proxy/Caddyfile obtains HTTPS certificates and routes the domain to loopback. proxy/nginx.conf needs your certificate paths; run nginx -t before reload. proxy/traefik.yaml is dynamic file-provider configuration for an existing Traefik installation with its certificate resolver. The examples assume a proxy on the Docker host. A containerized proxy needs a controlled shared network or reachable host address; its loopback refers to itself. No additional static/media proxy is needed: the official app image includes Nginx.
Three project-scoped volumes are created: database at /var/lib/postgresql, media at /opt/recipes/mediafiles, and static at /opt/recipes/staticfiles. PostgreSQL holds recipes, users, spaces, meal plans, shopping lists and integration settings. Images and user uploads live in media. Static assets are generated at each startup and are not user data. The initializer assigns the media/static roots to UID/GID 65534; the application runs without root. Do not change the UID or replace volume ownership blindly.
| Variable | Meaning |
|---|---|
TANDOOR_VERSION |
Pinned app version, 2.7.2. |
TANDOOR_PORT |
Loopback web port, 8089. |
TANDOOR_SECRET_KEY |
Random Django secret of at least 50 characters; preserve it with backups. |
TANDOOR_DB_PASSWORD |
Unique PostgreSQL password set before the first start; changing only .env does not alter the existing database role password. |
TANDOOR_ALLOWED_HOSTS |
Comma-separated hostnames/IPs without schemes or ports; include loopback for healthchecks. |
TANDOOR_CSRF_TRUSTED_ORIGINS |
Comma-separated exact origins including scheme and any nonstandard port; no wildcard. |
TZ |
IANA application timezone, UTC by default. |
Scripts additionally accept FOSSARY_ENV_FILE, COMPOSE_PROJECT_NAME and TANDOOR_BACKUP_DIR, defaulting to .env, project tandoor and backups/. If you launched with a custom docker compose -p, export that same COMPOSE_PROJECT_NAME for backup and restore. SMTP, AI, external storage and identity providers remain unconfigured; the recipe does not require their keys.
bash backup.sh
Wait for initialization first. The script stops the application, dumps PostgreSQL and archives the full media volume, .env and Compose. It restarts the app only if it was running. Archives use private permissions and unique filenames; encrypt an off-server copy and rehearse recovery. Recipe exports alone do not preserve accounts, meal plans, shopping lists or all settings. Static files are regenerated and excluded from the archive.
Use trusted archives and the matching app/database versions and secrets. On a fresh server, prepare the matching configuration without starting the application:
docker compose up -d --wait database
docker compose create --no-deps tandoor initialize
bash restore.sh /absolute/path/tandoor-<timestamp>.tar
The restore validates archive members, creates a safety backup, stops writers, recreates the application database, replaces media and waits for health. .env from the archive is not activated automatically. Verify login, recipe instructions, images, meal plans and shopping lists before reopening access. If restoration fails, keep writers stopped and inspect logs before retrying. A different server also needs corrected host/origin settings.
Read the release notes and configuration guide. Save the old .env, Compose and a verified backup, stop the app, select a reviewed pinned TANDOOR_VERSION, then restart:
bash backup.sh
docker compose stop tandoor
# Edit TANDOOR_VERSION in .env; keep the PostgreSQL major version unchanged.
docker compose pull tandoor
docker compose up -d --wait --wait-timeout 600
docker compose logs --tail=100 tandoor
Startup migrates PostgreSQL and rebuilds static assets. Check recipes, media, permissions, meal plans and shopping lists. PostgreSQL major upgrades require a separate export/import plan; never reuse a data directory with a different major image.
tandoor..env and Compose, preserving the matching secret and the database major version; set the old TANDOOR_VERSION.docker compose create --no-deps tandoor initialize. Keep the old app stopped over the newer schema.bash restore.sh /path/to/pre-upgrade.tar. The safety copy preserves the current state before the old database and media replace it; static assets are regenerated.docker compose down preserves the volumes. After verifying an external backup, docker compose down --volumes --remove-orphans destroys the database, all uploads and static assets. Remove .env and local backups separately when they are no longer needed.
Tell us how it went on your server
Opens a prefilled GitHub issue. A GitHub account is required; submitting the issue makes it public.
Start with docker compose ps --all, docker compose logs --tail=200 tandoor database initialize, docker compose --env-file .env config --quiet, and curl -i http://127.0.0.1:8089/accounts/login/. Keep secrets, session cookies and household data out of public reports.
TANDOOR_SECRET_KEY must be at least 50 characters. Preserve an existing key when recovering an established installation..env value or deliberately change the role password; deleting volumes destroys user data.TANDOOR_ALLOWED_HOSTS takes hostnames/IPs without scheme or port; TANDOOR_CSRF_TRUSTED_ORIGINS takes complete origins. Include the actual hostname, scheme and any nonstandard port, forward Host/protocol correctly, then recreate the app. Keep the backend reachable only through trusted paths./setup/ after creating the owner: this is upstream #4907, still present in 2.7.2. Use /account/login/; do not delete the database or repeat owner creation. The normal headless login and recipe API work independently of that old redirect.docker compose exec tandoor /opt/recipes/venv/bin/python manage.py changepassword <username>. It prompts interactively; keep the new password out of command history. Configure SMTP before relying on email verification/reset.References: Docker guide, configuration, authentication and upstream issues.
Fossary is an independent informational catalog and is not affiliated with the developers of the listed applications. We collect information from public sources and verify published recipes, but we do not develop, distribute, or control these applications.
A listing or validation status is not a requirement, endorsement, or personal recommendation to use an application. You decide whether it is suitable and use it at your own risk. We do not warrant an application's security, availability, or fitness for purpose and, to the extent permitted by law, are not liable for resulting loss or damage. Review its license, security settings, data processing, and backup procedures before installation.