Quick start
Prerequisites
Install Docker Engine with Compose v2 (Docker Desktop on Windows/macOS). Windows users can run the shell scripts from WSL.
Configure and start
git clone https://github.com/DialmasterOrg/Youtarr.git
cd Youtarr
cp .env.example .env
# Edit .env and set YOUTUBE_OUTPUT_DIR=./downloads (or an absolute host path)
mkdir -p downloads config jobs server/images database
# Standard bundled database
docker compose -f docker-compose.yml up -d
# ARM/NAS or Docker Desktop safer named-volume database
docker compose -f docker-compose.yml -f docker-compose.arm.yml up -d
# External MariaDB/MySQL (DB_HOST, DB_USER, DB_PASSWORD are required)
docker compose -f docker-compose.external-db.yml up -d
The ARM compose file is an override and must be layered with the base file. The external database file is standalone and must be used by itself so it does not start the bundled database. Development is a separate source-built alternative; follow the Development Guide for the required client build and startup sequence. For external DB, set DB_HOST, DB_USER, DB_PASSWORD, and optionally DB_PORT/DB_NAME in .env.
Verify, open, and stop
Run the matching docker compose ... ps, then open http://localhost:3087. Complete the setup-token wizard on first access, or inspect matching docker compose ... logs -f youtarr output. Stop the selected project with the same file flags and down (for example, docker compose -f docker-compose.yml down).
On Windows, use Docker Desktop Compose commands above or run the referenced shell scripts under WSL. Generation only references scripts; it never executes them.
Base compose (required)
# IMPORTANT NOTES:
# 1) UID/GID and folder setup:
# By default, the youtarr service runs as ROOT (UID 0, GID 0) for compatibility with existing setups.
# For improved security, you can set YOUTARR_UID and YOUTARR_GID environment variables to run the container as a non-root user.
# If you do so, ensure that the following directories exist on the host with the correct ownership/permissions before
# starting the container:
# - ./config
# - ./jobs
# - ./server/images
# - <YOUTUBE_OUTPUT_DIR> (as specified in environment variable)
# Docker will create these directories as ROOT if they do not exist!
#
# To create and set ownership/permissions, you can use the following commands:
# Example (using example YOUTUBE_OUTPUT_DIR of /path/to/youtube_videos and YOUTARR_UID/GID of 1000/1000):
# mkdir -p config jobs server/images /path/to/youtube_videos
# sudo chown -R 1000:1000 config jobs server/images /path/to/youtube_videos
#
# 2) Database setup notes:
# The default bundled MariaDB uses ./database as a bind mount for backwards compatibility.
# On Docker Desktop (Windows/macOS), ARM hosts, and some NAS/virtualized filesystems,
# bind-mounted MariaDB data can become corrupted during schema migrations. For a safer named
# volume, use docker-compose.arm.yml or run ./scripts/migrate-to-named-volume.sh
# for an existing bind-mounted install.
services:
youtarr-db:
image: mariadb:10.3
container_name: youtarr-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-123qweasd}
MYSQL_DATABASE: ${DB_NAME:-youtarr}
MYSQL_TCP_PORT: ${DB_PORT:-3321}
# Set utf8mb4 as default for new installations
# Only set MYSQL_USER / MYSQL_PASSWORD if you configure a non-root DB_USER user in .env
# MYSQL_USER: ${DB_USER}
# MYSQL_PASSWORD: ${DB_PASSWORD}
MYSQL_CHARSET: utf8mb4
MYSQL_COLLATION: utf8mb4_unicode_ci
volumes:
- ./database:/var/lib/mysql
command: --port=${DB_PORT:-3321} --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --innodb-file-per-table=1 --innodb-large-prefix=ON
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-P", "${DB_PORT:-3321}", "-u", "${DB_USER:-root}", "-p${DB_PASSWORD:-123qweasd}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
youtarr:
image: ${YOUTARR_IMAGE:-dialmaster/youtarr:latest}
container_name: youtarr
restart: unless-stopped
# Optional: Run as specific UID:GID for security (defaults to root if not set for backwards compatibility with existing users)
user: "${YOUTARR_UID:-0}:${YOUTARR_GID:-0}"
depends_on:
youtarr-db:
condition: service_healthy
environment:
# DEPRECATED but retained for backwards compatibility with old images for now
IN_DOCKER_CONTAINER: 1
TZ: ${TZ:-UTC}
DB_HOST: ${DB_HOST:-youtarr-db}
DB_PORT: ${DB_PORT:-3321}
DB_USER: ${DB_USER:-root}
DB_PASSWORD: ${DB_PASSWORD:-123qweasd}
DB_NAME: ${DB_NAME:-youtarr}
# Optional: Disable authentication (for platforms with external auth like Elfhosted)
AUTH_ENABLED: ${AUTH_ENABLED:-}
# Optional: Seed initial admin credentials for headless deployments
AUTH_PRESET_USERNAME: ${AUTH_PRESET_USERNAME:-}
AUTH_PRESET_PASSWORD: ${AUTH_PRESET_PASSWORD:-}
# Optional: Configure Express proxy header trust
TRUST_PROXY: ${TRUST_PROXY:-}
# Optional external cookies; /app/config uses the existing mount (see docs/CONFIG.md).
YOUTARR_COOKIES_FILE: ${YOUTARR_COOKIES_FILE:-}
# Logging configuration
LOG_LEVEL: ${LOG_LEVEL:-info}
# Optional: rolling log files in config/logs (defaults: 10MB per file, 5 older files kept)
LOG_FILE_MAX_SIZE: ${LOG_FILE_MAX_SIZE:-}
LOG_FILE_MAX_COUNT: ${LOG_FILE_MAX_COUNT:-}
# This is just informational and lets the app know where the videos will be stored on the host
YOUTUBE_OUTPUT_DIR: ${YOUTUBE_OUTPUT_DIR}
# Optional: Custom data path for platforms like Elfhosted (defaults to /usr/src/app/data)
# This is the internal path where videos are downloaded inside the container and is not needed for most users
# DATA_PATH: /storage/rclone/storagebox/youtube
ports:
- "${YOUTARR_HOST_PORT:-3087}:3011"
volumes:
- ${YOUTUBE_OUTPUT_DIR}:/usr/src/app/data
- ./server/images:/app/server/images
- ./config:/app/config
- ./jobs:/app/jobs
healthcheck:
test: ["CMD", "curl", "--fail", "--silent", "--show-error", "--output", "/dev/null", "http://localhost:3011/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
default:
name: youtarr-network
# Named volume definition (used by docker-compose.arm.yml override)
volumes:
youtarr-db-data:
ARM/NAS override (use with base)
# Named-volume database override.
# The filename is historical: it was originally added for ARM systems, but it is
# also useful on Docker Desktop and NAS/virtualized filesystems where bind-mounted
# MariaDB data can corrupt during schema migrations.
services:
youtarr-db:
volumes:
- youtarr-db-data:/var/lib/mysql
volumes:
youtarr-db-data:
External database compose (standalone)
# IMPORTANT NOTES:
# By default, the youtarr service runs as ROOT (UID 0, GID 0) for compatibility with existing setups.
# For improved security, you can set YOUTARR_UID and YOUTARR_GID environment variables to run the container as a non-root user.
# If you do so, ensure that the following directories exist on the host with the correct ownership/permissions before
# starting the container:
# - ./config
# - ./jobs
# - ./server/images
# - <YOUTUBE_OUTPUT_DIR> (as specified in environment variable)
# Docker will create these directories as ROOT if they do not exist!
#
# To create and set ownership/permissions, you can use the following commands:
# Example (using example YOUTUBE_OUTPUT_DIR of /path/to/youtube_videos and YOUTARR_UID/GID of 1000/1000):
# mkdir -p config jobs server/images /path/to/youtube_videos
# sudo chown -R 1000:1000 config jobs server/images /path/to/youtube_videos
services:
youtarr:
image: ${YOUTARR_IMAGE:-dialmaster/youtarr:latest}
container_name: youtarr
restart: unless-stopped
# Optional: Run as specific UID:GID for security (defaults to root if not set per previous behavior)
user: "${YOUTARR_UID:-0}:${YOUTARR_GID:-0}"
# Add extra_hosts for connecting to external DB on host
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
# DEPRECATED but retained for backwards compatibility with old images for now
IN_DOCKER_CONTAINER: 1
# Override DB connection settings for external database
# Enforced for external DB usage
TZ: ${TZ:-UTC}
DB_HOST: ${DB_HOST:?Set DB_HOST in .env or environment}
DB_PORT: ${DB_PORT:-3306}
DB_USER: ${DB_USER:?Set DB_USER in .env or environment}
DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD in .env or environment}
DB_NAME: ${DB_NAME:-youtarr}
# Optional: Disable authentication (for platforms with external auth like Elfhosted)
AUTH_ENABLED: ${AUTH_ENABLED:-}
# Optional: Seed initial admin credentials for headless deployments
AUTH_PRESET_USERNAME: ${AUTH_PRESET_USERNAME:-}
AUTH_PRESET_PASSWORD: ${AUTH_PRESET_PASSWORD:-}
# Optional: Configure Express proxy header trust
TRUST_PROXY: ${TRUST_PROXY:-}
# Optional external cookies; /app/config uses the existing mount (see docs/CONFIG.md).
YOUTARR_COOKIES_FILE: ${YOUTARR_COOKIES_FILE:-}
# Logging configuration
LOG_LEVEL: ${LOG_LEVEL:-info}
# Optional: rolling log files in config/logs (defaults: 10MB per file, 5 older files kept)
LOG_FILE_MAX_SIZE: ${LOG_FILE_MAX_SIZE:-}
LOG_FILE_MAX_COUNT: ${LOG_FILE_MAX_COUNT:-}
# This is just informational and lets the app know where the videos will be stored on the host
YOUTUBE_OUTPUT_DIR: ${YOUTUBE_OUTPUT_DIR}
# Optional: Custom data path for platforms like Elfhosted (defaults to /usr/src/app/data)
# This is the internal path where videos are downloaded inside the container and is not needed for most users
# DATA_PATH: /storage/rclone/storagebox/youtube
ports:
- "${YOUTARR_HOST_PORT:-3087}:3011"
volumes:
- ${YOUTUBE_OUTPUT_DIR}:/usr/src/app/data
- ./server/images:/app/server/images
- ./config:/app/config
- ./jobs:/app/jobs
healthcheck:
test: ["CMD", "curl", "--fail", "--silent", "--show-error", "--output", "/dev/null", "http://localhost:3011/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
networks:
default:
name: youtarr-network
Development compose (build first; see Development Guide)
services:
youtarr-db:
image: mariadb:10.3
container_name: youtarr-db-dev
volumes:
- youtarr-db-data-dev:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-123qweasd}
MYSQL_DATABASE: ${DB_NAME:-youtarr}
MYSQL_USER: ${DB_USER:-youtarr}
MYSQL_PASSWORD: ${DB_PASSWORD:-youtarrpassword}
command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
youtarr:
build:
context: .
dockerfile: Dockerfile
image: ${YOUTARR_IMAGE:-youtarr-dev:latest}
container_name: youtarr-dev
# Match production: honor the configured app identity in local development.
# Existing root/other-user-owned files need a one-time ownership repair;
# see docs/DEVELOPMENT.md (Development container ownership).
user: "${YOUTARR_UID:-0}:${YOUTARR_GID:-0}"
# Expose backend on host port 3087 by default (container still listens on 3011).
# The Vite dev server proxies to http://127.0.0.1:3087 by default.
ports:
- "${YOUTARR_HOST_PORT:-3087}:3011"
volumes:
- ${YOUTUBE_OUTPUT_DIR:-./downloads}:/usr/src/app/data
- ./server/images:/app/server/images
- ./config:/app/config
- ./jobs:/app/jobs
# Mount server code for hot reload with --watch
- ./server:/app/server
- ./migrations:/app/migrations
- ./package.json:/app/package.json
- ./package-lock.json:/app/package-lock.json
environment:
- NODE_ENV=development
- DEV_MODE=true
- LOG_LEVEL=${LOG_LEVEL:-debug}
- LOG_FILE_MAX_SIZE=${LOG_FILE_MAX_SIZE:-}
- LOG_FILE_MAX_COUNT=${LOG_FILE_MAX_COUNT:-}
- TZ=${TZ:-UTC}
- DB_HOST=youtarr-db
- DB_PORT=3306
- DB_NAME=${DB_NAME:-youtarr}
- DB_USER=${DB_USER:-youtarr}
- DB_PASSWORD=${DB_PASSWORD:-youtarrpassword}
- YOUTUBE_OUTPUT_DIR=/usr/src/app/data
- AUTH_ENABLED=${AUTH_ENABLED:-true}
- AUTH_PRESET_USERNAME=${AUTH_PRESET_USERNAME:-}
- AUTH_PRESET_PASSWORD=${AUTH_PRESET_PASSWORD:-}
- TRUST_PROXY=${TRUST_PROXY:-}
# Optional external cookies; /app/config uses the existing mount (see docs/CONFIG.md).
- YOUTARR_COOKIES_FILE=${YOUTARR_COOKIES_FILE:-}
# Platform-spoof env vars (used by ./scripts/start-dev.sh --as-elfhosted and full Elfhosted spoofs).
# Empty when unset on the host, so non-Elfhosted dev runs are unaffected.
- PLATFORM=${PLATFORM:-}
- DATA_PATH=${DATA_PATH:-}
- PLEX_URL=${PLEX_URL:-}
depends_on:
- youtarr-db
# Use Node 18+'s built-in watch mode for auto-restart on server changes
command: ["node", "--watch", "server/server.js"]
healthcheck:
test: ["CMD", "curl", "--fail", "--silent", "--show-error", "--output", "/dev/null", "http://localhost:3011/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
volumes:
youtarr-db-data-dev:
Script alternatives
start.sh, start-with-external-db.sh, scripts/start-dev.sh, and scripts/start-dev-external-db.sh are Linux/macOS shell entry points. On Windows, use Docker Desktop Compose commands above or run these scripts under WSL; scripts are references only and are not executed by this generator.