Installation ============ The following installation guides are for Linux only. Theoretically all the components of this software should be possible to deploy onto other operating systems as well however this is not tested and not supported. You will have to be on your own for that. .. note:: The config files shown here are for a setup with local Project-W accounts only. If you want to setup LDAP and/or OIDC, please refer to TODO for more advanced example configs. .. important:: If you plan to host the backend public to the internet: Make sure to only serve the backend over https regardless of your installation method! Without ssl encryption sensitive information like passwords, JWT Tokens for the clients and runners or user data will be transmitted in clear text! .. note:: Prerequisites: Make sure that your DNS and Firewall settings are correct. In particular, the domain that you want to use has to point to the ip address of your server, and your servers firewall needs to allow incoming tcp traffic on your http port Docker ------ We provide two docker images, one for the backend that also serves the frontend at the same time, one that runs cleanup jobs and other periodic tasks with cron, and one for the runner. In the following we assume that you want to host our backend, periodic background tasks, and client/frontend on the same server, and the runner on a different one. If this assumption doesn't hold for you (e.g. if you want the frontend to be served by a different server than the backends API), then you may have to write your own Dockerfiles and docker-compose.yml or choose a different installation method like NixOS ;). .. note:: For both docker images there are multiple docker image tags. The examples below will use the 'latest' tag which will pull the latest stable release (recommended). If you want to pull the development version (latest git commit on main branch), then choose the 'main' tag instead. Alternatively you can also pinpoint the docker image to a specific version. Go to the Packages section of each GitHub repository to find out which tags are available. To use a tag other than 'latest' add it to the end of the 'image:' lines in the docker-compose.yml files below like this: image: /: .. _docker_backend_frontend-label: Backend, Frontend & background jobs ```````````````````````````````````` Choose between the following instructions depending on your setup. If you are unsure which setup to choose and you want the SSL certificate generation to be as easy as possible then :ref:`reverse_proxy-label` is probably for you. Standalone '''''''''' This will setup the backend/frontend without a reverse proxy or any additional components. This guide assumes that you know how to get an SSL certificate for the backend yourself (e.g. by using a self-signed certificate). 1. Install Docker: Refer to your distros package manager / the `Docker documentation `_ for this 2. Create initial directory structure and enter project-W directory: .. code-block:: console mkdir -p project-W/project-W-data/certs && mkdir project-W/project-W-data/postgres && cd project-W 3. To run the backend you need a config.yml file that configures it. You can start off with the following example (don't forget to replace the !) and modify it to your needs if necessary. Put this config file into ./project-W-data. Refer to :doc:`example_configs` for more advanced example configs and to :ref:`description_backend_config-label` for more information about all the configuration options. .. warning:: Please make sure to store the secrets that are read from an environment variable here in a secret way on your server! Some of these secrets would allow a bad actor to gain full access to Project-W including access to all user data! In this setup, the session secret key and the smtp password are being read from the environment variables 'PROJECT_W_JWT_SECRET_KEY' and 'PROJECT_W_SMTP_PASSWORD'. If you want you can also choose to set them here directly in the config, but if you do so please take appropriate measures to keep this config file secret! .. code-block:: yaml client_url: https:///# web_server: ssl: allowed_hosts: - localhost - cert_file: '/etc/xdg/project-W/certs/cert.pem' key_file: '/etc/xdg/project-W/certs/key.pem' postgres_connection_string: !ENV 'postgresql://project_w:${POSTGRES_PASSWORD}@postgres:5432/project_w' redis_connection: connection_string: 'redis://redis:6379/project-W' security: local_token: session_secret_key: !ENV ${JWT_SECRET_KEY} local_account: user_provisioning: 0: email: password: !ENV ${ADMIN_PASSWORD} is_admin: true smtp_server: hostname: port: secure: sender_email: username: password: !ENV ${SMTP_PASSWORD} 4. Put your ssl certs into ./project-W-data/certs. Name the cert and key files as specified in the config above (cert.pem and key.pem respectively) 5. Put docker-compose.yml in the current directory. Use the following config and make same adjustments if needed (make sure to replace the !): .. code-block:: yaml services: postgres: image: postgres:17 restart: unless-stopped environment: - POSTGRES_USER=project_w - POSTGRES_PASSWORD=${PROJECT_W_POSTGRES_PASSWORD} healthcheck: test: ["CMD-SHELL", "pg_isready -U project_w -d project_w"] interval: 10s retries: 3 start_period: 30s timeout: 10s volumes: - ./project-W-data/postgres/:/var/lib/postgresql/data redis: image: redis:8 restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s retries: 3 start_period: 30s timeout: 10s project-w: image: ghcr.io/julianfp/project-w restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "curl", "-fk", "https://localhost:5000/api/about"] interval: 10s retries: 3 start_period: 30s timeout: 10s volumes: - ./project-W-data/:/etc/xdg/project-W/ environment: - JWT_SECRET_KEY=${PROJECT_W_JWT_SECRET_KEY} - SMTP_PASSWORD=${PROJECT_W_SMTP_PASSWORD} - POSTGRES_PASSWORD=${PROJECT_W_POSTGRES_PASSWORD} - ADMIN_PASSWORD=${PROJECT_W_ADMIN_PASSWORD} ports: - 443:5000 project-w_cron: image: ghcr.io/julianfp/project-w_cron restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy volumes: - ./project-W-data/:/etc/xdg/project-W/ environment: - JWT_SECRET_KEY=${PROJECT_W_JWT_SECRET_KEY} - POSTGRES_PASSWORD=${PROJECT_W_POSTGRES_PASSWORD} - ADMIN_PASSWORD=${PROJECT_W_ADMIN_PASSWORD} 6. Generate a JWT_SECRET_KEY that will be used to for generating Session Tokens. If you have python installed you can use the following command for this: .. code-block:: console python -c 'import secrets; print(secrets.token_hex(32))' 7. Run the containers. Replace , , and with the JWT_SECRET_KEY we generated before, the password of the SMTP Server you want to use, some secure password that the admin user should have, and some secure password that you want to use for Postgresql respectively: .. code-block:: console PROJECT_W_JWT_SECRET_KEY="" PROJECT_W_SMTP_PASSWORD="" PROJECT_W_POSTGRES_PASSWORD="" PROJECT_W_ADMIN_PASSWORD="" docker compose up -d 8. You may want to set up some kind of backup solution. For this you just need to backup the project-W-data directory (which will include the database, your ssl certificate and your config.yml) and maybe your docker-compose.yml if you made changes to it. .. _reverse_proxy-label: With Reverse Proxy '''''''''''''''''' Follow this guide if you want to run this behind a Reverse Proxy which automatically takes care of SSL. This setup will disable https on the backend itself but enable it on the reverse proxy. Please make sure that your users only access the Project-W backend through the reverse proxy in this setup, otherwise their traffic will be unencrypted leaving sensitive data, passwords and token open to attackers! .. attention:: This guide will make use of the caddy webserver because of it's automatic handling of https. If you choose to not use caddy as your reverse proxy though then please make sure that your reverse proxy is properly configured to handle the upload of large files. The backend can handle files of many GiB or even larger, limiting this in your reverse proxy will hinder the submission of jobs and present the user with possibly confusing error messages! We will not cover the configuration of the reverse proxy here, but for example if you use nginx you will want to set ``client_max_body_size 0;`` in your config. 1. Install Docker: Refer to your distros package manager / the `Docker documentation `_ for this 2. Create initial directory structure and enter project-W directory: .. code-block:: console mkdir -p project-W/project-W-data && mkdir -p project-W/caddy-data/data && mkdir project-W/caddy-data/config && mkdir project-W/caddy-data/conf && cd project-W 3. Configure Caddy by creating the file called Caddyfile under caddy-data/conf/ with the following content. Please make sure that the DNS record of this domain points to the docker host and that all firewalls and NATs you may have in place are configured to allow traffic on ports 80 AND 443 to the docker host from the internet. .. code-block:: #configure hsts header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload" #compression encode zstd gzip reverse_proxy project-w:5000 4. To run the backend you need a config.yml file that configures it. You can start off with the following example (don't forget to replace the !) and modify it to your needs if necessary. Put this config file into ./project-W-data. Refer to :doc:`example_configs` for more advanced example configs and to :ref:`description_backend_config-label` for more information about all the configuration options. .. warning:: Please make sure to store the secrets that are read from an environment variable here in a secret way on your server! Some of these secrets would allow a bad actor to gain full access to Project-W including access to all user data! In this setup, the session secret key and the smtp password are being read from the environment variables 'PROJECT_W_JWT_SECRET_KEY' and 'PROJECT_W_SMTP_PASSWORD'. If you want you can also choose to set them here directly in the config, but if you do so please take appropriate measures to keep this config file secret! .. code-block:: yaml client_url: https:///# web_server: allowed_hosts: - localhost - reverse_proxy: trusted_proxies: - "172.16.0.0/12" #private ip range used by docker by default no_https: true postgres_connection_string: !ENV 'postgresql://project_w:${POSTGRES_PASSWORD}@postgres:5432/project_w' redis_connection: connection_string: 'redis://redis:6379/project-W' security: local_token: session_secret_key: !ENV ${JWT_SECRET_KEY} local_account: user_provisioning: 0: email: password: !ENV ${ADMIN_PASSWORD} is_admin: true smtp_server: hostname: port: secure: sender_email: username: password: !ENV ${SMTP_PASSWORD} 5. Put docker-compose.yml in the current directory. Use the following config and make same adjustments if needed (make sure to replace the !): .. code-block:: yaml services: postgres: image: postgres:17 restart: unless-stopped environment: - POSTGRES_USER=project_w - POSTGRES_PASSWORD=${PROJECT_W_POSTGRES_PASSWORD} healthcheck: test: ["CMD-SHELL", "pg_isready -U project_w -d project_w"] interval: 10s retries: 3 start_period: 30s timeout: 10s volumes: - ./project-W-data/postgres/:/var/lib/postgresql/data redis: image: redis:8 restart: unless-stopped healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s retries: 3 start_period: 30s timeout: 10s project-w: image: ghcr.io/julianfp/project-w restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "curl", "-fk", "http://localhost:5000/api/about"] interval: 10s retries: 3 start_period: 30s timeout: 10s volumes: - ./project-W-data/:/etc/xdg/project-W/ environment: - JWT_SECRET_KEY=${PROJECT_W_JWT_SECRET_KEY} - SMTP_PASSWORD=${PROJECT_W_SMTP_PASSWORD} - POSTGRES_PASSWORD=${PROJECT_W_POSTGRES_PASSWORD} - ADMIN_PASSWORD=${PROJECT_W_ADMIN_PASSWORD} project-w_cron: image: ghcr.io/julianfp/project-w_cron restart: unless-stopped depends_on: postgres: condition: service_healthy redis: condition: service_healthy volumes: - ./project-W-data/:/etc/xdg/project-W/ environment: - JWT_SECRET_KEY=${PROJECT_W_JWT_SECRET_KEY} - POSTGRES_PASSWORD=${PROJECT_W_POSTGRES_PASSWORD} - ADMIN_PASSWORD=${PROJECT_W_ADMIN_PASSWORD} caddy: image: caddy:2 restart: unless-stopped cap_add: - NET_ADMIN depends_on: project-w: condition: service_healthy volumes: - ./caddy-data/data:/data - ./caddy-data/config:/config - ./caddy-data/conf:/etc/caddy ports: - 80:80 - 443:443 - 443:443/udp 6. Generate a JWT_SECRET_KEY that will be used to for generating Session Tokens. If you have python installed you can use the following command for this: .. code-block:: console python -c 'import secrets; print(secrets.token_hex(32))' 7. Run the containers. Replace , , and with the JWT_SECRET_KEY we generated before, the password of the SMTP Server you want to use, some secure password that the admin user should have, and some secure password that you want to use for Postgresql respectively: .. code-block:: console PROJECT_W_JWT_SECRET_KEY="" PROJECT_W_SMTP_PASSWORD="" PROJECT_W_POSTGRES_PASSWORD="" PROJECT_W_ADMIN_PASSWORD="" docker compose up -d 8. You may want to set up some kind of backup solution. For this you just need to backup the project-W-data directory (which will include the database and your config.yml), the caddy-data directory (which will include your ssl certs, ocsp staples and so on) and maybe your docker-compose.yml if you made changes to it. Runner `````` The runner runs the whisper model and thus benefits greatly from running on a GPU, which we heavily recommend. This GPU should have at least 10GB of VRAM available, ideally a bit more. If you don't have a powerful enough GPU available though you can choose to also run it on CPU. Choose between the following instructions depending on your choice. Currently we have only instructions for NVIDIA GPUs using CUDA but it should also be possible to run this on an AMD GPU using ROCM (for this you are on your own though). NVIDIA GPU '''''''''' 1. If you don't already have one then create an hugging face account, then using that account accept the conditions for the `pyannote/segmentation-3.0 `_ and `pyannote/speaker-diarization-3.1 `_ models. Create a token with access permissions to these repositories (e.g. by just granting the 'Read access to contents of all public gated repos you can access' permission). 2. Install Docker: Refer to your distros package manager / the `Docker documentation `_ for this 3. Install the NVIDIA container toolkit. Refer to the `NVIDIA toolkit documentation `_ for this. Don't forget to restart your docker daemon afterwards. 4. Create initial directory structure and enter project-w directory: .. code-block:: console mkdir -p project-W/runner-config && mkdir project-W/runner-models && cd project-W 5. Like for the backend you also need a config.yml file for the runner. Prepare this file before following the installation steps below. You can use the following example as a base (don't forget to replace the !) and modify it to your needs if necessary. Put this file into ./runner-config. Refer to :ref:`description_runner_config-label` for more information about all the configuration options of the runner. .. warning:: Please make sure to store the secrets that are read from an environment variable here in a secret way on your server! Some of these secrets would allow a bad actor to gain full access to Project-W including access to all user data! In this setup, the auth token and the hugging face token are read from the environment variable 'PROJECT_W_AUTH_TOKEN' and 'PROJECT_W_HF_TOKEN' respectively. If you want you can also choose to set it directly in the config, but if you do so please take appropriate measures to keep this config file secret! .. code-block:: yaml runner_attributes: name: "" backend_settings: url: https:// auth_token: !ENV ${AUTH_TOKEN} whisper_settings: hf_token: !ENV ${HF_TOKEN} 6. Put docker-compose.yml in the current directory. Use the following config and make adjustments if needed .. code-block:: yaml services: runner: image: ghcr.io/julianfp/project-w_runner restart: unless-stopped volumes: - ./runner-config:/etc/xdg/project-W-runner/ - ./runner-models:/root/.cache/project-W-runner/ environment: - AUTH_TOKEN=${PROJECT_W_AUTH_TOKEN} - HF_TOKEN=${PROJECT_W_HF_TOKEN} deploy: resources: reservations: devices: - driver: nvidia count: 1 capabilities: [gpu] .. note:: Alternatively if you have a system with multiple GPUs and you want to have more control over which GPU gets allocated to the Runner, you can replace 'count: 1' above with 'count: all' and then select the GPU in the config.yml using the 'whisper_settings.torch_device' option. See :ref:`description_runner_config-label`. 7. Create a new Runner and obtain its runner token. Refer to :doc:`connect_runner_backend` for how to do that. 8. Run the container. Replace with the runner token you obtained from the backend in the previous step: .. code-block:: console PROJECT_W_AUTH_TOKEN="" PROJECT_W_HF_TOKEN="" docker compose up -d 9. You may want to back up the runners config file (in ./runner-config) and the docker-compose.yml file if you made any changes to them. The ./runner-models directory contains all the whisper models that the runner will fetch automatically. You don't need to backup this directory but you can keep this directory around, copy it to other machines and share it between runners so that the runner doesn't need to spend time fetching these models anymore and so that if you have multiple runners on the same machine the models don't take up storage space multiple times! CPU ''' 1. If you don't already have one then create an hugging face account, then using that account accept the conditions for the `pyannote/segmentation-3.0 `_ and `pyannote/speaker-diarization-3.1 `_ models. Create a token with access permissions to these repositories (e.g. by just granting the 'Read access to contents of all public gated repos you can access' permission). 2. Install Docker: Refer to your distros package manager / the `Docker documentation `_ for this 3. Create initial directory structure and enter project-w directory: .. code-block:: console mkdir -p project-W/runner-config && mkdir project-W/runner-models && cd project-W 4. Like for the backend you also need a config.yml file for the runner. Prepare this file before following the installation steps below. You can use the following example as a base (don't forget to replace the !) and modify it to your needs if necessary. Put this file into ./runner-config. Refer to :ref:`description_runner_config-label` for more information about all the configuration options of the runner. .. warning:: Please make sure to store the secrets that are read from an environment variable here in a secret way on your server! Some of these secrets would allow a bad actor to gain full access to Project-W including access to all user data! In this setup, the auth token and the hugging face token are read from the environment variable 'PROJECT_W_AUTH_TOKEN' and 'PROJECT_W_HF_TOKEN' respectively. If you want you can also choose to set it directly in the config, but if you do so please take appropriate measures to keep this config file secret! .. code-block:: yaml runner_attributes: name: "" backend_settings: url: https:// auth_token: !ENV ${AUTH_TOKEN} whisper_settings: hf_token: !ENV ${HF_TOKEN} torch_device: cpu compute_type: int8 batch_size: 4 5. Put docker-compose.yml in the current directory. Use the following config and make adjustments if needed .. code-block:: yaml services: runner: image: ghcr.io/julianfp/project-w_runner restart: unless-stopped volumes: - ./runner-config:/etc/xdg/project-W-runner/ - ./runner-models:/root/.cache/project-W-runner/ environment: - AUTH_TOKEN=${PROJECT_W_AUTH_TOKEN} - HF_TOKEN=${PROJECT_W_HF_TOKEN} 6. Create a new Runner and obtain its runner token. Refer to :doc:`connect_runner_backend` for how to do that. 7. Run the container. Replace with the runner token you obtained from the backend in the previous step: .. code-block:: console PROJECT_W_AUTH_TOKEN="" PROJECT_W_HF_TOKEN="" docker compose up -d 8. You may want to back up the runners config file (in ./runner-config) and the docker-compose.yml file if you made any changes to them. The ./runner-models directory contains all the whisper models that the runner will fetch automatically. You don't need to backup this directory but you can keep this directory around, copy it to other machines and share it between runners so that the runner doesn't need to spend time fetching these models anymore and so that if you have multiple runners on the same machine the models don't take up storage space multiple times! NixOS ----- We provide NixOS flakes for the backend & frontend combination. Each of the flakes provide a development shell and a package, and the Project-W flake also provides a NixOS module that we will be using now. The runner package, dev shell and NixOS module are currently not functional because nixpkgs hasn't the required version of whisperx right now and updating it is not trivial. Backend & Frontend `````````````````` First you need to import our flake into your flake containing the NixOS config of your machine. For this add the following to your 'inputs' section of your flake.nix: .. code-block:: Nix inputs = { ... project-W = { url = "github:JulianFP/project-W"; inputs.nixpkgs.follows = "nixpkgs"; }; }; Next you need to pass your inputs as an argument to your outputs, where you then can import the module: .. code-block:: Nix nixosConfiguration. = nixpkgs.lib.nixosSystem { ... modules = [ inputs.project-W.nixosModules.default ... ]; }; Now you can start using the module. It's options are available under ``services.project-W``. For a full list and description of options go to nix/module.nix in the project-W repository. Also the ``services.project-W.settings`` attribute set is just a copy of the options of the config file, so you can also refer to :ref:`description_backend_config-label` for this part. You can just use ``!ENV`` at the beginning of Nix strings as well, the module will take care that these are correctly translated into appropriate YAML. Use the ``services.project-W.envFile`` option to pass a path to a file that sets the required environment variables. You can use secret management systems like sops-nix for this to securely manage these secrets. Don't write sensitive information into the ``services.project-W.settings`` because then they would be world-readable in the nix store! Please also make sure to setup a Postgresql and Redis server since that is out of scope of this NixOS module. Refer to the NixOS wiki for how to do that. Runner `````` As already mentioned the runner package and module are currently not working. Use the docker or manual installation method for the runner or make a PR to fix it. .. _manual_installation-label: Manual installation ------------------- You can also run Project-W barebones. This can be a bit more difficult and the following steps will not be as detailed as the ones with Docker or NixOS. You will have to do stuff like configuring python virtual environments, setting up webservers or compiling the frontend yourself. Backend, Frontend & background jobs ```````````````````````````````````` The frontend is written in Svelte and needs to be compiled into native Javascript. To do this you will need some build dependencies, however you can remove them after step 4. If you want you can even build it on a different machine and then just move the build directory to the server between step 4 and 5. 1. Install nodejs 2. Clone the frontend repository and enter it: .. code-block:: console git clone https://github.com/JulianFP/project-W-frontend.git & cd project-W-frontend 3. Install pnpm: .. code-block:: console npm install -g pnpm 4. Install all build dependencies: .. code-block:: console pnpm install 4. Build the frontend: .. code-block:: console pnpm build You can find the result in the ./build directory. Now we will now setup the backend which will serve the static files inside this build directory together with the API. This way the frontend and the API are served from the same origin. 5. Install Python (3.11 or newer, I have tested 3.11 to 3.13) and pip 6. Clone this repository and enter it: .. code-block:: console git clone https://github.com/JulianFP/project-W.git & cd project-W 7. Install the package with pip: .. code-block:: console python -m pip install . 8. Spin up a Postgresql and Redis server (outside of the scope of this tutorial) and put the config.yml file of the backend either into /etc/xdg/project-W/ or ~/.config/project-W/. Alternatively you can also set a custom path to the config file using the `--custom_config_path` CLI option in the command below. 9. Run the backend server: .. code-block:: console project_W --root_static_files 10. Run the background jobs once. This command should be executed at least once each day, so you probably want add a cron job or a systemd service + timer for it: .. code-block:: console project_W --run_periodic_tasks Runner `````` 1. Install Python (3.11 or 3.12, I have mostly tested 3.12), pip, and ffmpeg. 2. Clone this repository and enter it: .. code-block:: bash git clone https://github.com/JulianFP/project-W-runner.git & cd project-W-runner 3. Install the package including the whisperx dependencies with pip: .. code-block:: bash python -m pip install .[not_dummy] 4. Put the config.yml file of the runner either into /etc/xdg/project-W-runner/ or ~/.config/project-W-runner/. Alternatively you can also set a custom path to the config file using the `--custom_config_path` CLI option in the command below. 5. Start up the runner: .. code-block:: bash project_W_runner 6. You may want to make sure that the runner will always restart itself even if it crashes. Currently this might happen in rare cases, so maybe write a script or a systemd service that will always automatically restart the runner in case of a crash.