From 54a88cf6cb238d4e96e323b045b78b776616c069 Mon Sep 17 00:00:00 2001 From: Jacob Schlecht Date: Wed, 18 Feb 2026 20:38:03 -0700 Subject: [PATCH] feat: Add voice and new web app to self hosted files (#196) * chore: Use v0.11.1 for now as v0.11.x>1 contain emergency prod-only fix This commit was made without the use of generative AI. Signed-off-by: Jacob Schlecht * feat: add voice to the compose, caddyfile, and livekit config Web section of the compose is commented out for now Added section to readme about the name of the project changing This commit was made without the use of generative AI. Signed-off-by: Jacob Schlecht * chore: update many references to Revolt to reference Stoat Signed-off-by: Jacob Schlecht * feat: Add new dockerized web container This commit was made without the use of generative AI. Signed-off-by: Jacob Schlecht * feat: Confirm reconfiguration if Revolt.toml exists Also fix not outputing new env vars to .env.web This commit was made without the use of generative AI. Signed-off-by: Jacob Schlecht * feat: Add a migration script to make upgrading to voice easier This commit was made without the use of generative AI. Signed-off-by: Jacob Schlecht * fix: Use old referral code This commit was made without the use of generative AI. Signed-off-by: Jacob Schlecht --------- Signed-off-by: Jacob Schlecht Co-authored-by: Declan Chidlow --- Caddyfile | 14 ++++ README.md | 64 ++++++++++++------- compose.yml | 50 +++++++++++---- generate_config.sh | 45 ++++++++++++- livekit.yml | 9 +++ ...240929-autumn-rewrite---prod-migration.mjs | 2 +- migrations/20260218-voice-config.sh | 45 +++++++++++++ 7 files changed, 191 insertions(+), 38 deletions(-) create mode 100644 livekit.yml create mode 100644 migrations/20260218-voice-config.sh diff --git a/Caddyfile b/Caddyfile index b14a88d..4bee7b0 100644 --- a/Caddyfile +++ b/Caddyfile @@ -34,5 +34,19 @@ } } + route /livekit* { + uri strip_prefix /livekit + reverse_proxy http://livekit:7880 { + header_down Location "^/" "/livekit/" + } + } + + route /ingress* { + uri strip_prefix /ingress + reverse_proxy http://voice-ingress:8500 { + header_down Location "^/" "/ingress/" + } + } + reverse_proxy http://web:5000 } diff --git a/README.md b/README.md index 1eec0ae..4a6fb5e 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@

Stoat Self-Hosted - [![Stars](https://img.shields.io/github/stars/revoltchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/revoltchat/self-hosted/stargazers) - [![Forks](https://img.shields.io/github/forks/revoltchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/revoltchat/self-hosted/network/members) - [![Pull Requests](https://img.shields.io/github/issues-pr/revoltchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/revoltchat/self-hosted/pulls) - [![Issues](https://img.shields.io/github/issues/revoltchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/revoltchat/self-hosted/issues) - [![Contributors](https://img.shields.io/github/contributors/revoltchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/revoltchat/self-hosted/graphs/contributors) - [![License](https://img.shields.io/github/license/revoltchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/revoltchat/self-hosted/blob/main/LICENSE) + [![Stars](https://img.shields.io/github/stars/stoatchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/stoatchat/self-hosted/stargazers) + [![Forks](https://img.shields.io/github/forks/stoatchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/stoatchat/self-hosted/network/members) + [![Pull Requests](https://img.shields.io/github/issues-pr/stoatchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/stoatchat/self-hosted/pulls) + [![Issues](https://img.shields.io/github/issues/stoatchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/stoatchat/self-hosted/issues) + [![Contributors](https://img.shields.io/github/contributors/stoatchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/stoatchat/self-hosted/graphs/contributors) + [![License](https://img.shields.io/github/license/stoatchat/self-hosted?style=flat-square&logoColor=white)](https://github.com/stoatchat/self-hosted/blob/main/LICENSE)

Self-hosting Stoat using Docker @@ -17,18 +17,14 @@ This repository contains configurations and instructions that can be used for de > [!WARNING] > If you are updating an instance from before November 28, 2024, please consult the [notices section](#notices) at the bottom. +> If you are updating an instance from before October 5, 2025, please consult the [notices section](#notices) at the bottom. +> If you are updating an instance from before February 18, 2026, please consult the [notices section](#notices) at the bottom. > [!IMPORTANT] > A list of security advisories is [provided at the bottom](#security-advisories). > [!NOTE] -> Please consult _[What can I do with Stoat, and how do I self-host?](https://developers.revolt.chat/faq.html#admonition-what-can-i-do-with-revolt-and-how-do-i-self-host)_ on our developer site for information about licensing and brand use. - -> [!NOTE] -> amd64 builds are not currently available for the web client. - -> [!NOTE] -> This guide does not include working voice channels ([#138](https://github.com/revoltchat/self-hosted/pull/138#issuecomment-2762682655)). A [rework](https://github.com/revoltchat/backend/issues/313) is currently in progress. +> Please consult _[What can I do with Stoat and how do I self-host?](https://developers.stoat.chat/faq)_ on our developer site for information about licensing and brand use. ## Table of Contents @@ -102,6 +98,8 @@ apt-get update && apt-get upgrade -y ufw allow ssh ufw allow http ufw allow https +ufw allow 7881/tcp +ufw allow 50000:50100/udp ufw default deny ufw enable @@ -141,7 +139,7 @@ apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docke Now, we can pull in the configuration for Stoat: ```bash -git clone https://github.com/revoltchat/self-hosted stoat +git clone https://github.com/stoatchat/self-hosted stoat cd stoat ``` @@ -152,7 +150,7 @@ chmod +x ./generate_config.sh ./generate_config.sh your.domain ``` -You can find [more options here](https://github.com/revoltchat/backend/blob/stable/crates/core/config/Revolt.toml), some noteworthy configuration options: +You can find [more options here](https://github.com/stoatchat/stoatchat/blob/stable/crates/core/config/Revolt.toml), some noteworthy configuration options: - Email verification - Captcha @@ -187,7 +185,7 @@ Pull the latest version of this repository: git pull ``` -Check if your configuration file is correct by opening [the reference config file](https://github.com/revoltchat/backend/blob/df074260196f5ed246e6360d8e81ece84d8d9549/crates/core/config/Revolt.toml) and your `Revolt.toml` to compare changes. +Check if your configuration file is correct by opening [the reference config file](https://github.com/stoatchat/stoatchat/blob/df074260196f5ed246e6360d8e81ece84d8d9549/crates/core/config/Revolt.toml) and your `Revolt.toml` to compare changes. Then pull all the latest images: @@ -213,7 +211,7 @@ Prerequisites before continuing: Clone this repository. ```bash -git clone https://github.com/revoltchat/self-hosted stoat +git clone https://github.com/stoatchat/self-hosted stoat cd stoat ``` @@ -225,7 +223,7 @@ Create `.env.web` and download `Revolt.toml`, then modify them according to your ```bash echo "HOSTNAME=http://local.stoat.chat" > .env.web echo "REVOLT_PUBLIC_URL=http://local.stoat.chat/api" >> .env.web -wget -O Revolt.toml https://raw.githubusercontent.com/revoltchat/backend/main/crates/core/config/Revolt.toml +wget -O Revolt.toml https://raw.githubusercontent.com/stoatchat/stoatchat/main/crates/core/config/Revolt.toml ``` Then start Stoat: @@ -361,7 +359,7 @@ db.invites.insertOne({ _id: "enter_an_invite_code_here" }) > ``` > [!IMPORTANT] -> If you deployed Stoat before [2023-04-21](https://github.com/revoltchat/backend/commit/32542a822e3de0fc8cc7b29af46c54a9284ee2de), you may have to flush your Redis database. +> If you deployed Stoat before [2023-04-21](https://github.com/stoatchat/stoatchat/commit/32542a822e3de0fc8cc7b29af46c54a9284ee2de), you may have to flush your Redis database. > > ```bash > # for stock Redis and older KeyDB images: @@ -416,9 +414,31 @@ db.invites.insertOne({ _id: "enter_an_invite_code_here" }) > > - Added `rabbit` (RabbitMQ) and `pushd` (Stoat push daemon) +> [!IMPORTANT] +> As of October 5, 2025, the following breaking changes have been applied: +> +> - Rename docker compose project from revolt to stoat +> +> These will NOT automatically be applied to your environment. +> +> You must run the environment with the old revolt name to apply the update. After you run `docker compose pull` during the upgrade procedure, you must run `docker compose -p revolt down`. You may then continue with the upgrade procedure. + +> [!IMPORTANT] +> As of February 18, 2026, livekit support and the new web app was added to the self host repo. In order to utilize the new voice features and the new web app, you must add configuration. +> +> Before beginning the upgrade process, please do the following: +> +> ```bash +> git pull +> chmod +x migrations/20260218-voice-config.sh +> ./migrations/20260218-voice-config.sh your.domain +> ``` +> +> This should append the new configurations to your existing configuration. Only run this migration once, as if you run it more than once your instance will fail to start. You may then continue with the upgrade procedure. + ## Security Advisories -- (`2024-06-21`) [GHSA-f26h-rqjq-qqjq revoltchat/backend: Unrestricted account creation.](https://github.com/revoltchat/backend/security/advisories/GHSA-f26h-rqjq-qqjq) +- (`2024-06-21`) [GHSA-f26h-rqjq-qqjq stoatchat/stoatchat: Unrestricted account creation.](https://github.com/stoatchat/stoatchat/security/advisories/GHSA-f26h-rqjq-qqjq) - (`2024-12-17`) [GHSA-7f9x-pm3g-j7p4 revoltchat/january: January service can call itself recursively, causing heavy load.](https://github.com/revoltchat/january/security/advisories/GHSA-7f9x-pm3g-j7p4) -- (`2025-02-10`) [GHSA-8684-rvfj-v3jq revoltchat/backend: Webhook tokens are freely accessible for users with read permissions.](https://github.com/revoltchat/backend/security/advisories/GHSA-8684-rvfj-v3jq) -- (`2025-02-10`) [GHSA-h7h6-7pxm-mc66 revoltchat/backend: Nearby message fetch requests can be crafted to fetch entire message history.](https://github.com/revoltchat/backend/security/advisories/GHSA-h7h6-7pxm-mc66) +- (`2025-02-10`) [GHSA-8684-rvfj-v3jq stoatchat/stoatchat: Webhook tokens are freely accessible for users with read permissions.](https://github.com/stoatchat/stoatchat/security/advisories/GHSA-8684-rvfj-v3jq) +- (`2025-02-10`) [GHSA-h7h6-7pxm-mc66 stoatchat/stoatchat: Nearby message fetch requests can be crafted to fetch entire message history.](https://github.com/stoatchat/stoatchat/security/advisories/GHSA-h7h6-7pxm-mc66) diff --git a/compose.yml b/compose.yml index e3ab836..d567571 100644 --- a/compose.yml +++ b/compose.yml @@ -73,7 +73,7 @@ services: # API server api: - image: ghcr.io/revoltchat/server:20250930-2 + image: ghcr.io/stoatchat/api:v0.11.1 depends_on: database: condition: service_healthy @@ -89,7 +89,7 @@ services: # Events service events: - image: ghcr.io/revoltchat/bonfire:20250930-2 + image: ghcr.io/stoatchat/events:v0.11.1 depends_on: database: condition: service_healthy @@ -101,15 +101,9 @@ services: target: /Revolt.toml restart: always - # Web App - web: - image: ghcr.io/revoltchat/client:master - restart: always - env_file: .env.web - # File server autumn: - image: ghcr.io/revoltchat/autumn:20250930-2 + image: ghcr.io/stoatchat/file-server:v0.11.1 depends_on: database: condition: service_healthy @@ -123,7 +117,7 @@ services: # Metadata and image proxy january: - image: ghcr.io/revoltchat/january:20250930-2 + image: ghcr.io/stoatchat/proxy:v0.11.1 volumes: - type: bind source: ./Revolt.toml @@ -132,7 +126,7 @@ services: # Tenor proxy gifbox: - image: ghcr.io/revoltchat/gifbox:20250930-2 + image: ghcr.io/stoatchat/gifbox:v0.11.1 volumes: - type: bind source: ./Revolt.toml @@ -141,7 +135,7 @@ services: # Regular task daemon crond: - image: ghcr.io/revoltchat/crond:20250930-2 + image: ghcr.io/stoatchat/crond:v0.11.1 depends_on: database: condition: service_healthy @@ -155,7 +149,7 @@ services: # Push notification daemon pushd: - image: ghcr.io/revoltchat/pushd:20250930-2 + image: ghcr.io/stoatchat/pushd:v0.11.1 depends_on: database: condition: service_healthy @@ -169,6 +163,30 @@ services: target: /Revolt.toml restart: always + # Voice ingress daemon + voice-ingress: + image: ghcr.io/stoatchat/voice-ingress:v0.11.1 + restart: always + depends_on: + database: + condition: service_healthy + rabbit: + condition: service_healthy + volumes: + - type: bind + source: ./Revolt.toml + target: /Revolt.toml + + livekit: + image: ghcr.io/stoatchat/livekit-server:v1.9.6 + command: --config /etc/livekit.yml + volumes: + - ./livekit.yml:/etc/livekit.yml + ports: + - "7881:7881" + - "50000-50100:50000-50100/udp" + restart: always + # Create buckets for minio. createbuckets: image: docker.io/minio/mc @@ -183,3 +201,9 @@ services: /usr/bin/mc mb minio/revolt-uploads; exit 0; " + + # Web App + web: + image: ghcr.io/stoatchat/for-web:6c5970f + restart: always + env_file: .env.web \ No newline at end of file diff --git a/generate_config.sh b/generate_config.sh index f16052f..3331fe7 100644 --- a/generate_config.sh +++ b/generate_config.sh @@ -1,17 +1,36 @@ #!/usr/bin/env bash -# set hostname for Caddy +if test -f "Revolt.toml"; then + echo "Existing config found, running this script will overwrite your existing config. Are you sure you'd like to reconfigure?" + select yn in "Yes" "No"; do + case $yn in + No ) exit;; + Yes ) break;; + esac + done +fi + +# set hostname for Caddy and vite variables echo "HOSTNAME=https://$1" > .env.web echo "REVOLT_PUBLIC_URL=https://$1/api" >> .env.web +echo "VITE_API_URL=https://$1/api" >> .env.web +echo "VITE_WS_URL=wss://$1/ws" >> .env.web +echo "VITE_MEDIA_URL=https://$1/autumn" >> .env.web +echo "VITE_PROXY_URL=https://$1/january" >> .env.web # hostnames -echo "[hosts]" >> Revolt.toml +echo "[hosts]" > Revolt.toml echo "app = \"https://$1\"" >> Revolt.toml echo "api = \"https://$1/api\"" >> Revolt.toml echo "events = \"wss://$1/ws\"" >> Revolt.toml echo "autumn = \"https://$1/autumn\"" >> Revolt.toml echo "january = \"https://$1/january\"" >> Revolt.toml +# livekit hostname +echo "" >> Revolt.toml +echo "[hosts.livekit]" >> Revolt.toml +echo "worldwide = \"wss://$1/livekit\"" >> Revolt.toml + # VAPID keys echo "" >> Revolt.toml echo "[pushd.vapid]" >> Revolt.toml @@ -24,3 +43,25 @@ rm vapid_private.pem echo "" >> Revolt.toml echo "[files]" >> Revolt.toml echo "encryption_key = \"$(openssl rand -base64 32)\"" >> Revolt.toml + +livekit_key=$(openssl rand -hex 6) +livekit_secret=$(openssl rand -hex 24) + +# livekit key +echo "" >> livekit.yml +echo "keys:" >> livekit.yml +echo " $livekit_key: $livekit_secret" >> livekit.yml +echo "" >> livekit.yml +echo "webhook:" >> livekit.yml +echo " api_key: $livekit_key" >> livekit.yml +echo " urls:" >> livekit.yml +echo " - \"https://$1/ingress/worldwide\"" >> livekit.yml + +# livekit config +echo "" >> Revolt.toml +echo "[api.livekit.nodes.worldwide]" >> Revolt.toml +echo "url = \"https://$1/livekit\"" >> Revolt.toml +echo "lat = 0.0" >> Revolt.toml +echo "lon = 0.0" >> Revolt.toml +echo "key = \"$livekit_key\"" >> Revolt.toml +echo "secret = \"$livekit_secret\"" >> Revolt.toml \ No newline at end of file diff --git a/livekit.yml b/livekit.yml new file mode 100644 index 0000000..6fe2a63 --- /dev/null +++ b/livekit.yml @@ -0,0 +1,9 @@ +rtc: + use_external_ip: true + port_range_start: 50000 + port_range_end: 50100 + tcp_port: 7881 +redis: + address: redis:6379 +turn: + enabled: false \ No newline at end of file diff --git a/migrations/20240929-autumn-rewrite---prod-migration.mjs b/migrations/20240929-autumn-rewrite---prod-migration.mjs index eca3a22..757d36e 100644 --- a/migrations/20240929-autumn-rewrite---prod-migration.mjs +++ b/migrations/20240929-autumn-rewrite---prod-migration.mjs @@ -1,4 +1,4 @@ -// THIS FILE IS TAILORED TO REVOLT PRODUCTION +// THIS FILE IS TAILORED TO STOAT PRODUCTION // MIGRATING FROM A BACKUP & EXISTING CDN NODE // INTO BACKBLAZE B2 // diff --git a/migrations/20260218-voice-config.sh b/migrations/20260218-voice-config.sh new file mode 100644 index 0000000..9a746cb --- /dev/null +++ b/migrations/20260218-voice-config.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# This script is intended for appending the configuration values for livekit. +# Please run this script from the project directory like so: +# ./migrations/20260218-voice-config.sh your.domain + +# Append the new web environment variables to the .env.web +echo "Adding new environment variables to .env.web for new web app..." +echo "VITE_API_URL=https://$1/api" >> .env.web +echo "VITE_WS_URL=wss://$1/ws" >> .env.web +echo "VITE_MEDIA_URL=https://$1/autumn" >> .env.web +echo "VITE_PROXY_URL=https://$1/january" >> .env.web + +# Append the hosts.livekit configuration +echo "Adding livekit worldwide host to Revolt.toml..." +echo "" >> Revolt.toml +echo "[hosts.livekit]" >> Revolt.toml +echo "worldwide = \"wss://$1/livekit\"" >> Revolt.toml + +# Create livekit key and secret +livekit_key=$(openssl rand -hex 6) +livekit_secret=$(openssl rand -hex 24) + +# Append keys and webhook to livekit.yml +echo "Adding livekit key and webhook configuration to livekit.yml..." +echo "" >> livekit.yml +echo "keys:" >> livekit.yml +echo " $livekit_key: $livekit_secret" >> livekit.yml +echo "" >> livekit.yml +echo "webhook:" >> livekit.yml +echo " api_key: $livekit_key" >> livekit.yml +echo " urls:" >> livekit.yml +echo " - \"https://$1/ingress/worldwide\"" >> livekit.yml + +# Append livekit node configuration to Revolt.toml +echo "Adding livekit node configuration to Revolt.toml..." +echo "" >> Revolt.toml +echo "[api.livekit.nodes.worldwide]" >> Revolt.toml +echo "url = \"https://$1/livekit\"" >> Revolt.toml +echo "lat = 0.0" >> Revolt.toml +echo "lon = 0.0" >> Revolt.toml +echo "key = \"$livekit_key\"" >> Revolt.toml +echo "secret = \"$livekit_secret\"" >> Revolt.toml + +echo "Done! <3" \ No newline at end of file