How to Self-Host Tandoor Recipes with Docker

What Is Tandoor Recipes?

Tandoor Recipes is a self-hosted recipe manager built with Django and Vue.js. Import recipes from thousands of websites with a single click, organize them into cookbooks, plan meals on a weekly calendar, and generate shopping lists. It supports multiple users with a permission system, full-text search with trigram similarity, and AI-powered features for image recognition and nutrition lookup. Tandoor replaces Paprika, AnyList, and ad-heavy recipe sites where you scroll past three life stories to find the ingredients.

Prerequisites

  • A Linux server (Ubuntu 22.04+ recommended)
  • Docker and Docker Compose installed (guide)
  • 1 GB of free RAM (2 GB recommended for AI features)
  • 2 GB of free disk space (plus storage for recipe images)
  • A domain name (optional, for remote access)

Docker Compose Configuration

Create a directory for Tandoor and a docker-compose.yml file:

services:
  tandoor:
    image: vabene1111/recipes:2.5.3
    container_name: tandoor
    restart: unless-stopped
    ports:
      - "8080:8080"
    env_file:
      - .env
    volumes:
      - tandoor_static:/opt/recipes/staticfiles
      - tandoor_media:/opt/recipes/mediafiles
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    container_name: tandoor-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: tandoor
      POSTGRES_USER: tandoor
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - tandoor_db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U tandoor"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  tandoor_static:
  tandoor_media:
  tandoor_db:

Create a .env file alongside the Compose file:

# Generate a random secret key — required
# Run: base64 /dev/urandom | head -c50
SECRET_KEY=CHANGE_ME_TO_A_RANDOM_STRING

# Timezone — see https://timezonedb.com/time-zones
TZ=America/New_York

# Database connection — must match the db service above
DB_ENGINE=django.db.backends.postgresql
POSTGRES_HOST=db
POSTGRES_DB=tandoor
POSTGRES_PORT=5432
POSTGRES_USER=tandoor
POSTGRES_PASSWORD=CHANGE_ME_TO_A_STRONG_PASSWORD

# Allowed hosts — set to your domain or * for all
# ALLOWED_HOSTS=recipes.yourdomain.com

# Enable signup for additional users (disable after creating accounts)
ENABLE_SIGNUP=1

Start the stack:

docker compose up -d

Initial Setup

Once the containers are running, open http://your-server-ip:8080 in your browser.

  1. Click Register to create your admin account
  2. Set your preferred language and timezone in the settings
  3. Disable ENABLE_SIGNUP=0 in your .env file after creating all accounts, then restart: docker compose restart tandoor

The default superuser is the first account created. Additional users can be invited with configurable permissions — viewer, guest, or full editor access.

Configuration

Key Environment Variables

VariableDefaultDescription
SECRET_KEYRequired. Django secret key for session encryption
TZEurope/BerlinServer timezone
ALLOWED_HOSTS*Comma-separated hostnames allowed to connect
ENABLE_SIGNUP0Allow new user registration
FRACTION_PREF_DEFAULT0Show fractions (1) or decimals (0) in ingredients
COMMENT_PREF_DEFAULT1Enable recipe comments
SHOPPING_MIN_AUTOSYNC_INTERVAL5Minimum seconds between shopping list syncs
TANDOOR_PORT8080Internal web server port
GUNICORN_WORKERS3Number of application workers
GUNICORN_THREADS2Threads per worker

Importing Recipes

Tandoor imports recipes from any site using schema.org Recipe markup (ld+json or microdata). Three methods:

  • URL import: Paste a recipe URL and Tandoor scrapes the structured data — title, ingredients, instructions, image, nutrition info, and prep/cook times.
  • Bulk import: Paste multiple URLs (one per line) for batch import.
  • File import: Upload exports from Mealie, Nextcloud Cookbook, Paprika, Chowdown, Pepperplate, and other managers.

Meal Planning

The meal planning view shows a weekly calendar. Drag recipes onto days, assign meal types (breakfast, lunch, dinner, snack), and share meal plans with your household. Plans automatically feed into shopping list generation.

Shopping Lists

Generate shopping lists from individual recipes or entire meal plans. Tandoor merges duplicate ingredients, groups items by supermarket aisle (configurable), and syncs lists across devices in real time. Multiple household members can check off items simultaneously.

Reverse Proxy

For remote access with HTTPS, place Tandoor behind a reverse proxy. Add your domain to ALLOWED_HOSTS in the .env file.

Nginx Proxy Manager config:

  • Scheme: http
  • Forward Hostname: tandoor (or your container name)
  • Forward Port: 8080
  • Enable SSL with Let’s Encrypt

See Reverse Proxy Setup for full configuration.

Backup

Back up these volumes:

  • tandoor_db — PostgreSQL database (all recipes, users, meal plans, shopping lists)
  • tandoor_media — uploaded recipe images and files
  • tandoor_static — static assets (regenerated on startup, but good to include)

Database dump approach:

docker exec tandoor-db pg_dump -U tandoor tandoor > tandoor_backup.sql

See Backup Strategy for automated backup workflows.

Troubleshooting

Recipes not importing from certain sites

Symptom: URL import returns empty or partial data. Fix: The target site may not use schema.org Recipe markup, or it may load content via JavaScript. Try the bookmarklet (available in Tandoor’s settings) which runs in your browser and captures the rendered page. Some sites block server-side scraping but work fine with the bookmarklet.

Static files not loading (broken CSS/JS)

Symptom: Page loads but looks unstyled, browser console shows 404 for static files. Fix: The staticfiles volume may not have been populated. Run:

docker compose exec tandoor python manage.py collectstatic --noinput
docker compose restart tandoor

Database connection refused on startup

Symptom: Tandoor container exits with “could not connect to server” errors. Fix: The database takes a few seconds to initialize. The depends_on with health check in the Compose file handles this, but if you removed it, add it back. Alternatively, restart Tandoor after the database is ready:

docker compose restart tandoor

Search returns no results

Symptom: Full-text search finds nothing despite having recipes. Fix: Tandoor uses PostgreSQL trigram similarity for search. Rebuild the search index:

docker compose exec tandoor python manage.py rebuild_index

Resource Requirements

  • RAM: ~300 MB idle, ~500 MB under load with multiple users
  • CPU: Low — Django is not compute-intensive for typical usage
  • Disk: ~500 MB for the application, plus storage for recipe images (varies by collection size)

Verdict

Tandoor is the most feature-complete self-hosted recipe manager available. The meal planning and shopping list integration puts it ahead of simpler alternatives. Import support for thousands of recipe sites means you can migrate your entire collection in an afternoon. The UI is polished and mobile-friendly. For anyone serious about managing recipes, Tandoor is the clear first choice. If you want something lighter with less setup, Mealie is a good alternative — but Tandoor’s depth is hard to beat.

Comments