How to Self-Host Invidious with Docker
What Is Invidious?
Invidious is a privacy-focused alternative frontend for YouTube. It lets you watch YouTube videos without ads, without JavaScript (optionally), without Google tracking, and without a Google account. You get subscriptions, playlists, and search — all running on your own server. Think of it as a YouTube proxy that strips out the surveillance layer.
Invidious is built in Crystal and uses PostgreSQL for storing user preferences, subscriptions, and cached video metadata. A companion service handles video stream retrieval from YouTube.
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 4 GB of free RAM (minimum 2 GB)
- 20 GB of free disk space
- A domain name (recommended for HTTPS access)
- Git installed (required for database initialization files)
Docker Compose Configuration
Invidious requires three services: the main application, a companion service for video retrieval, and PostgreSQL.
First, clone the Invidious repository to get the required database initialization files:
git clone https://github.com/iv-org/invidious.git
cd invidious
Create a docker-compose.yml file in the cloned directory:
services:
invidious:
image: quay.io/invidious/invidious:2.20260207.0
# For ARM64: image: quay.io/invidious/invidious:2.20260207.0-arm64
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
environment:
INVIDIOUS_CONFIG: |
db:
dbname: invidious
user: kemal
password: CHANGE_THIS_DB_PASSWORD
host: invidious-db
port: 5432
check_tables: true
# Companion handles video stream retrieval (required for playback)
invidious_companion:
- private_url: "http://companion:8282/companion"
invidious_companion_key: "CHANGE_THIS_COMPANION_KEY"
# HMAC key for CSRF tokens and cookies (must differ from companion key)
hmac_key: "CHANGE_THIS_HMAC_KEY"
# Your domain (uncomment and set for production)
# domain: invidious.yourdomain.com
# external_port: 443
# https_only: true
# Disable telemetry
popular_enabled: true
registration_enabled: true
login_enabled: true
captcha_enabled: true
statistics_enabled: false
healthcheck:
test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/stats || exit 1
interval: 30s
timeout: 5s
retries: 2
logging:
options:
max-size: "1G"
max-file: "4"
depends_on:
- invidious-db
companion:
image: quay.io/invidious/invidious-companion:latest # Companion has no semver tags published — :latest is the only option
restart: unless-stopped
environment:
# Must match invidious_companion_key above
- SERVER_SECRET_KEY=CHANGE_THIS_COMPANION_KEY
logging:
options:
max-size: "1G"
max-file: "4"
cap_drop:
- ALL
read_only: true
volumes:
- companioncache:/var/tmp/youtubei.js:rw
security_opt:
- no-new-privileges:true
invidious-db:
image: docker.io/library/postgres:14
restart: unless-stopped
volumes:
- postgresdata:/var/lib/postgresql/data
- ./config/sql:/config/sql
- ./docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh
environment:
POSTGRES_DB: invidious
POSTGRES_USER: kemal
# Must match db.password in INVIDIOUS_CONFIG
POSTGRES_PASSWORD: CHANGE_THIS_DB_PASSWORD
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
volumes:
postgresdata:
companioncache:
Generate your secret keys before starting:
# Generate HMAC key
openssl rand -hex 16
# Generate companion key (must be different from HMAC key)
openssl rand -hex 16
# Generate database password
openssl rand -hex 24
Replace CHANGE_THIS_DB_PASSWORD, CHANGE_THIS_COMPANION_KEY, and CHANGE_THIS_HMAC_KEY with your generated values. The companion key must match between the invidious service (invidious_companion_key) and the companion service (SERVER_SECRET_KEY).
Start the stack:
docker compose up -d
Initial Setup
- Open
http://your-server-ip:3000in your browser - You should see the Invidious home page with trending videos
- Click Register to create an account (if registration is enabled)
- Go to Preferences to configure:
- Default video quality
- Dark/light mode
- Default locale and region
- Subscription feed settings
No default credentials exist — the first registered user is a regular user. Set admins in the config to grant admin privileges to specific usernames.
Configuration
Invidious uses YAML configuration embedded in the INVIDIOUS_CONFIG environment variable. Key settings:
| Setting | Default | Description |
|---|---|---|
domain | (none) | Your instance’s FQDN for production use |
external_port | 3000 | Port exposed through your reverse proxy |
https_only | false | Force HTTPS URLs throughout the interface |
registration_enabled | true | Allow new account signups |
login_enabled | true | Allow user login |
captcha_enabled | true | Basic anti-bot captcha on registration |
popular_enabled | true | Show the Popular/Trending tab |
statistics_enabled | false | Expose /api/v1/stats endpoint |
admins | [] | Array of admin usernames (e.g., ["myuser"]) |
default_home | ”Popular” | Default landing page (Popular, Trending, Subscriptions) |
feed_menu | [“Popular”, “Trending”, “Subscriptions”] | Visible menu items |
Production Configuration
For a production instance behind a reverse proxy:
INVIDIOUS_CONFIG: |
db:
dbname: invidious
user: kemal
password: YOUR_DB_PASSWORD
host: invidious-db
port: 5432
check_tables: true
invidious_companion:
- private_url: "http://companion:8282/companion"
invidious_companion_key: "YOUR_COMPANION_KEY"
hmac_key: "YOUR_HMAC_KEY"
domain: invidious.yourdomain.com
external_port: 443
https_only: true
registration_enabled: false
login_enabled: true
captcha_enabled: true
popular_enabled: true
admins: ["yourusername"]
Reverse Proxy
Invidious listens on port 3000. Point your reverse proxy to http://localhost:3000.
For Nginx Proxy Manager, create a proxy host pointing to invidious on port 3000 with WebSocket support enabled. For Caddy:
invidious.yourdomain.com {
reverse_proxy localhost:3000
}
Backup
Back up the PostgreSQL data volume:
# Dump the database
docker exec invidious-db pg_dump -U kemal invidious > invidious_backup.sql
# Restore from dump
cat invidious_backup.sql | docker exec -i invidious-db psql -U kemal invidious
The companion cache volume (companioncache) is ephemeral and does not need backup.
Troubleshooting
Videos Won’t Play
Symptom: Video pages load but playback fails with a black screen or error message.
Fix: The companion service handles video stream retrieval. Verify it’s running and the secret keys match:
docker compose logs companion
# Check for authentication errors
# Verify SERVER_SECRET_KEY matches invidious_companion_key
“Could not check out from database pool” Error
Symptom: Pages fail to load with a database connection error.
Fix: PostgreSQL may not have initialized the Invidious schema. Ensure the init-invidious-db.sh script ran on first startup:
docker compose logs invidious-db | grep "init-invidious"
# If schema wasn't created, restart the database with a clean volume:
docker compose down
docker volume rm invidious_postgresdata
docker compose up -d
Memory Usage Grows Over Time
Symptom: Invidious consumes increasing RAM until the container crashes.
Fix: This is a known behavior. Add a restart policy or use a cron job to restart the container periodically:
# Restart every 6 hours
0 */6 * * * docker compose restart invidious
Registration Disabled After Config Change
Symptom: Changed registration_enabled to false but existing registrations still work.
Fix: This is expected. The setting only prevents new registrations — existing accounts remain active. To remove users, use the database directly.
ARM64 Image Not Found
Symptom: Image pull fails on Raspberry Pi or ARM server.
Fix: Use the ARM-specific tag: quay.io/invidious/invidious:2.20260207.0-arm64. There is no multi-arch manifest — you must specify the ARM tag explicitly.
Resource Requirements
- RAM: ~200 MB idle, 500 MB+ under load with multiple users
- CPU: Low-Medium (video transcoding happens on YouTube’s side)
- Disk: 20 GB minimum for PostgreSQL data and companion cache; grows slowly with usage
Verdict
Invidious is the best self-hosted YouTube frontend if you want privacy, ad-free viewing, and subscription management without a Google account. The setup is straightforward — clone the repo, configure three services, and you’re watching YouTube without Google’s tracking.
The main limitation is YouTube’s ongoing efforts to block alternative clients. Invidious has historically faced periods where video playback breaks until the companion service is updated. If you need guaranteed reliability, consider it a complementary tool rather than a complete YouTube replacement. For archiving videos locally (rather than streaming them), look at Tube Archivist instead.
Note on image versioning: Invidious publishes only latest tags on Quay.io, not pinned semver tags. This is a deliberate project decision. The current release at time of writing is v2.20260207.0.
Frequently Asked Questions
Does Invidious still work with YouTube?
Invidious continues to work, but YouTube periodically implements changes that temporarily break playback. The companion service handles video stream retrieval and is updated by the developers when YouTube changes their API. Expect occasional downtime (hours to days) after YouTube pushes major changes. Check the GitHub repository for current status.
Do I need a Google account to use Invidious?
No. Invidious does not use or require a Google account. You create a local account on your instance for managing subscriptions and preferences. All YouTube interactions go through Invidious’s companion service, not through your Google credentials.
Why does Invidious use so much RAM?
Invidious is built in Crystal (compiled language) and caches video metadata and page renders in memory. Usage grows over time as the cache fills. Set up a cron job to restart the container periodically (e.g., every 6 hours) to reset memory usage. Plan for 500 MB+ under load with multiple users.
Can I run Invidious on a Raspberry Pi?
Yes. Use the ARM64 image tag: quay.io/invidious/invidious:2.20260207.0-arm64. There is no multi-arch manifest — you must specify the ARM tag explicitly. A Raspberry Pi 4 with 4 GB RAM handles single-user usage adequately.
Is there a mobile app for Invidious?
Several third-party apps support Invidious instances. On Android, NewPipe can be configured to use Invidious as a backend. LibreTube also supports custom Invidious/Piped instances. On iOS, Yattee supports Invidious. These are community-maintained, not official Invidious projects.
How is Invidious different from Piped?
Both are privacy-focused YouTube frontends. Invidious is built in Crystal with its own companion service for stream retrieval. Piped is built in Java and uses a different architecture. Invidious has been around longer and has a more mature codebase. Piped has a more modern UI. Both face the same YouTube blocking challenges. See our detailed comparison.
Related
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