A Working Invidious Tutorial

Why?

Invidious is a lovely self-hosted video player that I just learned about. I found about 20 ways to unsuccessfully get it running and then finally found one way that works. I figured I would document that working method for others.

What?

Basically

  • Docker
  • Docker Compose
  • This docker-compose.yml
services:

  invidious:
    image: quay.io/invidious/invidious:latest
    # image: quay.io/invidious/invidious:latest-arm64 # ARM64/AArch64 devices
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      # Please read the following file for a comprehensive list of all available
      # configuration options and their associated syntax:
      # https://github.com/iv-org/invidious/blob/master/config/config.example.yml
      INVIDIOUS_CONFIG: |
        db:
          dbname: invidious
          user: kemal
          password: kemal
          host: invidious-db
          port: 5432
        check_tables: true
        signature_server: inv_sig_helper:12999
        visitor_data: "ChangeMe"
        po_token: "ChangeMe"
        # external_port:
        # domain:
        # https_only: false
        # statistics_enabled: false
        hmac_key: "ChangeMe"
    healthcheck:
      test: wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/trending || exit 1
      interval: 30s
      timeout: 5s
      retries: 2
#    logging:
#      options:
#        max-size: "1G"
#        max-file: "4"
    depends_on:
      - invidious-db

  inv_sig_helper:
    image: quay.io/invidious/inv-sig-helper:latest
    init: true
    command: ["--tcp", "0.0.0.0:12999"]
    environment:
      - RUST_LOG=info
    restart: unless-stopped
    cap_drop:
      - ALL
    read_only: true
    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
      POSTGRES_PASSWORD: kemal
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]

volumes:
  postgresdata:

How?

  • Save that docker-compose.yml somewhere
  • Run this docker command in order to get the values for visitor_data: and po_token:
$ docker run quay.io/invidious/youtube-trusted-session-generator
[snip]
[INFO] internally launching GUI (X11 environment)
[INFO] starting Xvfb
[INFO] launching chromium instance
visitor_data: CgtWa1FpUXloTk[redacted]jIKCgJVUxIEGgAgVA%3D%3D
po_token: MnQgJPDJBUaJxCAc5Z-Z0TywPP6MRI8Xhk1vdbvse[redacted]cG6nBM7umn62tLgDrgf_VlAyf5L_itpSxsWIzoYhjSpjRvF_GJZruAnQF6zeKSv19fe7Z8x85n780lO4dG0E9Q3yLdc4fbxXAfe_sg==
  • Update the visitor_data: and po_token: values from that output in your docker-compose.yml
  • Run this command order to get a value for hmac_key:
$ pwgen 20 1
yohcooghfoobar1ohTh6
  • Update the hmac_key: value from that output in your docker-compose.yml
  • Run docker compose up
$ docker compose up
[+] Running 1/1
 ✔ Container invidious-invidious-1  Created  0.0s 
Attaching to inv_sig_helper-1, invidious-1, invidious-db-1
inv_sig_helper-1  | [2025-06-25T19:13:55Z INFO  inv_sig_helper_rust] Fetching player
invidious-db-1    | 
invidious-db-1    | PostgreSQL Database directory appears to contain a database; Skipping initialization
invidious-db-1    | 
invidious-db-1    | 2025-06-25 19:13:55.538 UTC [1] LOG:  starting PostgreSQL 14.18 (Debian 14.18-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
invidious-db-1    | 2025-06-25 19:13:55.538 UTC [1] LOG:  listening on IPv4 address "0.0.0.0", port 5432
invidious-db-1    | 2025-06-25 19:13:55.538 UTC [1] LOG:  listening on IPv6 address "::", port 5432
invidious-db-1    | 2025-06-25 19:13:55.540 UTC [1] LOG:  listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
invidious-db-1    | 2025-06-25 19:13:55.542 UTC [27] LOG:  database system was shut down at 2025-06-25 17:52:12 UTC
invidious-db-1    | 2025-06-25 19:13:55.547 UTC [1] LOG:  database system is ready to accept connections
invidious-1       | 2025-06-25 19:13:55 UTC [info] SigHelper: Using helper at 'inv_sig_helper:12999'
inv_sig_helper-1  | [2025-06-25T19:13:56Z INFO  inv_sig_helper_rust::player] Fetching player JS URL: https://www.youtube.com/s/player/5dcb2c1f/player_ias.vflset/en_US/base.js
inv_sig_helper-1  | [2025-06-25T19:13:56Z INFO  inv_sig_helper_rust::player] Prepending n function code with global array variable 'I'
inv_sig_helper-1  | [2025-06-25T19:13:56Z INFO  inv_sig_helper_rust::player] Fixing up nsig_func_body
inv_sig_helper-1  | [2025-06-25T19:13:56Z INFO  inv_sig_helper_rust] Successfully fetched player
invidious-1       | [production] Invidious is ready to lead at http://0.0.0.0:3000
  • Enjoy your Invidious deployment at http://ip-address:3000

Thank You

Thanks for taking the time to read this post. I hope it maybe saved you the few hours it took me to find all the installation methods that do not work. I welcome your feedback.

Postscript

Edit: Some videos fail to load with a "Nil assertion failed (NilAssertionError)" error. Invidious Github Issues says this may be due to videos with age restrictions. I'm not sure. Try another video if that happens.