Skip to content

Community Installation Guide

Before following the community installation guide

All the platforms listed in the community installation guide are not supported officially by the Invidious developers.
This means:

  • The Invidious developers can't help you to solve issues with your platform. Ask the community on Matrix or IRC before creating GitHub issues. But if you do fix an issue please create a PR for updating the community installation guide.
  • The guide for your platform may be outdated because things have changed since the creation of the guide.

If your platform is not listed but you would like to contribute to this guide for adding it, please do here. We rely on the community to help us.

After installation take a look at the Post-install steps.

Podman (rootless container)

Guide contributor(s): @sigulete

Podman is usually pre-installed in Fedora, CentOS, RHEL and derivatives. But if this is not the case, the instruction below will install all necessary packages.

RHEL based and RHEL-like systems

sudo dnf install podman

Download the configuration files from Invidious' repository

Note: Currently the repository has to be cloned, this is because the init-invidious-db.sh file and the config/sql directory have to be mounted to the postgres container (See the volumes section in the postgres' container). This "problem" will be solved in the future.

<INV-PATH> Absolute path in your home directory where Invidious will be downloaded (e.i. /home/johnsmith/.inv)

cd <INV-PATH>
git clone https://github.com/iv-org/invidious.git

Create Pod - videos

podman pod create --name videos -p 3000:3000

Create Container - postgres

podman create --rm \
--pod videos \
--name postgres \
--label "io.containers.autoupdate=registry" \
--health-cmd='pg_isready -U $POSTGRES_USER -d $POSTGRES_DB' \
-v postgresdata:/var/lib/postgresql/data \
-v <INV-PATH>/invidious/config/sql:/config/sql:z \
-v <INV-PATH>/invidious/docker/init-invidious-db.sh:/docker-entrypoint-initdb.d/init-invidious-db.sh:z \
-e POSTGRES_DB=invidious \
-e POSTGRES_USER=kemal \
-e POSTGRES_PASSWORD=kemal \
docker.io/library/postgres:14

Create Container - invidious

Copy <INV-PATH>/invidious/config/config.example.yml to <INV-PATH>/config.yml and update parameters as required.

podman create --rm \
--pod videos \
--name invidious \
--label "io.containers.autoupdate=registry" \
--health-cmd="wget -nv --tries=1 --spider http://127.0.0.1:3000/api/v1/stats || exit 1" \
--health-interval=30s \
--health-timeout=5s \
--health-retries=2 \
-v <INV-PATH>/config.yml:/invidious/config/config.yml:z,U \
quay.io/invidious/invidious:latest

Create systemd services to manage the Pod

Podman can generate systemd services to handle the life cycle of pods and containers. The instructions below will create 3 service units, and they will be placed in the correct location ready to be used.

cd ~
cp $(podman generate systemd --new --files --name videos) .config/systemd/user

Start Pod

Despite the existance of 3 services, only the one related to the Pod must be used. The life cycle for the 2 containers implementing postgres and invidious will be handled by the pod.

systemctl --user daemon-reload
systemctl --user enable --now pod-videos.service

And similarly, the instruction below will re-start the service:

systemctl --user restart pod-videos.service

If this service runs on a server, it will stop as soon as you logout, because it is running in user space. To ensure it is persistent and remains active after logging out, you will need to enable user lingering.

loginctl enable-linger

Updating to the latest release

podman auto-update
podman image prune -f

Podman via systemd

Guide contributor(s): @redbeardymcgee

This method employs rootless containers through podman whose lifecycles are managed by systemd and is suitable for systems which come with Podman version 5.x or higher. Ensure that SELinux is in enforcing mode for maximum security. Do not run any of the following commands or scripts as root.

Define containers

Add the quadlet definitions for Invidious, the database, and the companion containers to $HOME/.config/containers/systemd/invidious.

# $HOME/.config/containers/systemd/invidious/invidious.container
[Unit]
Description=Invidious
Requires=invidious-db.service
After=invidious-db.service
Requires=invidious-companion.service
After=invidious-companion.service

[Service]
Restart=on-failure
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target

[Container]
Image=quay.io/invidious/invidious:latest
ContainerName=invidious
AutoUpdate=registry

Network=invidious.network
HostName=invidious

Volume=./config.yml:/invidious/config/config.yml:Z
# $HOME/.config/containers/systemd/invidious/invidious-db
[Unit]
Description=Invidious postgres

[Service]
Restart=on-failure
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target

[Container]
Image=docker.io/library/postgres:14
ContainerName=invidious-db
AutoUpdate=registry

Network=invidious.network
HostName=invidious-db

Volume=invidious-db:/var/lib/postgresql/data:Z

Environment=POSTGRES_DB=invidious
Environment=POSTGRES_USER=kemal
Environment=POSTGRES_PASSWORD=kemal

# NOTE: Alternatively, set password as a podman secret
# `printf 'my-postgres-password' | podman secret create --replace invidious-db-pw -`
# Secret=invidious-db-pw,type=env,target=POSTGRES_PASSWORD
# $HOME/.config/containers/systemd/invidious/invidious-companion
[Unit]
Description=Invidious companion

[Service]
Restart=on-failure
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target

[Container]
Image=quay.io/invidious/invidious-companion:latest
ContainerName=invidious-companion
AutoUpdate=registry

Network=invidious.network
HostName=invidious-companion

Volume=invidious-companion-cache:/var/tmp/youtubei.js:rw,Z

# WARNING: The container will fail to start without this env var
# NOTE: The podman secret is preferred, but you may set the env var directly like this
# Environment=SERVER_SECRET_KEY=my-secret-key

# If you set the env var above, comment this out
# `pwgen 16 1 | podman secret create --replace invidious-db-pw -`
Secret=invidious-companion-secret-key,type=env,target=SERVER_SECRET_KEY

Define the storage volumes

The database requires a data volume to persist the database. The companion uses a cache volume.

# $HOME/.config/containers/systemd/invidious/invidious-db.volume
[Volume]
VolumeName=invidious-db
# $HOME/.config/containers/systemd/invidious/invidious-companion.volume
[Volume]
VolumeName=invidious-companion-cache

Modify config.yml for your evironment

Copy the example config from HERE.

curl -o "$HOME"/.config/containers/systemd/invidious/config.yml https://raw.githubusercontent.com/iv-org/invidious/refs/heads/master/config/config.example.yml

Edit the configuration according to your environment. The example is very well commented. Notable fields include invidious_companion and invidious_companion_key to ensure that the companion container is connectable. If you changed the $POSTGRES_PASSWORD, then it should be configured to match in the db field. The field hmac_key is mandatory.

Warning

The Invidious container may fail to start or operate as expected if the config.yml is not correctly configured.

Confirm the container services are generated

Systemd units are generated on-the-fly during daemon-reload command, but before that let's check syntax with quadlet generator. Note, you need Podman version 5.0 or higher, older versions will not work:

QUADLET_UNIT_DIRS="$HOME/.config/containers/systemd/invidious" /lib/systemd/user-generators/podman-user-generator -user -dryrun

Reload systemd daemon. Keep in mind you need to do this command every time you change a unit file.

systemctl --user daemon-reload

Prepare the database

The database container requires an initial migration. This should be handled by the field check_tables in config.yml if set to true. The following steps will manually initialize the database in case there is an issue.

# Start the database container
systemctl --user start invidious-db

# Enter the container, install curl, initialize the database, uninstall curl
podman exec invidious-db \
  sh -c '
        apt-get update
        apt-get install --assume-yes --no-install-recommends curl

        for initdb in channels videos channel_videos users session_ids nonces annotations playlists playlist_videos
        do
          curl -s https://raw.githubusercontent.com/iv-org/invidious/refs/heads/master/config/sql/$initdb.sql | psql postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@invidious-db/$POSTGRES_DB
        done
        apt-get --assume-yes purge curl
        '

Create a timer to restart Invidious regularly

Invidious recommends restarting frequently in the post-install configuration documentation. A systemd timer is an effective method of achieving this. Add the file to $HOME/.config/systemd/user/invidious.timer and activate it with systemctl --user enable --now invidious.timer.

# $HOME/.config/systemd/user/invidious.timer
[Unit]
Description=Restart Invidious every hour

[Install]
WantedBy=timers.target

[Timer]
OnUnitActiveSec=60minutes

Start the application

And the whole application can be now started:

systemctl --user start invidious

Keep in mind that generated units cannot be enabled using systemctl --user enable. The Invidious containers will be started automatically.

MacOS

Guide contributor(s): Previously Invidious developers

Generate po_token and visitor_data identities

Follow these instructions here on the official tool youtube-trusted-session-generator

These two parameters will be required for passing all verification checks on YouTube side and you will have to configure them in Invidious.

You have to run this command on the same public IP address as the one blocked by YouTube. Not necessarily the same machine, just the same public IP address.
You will need to copy these two parameters in the config.yaml file.
Subsequent usage of this same token will work on the same IP range or even the same ASN. The point is to generate this token on a blocked IP as "unblocked" IP addresses seems to not generate a token valid for passing the checks on a blocked IP.

About po_token and visitor_data identities

po_token known as Proof of Origin Token. This is an attestation token generated by a complex anti robot verification system created by Google named BotGuard/DroidGuard. It is used to confirm that the request is coming from a genuine device.

These identity tokens (po_token and visitor_data) generated in this tutorial will make your entire Invidious session more easily traceable by YouTube because it is tied to a unique identifier.

There is currently no official automatic tool to periodically change these tokens. This is working in progress but, for the time being, this is the solution the Invidious team is offering.

If you want to be less traceable, you can always script the process by changing the identities every X hour.

Run inv_sig_helper in background

Follow these instructions here on the official tool inv_sig_helper

inv_sig_helper handle the "deciphering" of the video stream fetched from YouTube servers. As it is running untrusted code from Google themselves, make sure to isolate it by for example running it inside Docker or a VM.

Call for action: An example here is welcome, if you want to contribute to one.

Install the dependencies

brew update
brew install crystal postgresql imagemagick librsvg

Clone the Invidious repository

git clone https://github.com/iv-org/invidious
cd invidious

Set up PostgreSQL

brew services start postgresql
createdb
psql -c "CREATE ROLE kemal WITH LOGIN PASSWORD 'kemal';" # Change 'kemal' here to a stronger password, and update `password` in config/config.yml
createdb -O kemal invidious
psql invidious kemal < config/sql/channels.sql
psql invidious kemal < config/sql/videos.sql
psql invidious kemal < config/sql/channel_videos.sql
psql invidious kemal < config/sql/users.sql
psql invidious kemal < config/sql/session_ids.sql
psql invidious kemal < config/sql/nonces.sql
psql invidious kemal < config/sql/annotations.sql
psql invidious kemal < config/sql/playlists.sql
psql invidious kemal < config/sql/playlist_videos.sql

Set up Invidious

make

# Configure config/config.yml as you like
cp config/config.example.yml config/config.yml

# edit config.yaml to include po_token and visitor_data previously generated

edit config/config.yaml