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.
- Click Register to create your admin account
- Set your preferred language and timezone in the settings
- Disable
ENABLE_SIGNUP=0in your.envfile 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
| Variable | Default | Description |
|---|---|---|
SECRET_KEY | — | Required. Django secret key for session encryption |
TZ | Europe/Berlin | Server timezone |
ALLOWED_HOSTS | * | Comma-separated hostnames allowed to connect |
ENABLE_SIGNUP | 0 | Allow new user registration |
FRACTION_PREF_DEFAULT | 0 | Show fractions (1) or decimals (0) in ingredients |
COMMENT_PREF_DEFAULT | 1 | Enable recipe comments |
SHOPPING_MIN_AUTOSYNC_INTERVAL | 5 | Minimum seconds between shopping list syncs |
TANDOOR_PORT | 8080 | Internal web server port |
GUNICORN_WORKERS | 3 | Number of application workers |
GUNICORN_THREADS | 2 | Threads 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 filestandoor_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.
Related
- Tandoor vs Grocy: Recipe Manager vs Kitchen Inventory
- Tandoor vs KitchenOwl: Which Should You Self-Host?
- Mealie vs Tandoor — side-by-side comparison
- How to Self-Host Mealie — simpler recipe manager
- Best Self-Hosted Recipe Managers — full category roundup
- Docker Compose Basics — prerequisite guide
- Reverse Proxy Setup — remote access configuration
- Backup Strategy — protect your data
- Replace Google Recipes — migration from cloud services
- Self-Hosted Alternatives to Yummly
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments