01 / TL;DR, with just enough context
Joining friends? Download Strife for your computer, get their Mumble hostname, port, join password, and Helltube HTTPS URL, then follow client setup. You do not need a VPS, Docker, or an administrator account.
Hosting everything? Our preferred fresh-server path is a dedicated Ubuntu 26.04 LTS x86_64 VM, a public IPv4 address, a domain, Docker for Mumble, and the upstream Helltube installer for the video service. Start around 4 vCPU / 8 GB RAM / 80 GB SSD if you intend to transcode video. That is a planning estimate, not a measured capacity promise.
- Choose the region closest to your group; confirm sustained CPU and outbound transfer costs before renting. Save access to the provider's recovery console.
- Create the VM with an SSH key. Update it, reboot if needed, and verify a second SSH login before changing authentication.
-
Create DNS-only
voiceandwatchA records. Allow your SSH port from your IP, 80/443 TCP for web, and 64738 TCP+UDP for voice in the provider firewall. - Install Docker using the commands for your OS, then run the Mumble script below.
- On Ubuntu 26.04, prepare a scoped Cloudflare DNS token and run the Helltube launcher. Choose the single-server arrangement by leaving the separate frontend origin blank.
- Retrieve the generated passwords privately. Change the Helltube admin password, create ordinary accounts, register a Mumble identity, and check channel permissions.
- For desktop sharing, configure and open 44444 TCP+UDP separately. Test all features from a second network, reboot, and take your first recoverable backup.
# In an interactive SSH session on the prepared server:
set -o pipefail
curl -fsSL https://strife.zip/scripts/mumble.sh | sudo bash
# Ubuntu 26.04 + systemd; prompts use your SSH terminal:
curl -fsSL https://strife.zip/scripts/helltube.sh | sudo bash
The script download page explains prerequisites, mutations, source pins, reruns, and checksums. No cloud account credentials are needed for Mumble. Helltube's automated certificate flow needs Cloudflare DNS credentials; the manual Caddy route does not.
02 / Know which machine you are touching
Strife is a desktop client. Installing it on your laptop does not start a public server. Voice and channel chat use a normal Mumble server (also called Murmur). Watch parties use a separate Helltube server. They have separate accounts, storage, connection settings, and operational lifecycles. A Mumble channel does not automatically create or join a Helltube room.
| Component | Runs on | Connections / data |
|---|---|---|
| Strife desktop | Each person's Windows, Linux, or Mac computer | Microphone, speakers, native voice identity, local preferences; embeds Helltube through a private loopback proxy. |
| Mumble container | Your VPS | 64738 TCP+UDP directly; persistent database, registrations, ACLs, server certificate. |
| nginx or Caddy | Your VPS | Public HTTPS on 443; forwards web/API/WebSocket traffic to Helltube on 127.0.0.1:3000. |
| Helltube + FFmpeg + yt-dlp | Your VPS | Accounts, rooms, uploads, media processing and delivery; data directory and service environment must survive updates. |
| Desktop media relay | Inside Helltube on the VPS | Separate 44444 TCP+UDP listener for WebRTC. Its public address must be explicitly configured. |
Your computer ── Mumble TCP + UDP :64738 ── voice server
├─ HTTPS / WSS :443 ── nginx OR Caddy ── :3000 Helltube
└─ WebRTC UDP / TCP :44444 ── Helltube media relay
One VM can run both services. Separate VMs make sense when transcoding starves voice, storage grows, or different people maintain each service. You can also use someone else's Mumble server and host only Helltube. This website's Cloudflare Worker distributes the client; it is not your voice or video server.
03 / Server and VPS selection, excessively considered
Choose by workload, then by region
A small private voice group is relatively lightweight. Video introduces sustained CPU, disk, and egress demand. A shared CPU plan that feels fast during installation can throttle under a long encode. Start with a plan you can resize, use a full VM with root access and systemd, and choose a datacenter near most participants. Try an hourly instance before making a long commitment.
| Use | Initial allocation | Watch first |
|---|---|---|
| Voice/chat for a small group | 1–2 vCPU, 1–2 GB RAM, 20 GB SSD | Packet loss, latency, noisy neighbors, logs. |
| Voice + light video experiments | 2–4 vCPU, 4 GB RAM, 40–80 GB SSD | FFmpeg CPU, native build memory, upload quotas. Limit concurrent transcoders. |
| Regular group watch parties | 4+ sustained vCPU, 8 GB+ RAM, 80 GB+ SSD | Encoding speed and network transfer. More rooms require measurement and scaling. |
| Heavy/multiple encodes | Dedicated CPU or a dedicated machine | Benchmark representative codecs/resolutions. A GPU only helps if your actual pipeline supports it. |
These are editorial starting points, not upstream hardware guarantees. Keep room for OS updates, npm/native builds, temporary media, logs, and backups. Helltube's default aggregate uploaded-storage limit is 30 GiB; that does not include every byte of OS/cache/build usage. Explicitly configure quotas for your disk instead of letting the defaults choose your storage plan.
Transfer is the bill people forget
For relayed video, outbound traffic grows with viewers. A rough
decimal estimate is
GB per hour = Mbps × viewers × 0.45, before protocol
overhead. An 8 Mbps stream sent to 10 viewers is about 80 Mbps and
36 GB per hour. Twenty such hours is roughly 720 GB. Screen
sharing also fans out from your server. Leave headroom rather than
equating a nominal 100 Mbps port with a usable 100 Mbps media
budget.
Check included outbound transfer, overage rate, uplink speed, regional pricing, CPU sharing, disk growth, IPv4 charges, snapshot charges, and whether suspended instances still bill. A snapshot stored in the same provider account is useful but is not an independent backup. Verify acceptable-use terms for your intended traffic and media.
A provider shortlist without made-up prices
Hetzner Cloud and DigitalOcean Droplets are examples of general-purpose VPS products to compare, not requirements or performance endorsements. Use the same region, sustained CPU, RAM, SSD and transfer assumptions in each provider's current calculator. Prefer accessible console recovery, firewall controls, snapshots, predictable billing, and an image you understand over saving a small amount on an obscure plan.
Home hosting, ARM, and containers
A spare machine is fine if it stays powered and your upload connection can handle the group. Reserve its LAN IP, forward the exact TCP and UDP ports, and test from cellular data. Carrier-grade NAT means router forwarding alone will not create public reachability; get a public address, use a VPS, or arrange a VPN that carries the required protocols. Check double NAT between an ISP modem and your router.
ARM64 can work for the pinned Mumble image and Helltube bootstrap. x86_64 remains our default because native media dependency compatibility is easier to compare. The Linux Strife desktop download is x64 only; that does not prevent your server being ARM. Avoid a tiny 32-bit board for video. LXC needs systemd and the appropriate nesting/network permissions; Docker and optional WireGuard may require host configuration. A full VM avoids that extra host/container boundary.
04 / Pick your operating system on purpose
| OS | Preference / trade-off | Use this path |
|---|---|---|
| Ubuntu 26.04 LTS | Preferred for a fresh full stack: matches Helltube's upstream automation. | OS prep → Docker → Mumble script → Helltube script. |
| Ubuntu 24.04 LTS | Good existing host; also the desktop Linux package baseline. Do not change OS just to silence an installer check. | OS prep → Docker/Mumble → manual Helltube/systemd + Caddy. |
| Debian 13 | Good minimal server if you want to own configuration. Stock Node may be below Helltube's requirement. | Debian packages → Docker/Mumble → explicit Node 24 and manual Helltube. |
| Debian 12 | Existing installations can use the same manual path while supported; prefer 13 for a new VM. | Check lifecycle, install current Node, follow Debian branch below. |
| Fedora 43/44 | Suitable for experienced Fedora operators; faster release cadence and SELinux/codec differences mean more maintenance. | Fedora prep and Docker; manual Helltube only after confirming codecs, SELinux access and native builds. |
| Windows / macOS | First-class Strife clients. Useful Helltube local development hosts; avoid tying your friends' uptime to a sleeping laptop. | Native client instructions; local Helltube instructions below; a Linux VM for always-on hosting. |
| Rocky / Alma / RHEL / Arch / Alpine / BSD | Not covered by the bootstrap contracts. Alpine's libc and other native dependencies add work. | Choose a supported Linux VM, or follow each upstream's platform documentation and maintain your own service packaging. |
LTS does not mean never update. Check Ubuntu's support schedule and Debian's release status before provisioning. Fedora operators should plan release upgrades. The scripts reject unsupported platforms; editing their OS checks does not make an unsupported installation supported.
05 / Provision it and keep a way back in
- Create your provider account, enable MFA, save recovery codes, set billing alerts, and choose a region/size. Turn on provider backups if desired, but plan an off-host copy too.
-
On your own computer, create an SSH key if you do not have one.
Give it a passphrase. Upload only the public
.pubfile to the provider; the private key stays on your computer. - Select your OS image and key, attach a provider firewall, and create the instance. Record its address, initial login user, disk layout, and recovery-console procedure.
- Compare the first SSH host-key fingerprint with the console/provider's trusted information. A rebuild legitimately changes it; an unexpected change needs investigation.
# Linux/macOS terminal, or Windows PowerShell with OpenSSH:
ssh-keygen -t ed25519 -C "strife-admin"
ssh root@203.0.113.10
# Some images use ubuntu, debian, or another provider-specified login instead.
To display your public key: Linux/macOS use
cat ~/.ssh/id_ed25519.pub; PowerShell uses
Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub".
Do not overwrite an existing key when prompted. If your image
lacks sudo, use the root console to install it before running sudo
examples.
On Ubuntu/Debian, create a day-to-day administrator with
sudo adduser operator and
sudo usermod -aG sudo operator. Install your public
key in that user's ~/.ssh/authorized_keys, with the
directory mode 700, file mode 600, and ownership belonging to that
user. Fedora uses sudo useradd -m operator,
sudo passwd operator, and group wheel.
Test ssh operator@203.0.113.10 and
sudo -v in a second terminal.
Only after that test should you consider disabling root/password
SSH login. Use an sshd configuration drop-in, verify the effective
values with sudo sshd -T and syntax with
sudo sshd -t, then reload the actual SSH service
(Ubuntu/Debian ssh, Fedora sshd). Cloud
images can have earlier drop-ins that take precedence. Keep the
original session open until the new login works. Do not change the
SSH port and firewall simultaneously without console access.
06 / DNS, ports, firewalls, and the router
In your domain's authoritative DNS zone, create
voice.example.com → 203.0.113.10 and
watch.example.com → 203.0.113.10 as A records. They
may point at different servers if you split services. Use DNS-only
records initially. An A record is IPv4; an AAAA record is IPv6.
Publish AAAA only after verifying the service, proxy, routing, and
both firewall layers over IPv6. A stale AAAA record can break
certificates and half your clients while IPv4 looks perfect.
| Port / protocol | Purpose | Exposure |
|---|---|---|
| 22/TCP (or your SSH port) | Administration | Your admin IP/VPN range. Keep recovery access. |
| 80/TCP | HTTP redirect / HTTP-01 ACME | Public for the Caddy route. DNS-01 issuance itself does not require it. |
| 443/TCP | Helltube HTTPS and WSS | Public. Optional 443/UDP is HTTP/3, not Mumble or desktop media. |
| 64738/TCP and 64738/UDP | Mumble control and voice | Participants; public if your group joins from changing networks. |
| 44444/UDP and 44444/TCP | Helltube desktop media | Participants, only when configured for screen sharing. |
| 3000/TCP | Node web backend | Loopback only. Never add a public rule for this setup. |
| 6502 / database / Docker API | Administrative internals | No public exposure. The supplied Compose file does not publish these. |
Packets must pass every layer: provider security group, VPS firewall, router/NAT if present, and service listener. Allow outbound DNS, HTTPS, time synchronization, and the media sources you use. A provider allowing TCP alone is not sufficient for voice or WebRTC. A TCP port check cannot prove UDP delivery.
Ubuntu / Debian host firewall
On a fresh host, after installing UFW, substitute your actual
admin IP and SSH port. Keep a second SSH session and the recovery
console available. Check
sudo ufw status verbose before enabling an existing
firewall; merge with its rules instead of resetting it.
sudo ufw allow from YOUR_ADMIN_PUBLIC_IP to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 64738/tcp
sudo ufw allow 64738/udp
# Add these when enabling remote desktop sharing:
sudo ufw allow 44444/tcp
sudo ufw allow 44444/udp
sudo ufw enable
sudo ufw status verbose
Docker changes packet filtering. Published container ports can bypass ordinary UFW rules. Apply the intended Mumble restrictions in the provider firewall or Docker's documented packet-filtering path, and test from outside. Do not disable Docker's firewall integration to try to fix this. See Docker firewall behavior.
Fedora host firewall
Use sudo firewall-cmd --get-active-zones to find the
zone attached to your external interface. The example assumes
public; substitute if different. Keep SSH allowed and
use the provider firewall to restrict its source address.
sudo firewall-cmd --permanent --zone=public --add-service=ssh
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --permanent --zone=public --add-port=64738/tcp
sudo firewall-cmd --permanent --zone=public --add-port=64738/udp
sudo firewall-cmd --permanent --zone=public --add-port=44444/tcp
sudo firewall-cmd --permanent --zone=public --add-port=44444/udp
sudo firewall-cmd --reload
sudo firewall-cmd --zone=public --list-all
At home, reserve the server's LAN address and forward each listed protocol to it. Do not forward 3000. Test from a phone hotspot: router hairpin NAT can make the public hostname fail locally even when it works outside. If only LAN clients fail, use split DNS pointing the same hostname to the LAN address. Retain the public hostname for certificate validation.
07 / Prepare the host, per OS
Ubuntu 26.04 or 24.04
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y ca-certificates curl openssl git iproute2 ufw
cat /etc/os-release
uname -m
timedatectl status
df -h
free -h
If a reboot is required, run sudo reboot, reconnect,
and confirm the new kernel and SSH access. Correct time matters
for TLS. For Helltube on 26.04, the upstream installer supplies
its build/media packages; proceed to Docker. On 24.04, install the
manual Helltube dependencies below.
Debian 13 or an existing Debian 12 host
For a minimal image, use su - or the root console to
install sudo and grant your operator access first. Then run the
same apt update/base-package commands as Ubuntu. Debian does not
have Ubuntu's Universe repository; do not add Ubuntu repositories
to Debian. Confirm the distribution ID before configuring Docker's
apt source.
Fedora 43/44
sudo dnf upgrade --refresh -y
sudo dnf install -y ca-certificates curl openssl git iproute firewalld
sudo systemctl enable --now firewalld
cat /etc/os-release
getenforce
timedatectl status
Reboot after kernel updates. Keep SELinux enforcing and inspect
denials if a service cannot access its files. The Mumble script
detects enabled SELinux with getenforce and adds
:Z to its own data bind mount. Do not relabel
arbitrary system directories or disable SELinux globally.
Windows or macOS hosting
For always-on service, provision a Linux VM and follow its Linux instructions over SSH. A local Ubuntu 26.04 VM also works if you configure bridged/NAT networking and keep the host awake. WSL2 is useful for development, but its virtual networking, UDP forwarding and lifecycle are additional work; a PowerShell TCP forwarding rule does not forward Mumble UDP. The downloadable bootstrap scripts target a Linux server, not Git Bash or native macOS.
For a single-computer Helltube experiment, see native Windows/macOS instructions. A local server at 127.0.0.1 is reachable only from that computer. Installing the Strife client is a separate operation.
08 / Install Docker for the Mumble script
Skip installation if your local Docker Engine and
docker compose version already work. These commands
assume a fresh server without competing Docker/containerd
packages. If the host already runs containers, inspect package
ownership and the upstream migration instructions before changing
its engine. Keep using sudo docker; membership in the
docker group grants extensive control over the host.
Ubuntu and Debian: official apt repository
Run the following in Bash. It reads your distribution and codename instead of accidentally installing Ubuntu packages on Debian. The supported releases are documented in the Ubuntu and Debian installation references.
(
set -euo pipefail
. /etc/os-release
case "$ID" in ubuntu|debian) ;; *) echo 'Use the instructions for your OS'; exit 1;; esac
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL "https://download.docker.com/linux/$ID/gpg" | sudo tee /etc/apt/keyrings/docker.asc >/dev/null
sudo chmod a+r /etc/apt/keyrings/docker.asc
printf 'Types: deb\nURIs: https://download.docker.com/linux/%s\nSuites: %s\nComponents: stable\nArchitectures: %s\nSigned-By: /etc/apt/keyrings/docker.asc\n' \
"$ID" "${UBUNTU_CODENAME:-$VERSION_CODENAME}" "$(dpkg --print-architecture)" \
| sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker run --rm hello-world
sudo docker compose version
)
Fedora: official RPM repository
sudo dnf install -y dnf-plugins-core
sudo dnf config-manager addrepo --from-repofile https://download.docker.com/linux/fedora/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
sudo docker run --rm hello-world
sudo docker compose version
Verify the signing-key fingerprint against the official Fedora instructions when prompted. Docker-compatible Podman commands are not the same runtime contract as this bootstrap. On Fedora, the script labels its data mount for SELinux.
09 / Mumble: voice, chat, and actual administration
Keep an existing working Mumble server if you have one. Strife speaks the native protocol and needs no plugin. For a new one, run mumble.sh after Docker setup. It pins the official multi-architecture image by digest, creates persistent host storage, and generates separate administrator and server-join passwords. See the official image configuration reference for additional settings.
set -o pipefail
curl -fsSL https://strife.zip/scripts/mumble.sh | sudo bash
sudo docker compose --project-directory /opt/strife-mumble ps
# Run privately; this output contains credentials:
sudo cat /opt/strife-mumble/mumble.env
MUMBLE_CONFIG_SERVER_PASSWORD is the entry password
you may give your group. MUMBLE_SUPERUSER_PASSWORD is
administrative. Do not send the entire file to friends. On a first
connection, verify the server's certificate fingerprint through a
trusted channel. Mumble's generated certificate can be
self-signed; HTTPS working on your watch hostname does not change
the voice certificate.
Bootstrap permissions with the standard Mumble client
-
Connect to the server as
SuperUserwith its generated administrator password. Use the regular upstream Mumble desktop client for full server/channel ACL administration if Strife does not expose the control you need. - Connect your normal identity under an ordinary username, register that identity, and use the administrator session to add that registered user to the root channel's admin group.
- Create your initial channels. Review inherited ACLs, speaking/join permissions, and whether ordinary users may create channels or register themselves. Test with a second non-admin identity.
- Disconnect SuperUser and use the registered everyday identity. Export/back up its client certificate securely; a display name alone does not preserve registration.
Use
sudo docker compose --project-directory /opt/strife-mumble logs
--tail=100
for startup failures. Logs can contain connection information;
inspect before sharing. The script checks local TCP/TLS startup,
not public UDP or your channel ACLs. A Mumble client can tunnel
voice over TCP when UDP fails, but that can mask firewall mistakes
and increase sensitivity to packet loss.
Manual package alternative
On Debian/Ubuntu,
sudo apt-get install mumble-server is an alternative
to Docker, not an additional step. Inspect
dpkg -L mumble-server and
systemctl cat mumble-server for your package's actual
ini/data/unit paths. Common Debian packages use
/etc/mumble-server.ini; older binaries are named
murmurd. Configure port, join password, user limit
and persistent database, set SuperUser using that binary's
--help instructions, then enable its unit. Do not
start both versions on 64738. The current upstream binary's
options differ from older distribution builds; use the matching
server documentation.
10 / Helltube on Ubuntu 26.04: guided installation
Use a dedicated host or container with systemd. Resolve any existing nginx/Caddy listener conflicts before proceeding. This upstream installer configures nginx and Certbot, so skip the manual proxy install afterward. It obtains certificates using Cloudflare DNS-01 and therefore needs an authoritative Cloudflare-hosted DNS zone.
- Create the DNS-only watch hostname and confirm it resolves to your server.
- Create a Cloudflare API token restricted to this zone with Zone DNS Edit and Zone Read. Prepare an email address for certificate notifications. A scoped token is preferable to a Global API Key.
-
Use an interactive SSH session (allocate a terminal with
ssh -tif necessary). Run the launcher. The downloaded source revision and its hash are listed on the download page. - Enter your backend hostname. For this single-server guide, leave the separate frontend HTTPS origin blank. That serves the frontend and backend from the same public hostname.
- Choose token authentication and enter the token at the hidden prompt. Skip optional cookies and WireGuard initially. Leave automatic backend updates disabled until you have backups and a rollback procedure.
- Wait for dependency installation, native builds, certificate issuance, service startup and HTTPS checks. Keep the SSH session connected and do not run two installers together.
set -o pipefail
curl -fsSL https://strife.zip/scripts/helltube.sh | sudo bash
sudo systemctl status helltube nginx certbot.timer --no-pager
curl -fsS https://watch.example.com/api/health
# Privately retrieve the initial password; change it after signing in:
sudo cat /etc/helltube/.secrets/admin-password
sudo certbot renew --cert-name helltube --dry-run
The app lives in /opt/helltube/app, persistent data
in /var/lib/helltube, and managed
configuration/secrets in /etc/helltube. The generated
password file records the initial password, not later changes.
Make ordinary accounts for everyday use and approve requests
through Helltube's user management.
Failure is a stop, not an automatic rollback. Read the last error
and sudo journalctl -u helltube -n 100 --no-pager.
Fix DNS/token scope, occupied ports, package failures, or
disk/memory shortages before retrying. Rerunning replaces managed
configuration while preserving data and non-default passwords.
Back up customizations first. The installer keeps port 3000 on
loopback; desktop media still needs the
separate setup.
11 / Helltube manually: Ubuntu, Debian, Fedora
This is the alternative for another supported Linux environment, another DNS provider, or an operator who wants to manage each part. Do not layer it over the automated install. Examples target a fresh host; stop if the user, app directory, or service already exists and follow the upgrade procedure instead. The baseline is Node 24, FFmpeg with libx264/AAC, yt-dlp with its default dependencies, and one Helltube process.
Install build and media dependencies
Ubuntu 24.04/26.04 and Debian 12/13:
sudo apt-get update
sudo apt-get install -y ca-certificates curl git xz-utils build-essential \
python3 python3-venv python3-pip ffmpeg openssl
# Ubuntu only: if ffmpeg is unavailable, enable Universe using
# sudo add-apt-repository universe, then repeat apt-get update/install.
Fedora:
sudo dnf install -y ca-certificates curl git xz gcc gcc-c++ make \
python3 python3-pip ffmpeg-free openssl
Fedora's ffmpeg-free package
may not provide the encoders this pipeline needs. Run
ffmpeg -hide_banner -encoders and check for
libx264 and aac. If missing, supply a
compatible FFmpeg build from a source you trust, or use the
Ubuntu/Debian host path. Do not treat successful package
installation as proof of codec availability. The
FFmpeg download page
describes upstream distribution options.
Install a compatible system-wide Node
Check node --version and npm --version.
Helltube requires Node 22.13 or newer; we prefer the supported
Node 24 LTS line. A shell-only version manager can work
interactively but disappear from a systemd service's PATH. The
following installs the explicit Node 24.21.0 baseline from
nodejs.org without replacing existing symlinks. If you already
have a maintained Node 24 installation, use its absolute path in
the unit and skip this block. Review newer security patches in the
Node release documentation
before a later deployment.
(
set -euo pipefail
case "$(uname -m)" in x86_64) arch=x64;; aarch64) arch=arm64;; *) exit 1;; esac
version=v24.21.0
archive="node-$version-linux-$arch.tar.xz"
work=$(mktemp -d)
trap 'rm -rf -- "$work"' EXIT
cd "$work"
curl -fSLO "https://nodejs.org/dist/$version/$archive"
curl -fSLO "https://nodejs.org/dist/$version/SHASUMS256.txt"
awk -v name="$archive" '$2 == name' SHASUMS256.txt > selected.sha256
test -s selected.sha256
sha256sum -c selected.sha256
sudo test ! -e "/opt/node-$version-linux-$arch"
sudo tar -xJf "$archive" -C /opt --no-same-owner
sudo ln -s "/opt/node-$version-linux-$arch/bin/node" /usr/local/bin/node
sudo ln -s "/opt/node-$version-linux-$arch/bin/npm" /usr/local/bin/npm
)
/usr/local/bin/node --version
/usr/local/bin/npm --version
The archive checksum is fetched over HTTPS from the same publisher. For independent signature verification, follow Node's signed release-checksum procedure. Do not force-overwrite an existing runtime used by other applications. If the symlink creation stops, inspect the existing install and choose its intended service path.
Create the service identity and build a pinned checkout
sudo useradd --system --create-home --home-dir /var/lib/helltube --shell /usr/sbin/nologin helltube
sudo install -d -o helltube -g helltube -m 750 /opt/helltube
sudo install -d -o root -g root -m 700 /etc/helltube
sudo -u helltube git clone https://github.com/M-ax/helltube.git /opt/helltube/app
sudo -u helltube git -C /opt/helltube/app checkout --detach b8edab6a0faca32fdddadc1ccfbba74444f7d8bf
sudo python3 -m venv /opt/helltube/tools
sudo /opt/helltube/tools/bin/pip install --upgrade 'yt-dlp[default]'
sudo -u helltube env PATH=/usr/local/bin:/usr/bin:/bin bash -c \
'cd /opt/helltube/app && npm ci && npm run build'
sudo chown -R root:root /opt/helltube/app
sudo chown root:helltube /opt/helltube
sudo chmod 750 /opt/helltube
sudo chmod 750 /var/lib/helltube
The build runs as an unprivileged account; the finished
application becomes root-owned while data stays writable by
Helltube. npm ci uses the lockfile, including the
native mediasoup worker installation. If a prebuilt worker is
unavailable, its build needs Python and a compiler. Resolve native
build errors before starting the service. Keep application and
data directories separate.
Replace seeded credentials before exposing the app
sudo sh -c 'umask 077; openssl rand -hex 24 > /etc/helltube/admin-password'
sudo sh -c 'runuser -u helltube -- env DATA_DIR=/var/lib/helltube \
/usr/local/bin/node /opt/helltube/app/scripts/bootstrap-admin.mjs \
< /etc/helltube/admin-password'
# Read privately, sign in as admin after HTTPS is ready, then change it:
sudo cat /etc/helltube/admin-password
The bootstrap helper changes seeded/default account credentials, preserving existing non-default passwords. Do not put a password in a shell command argument, service file, screenshot, or shared terminal recording. If this step fails, keep the service stopped.
Configure the production environment
Use sudoedit /etc/helltube/helltube.env to create the
following. Substitute the real watch hostname. Units below
interpret these as environment assignments, not a shell script.
Keep the file root-owned and mode 600.
NODE_ENV=production
HOST=127.0.0.1
PORT=3000
DATA_DIR=/var/lib/helltube
SECURE_COOKIES=true
TRUST_PROXY=true
ALLOWED_ORIGINS=https://watch.example.com
FFMPEG_PATH=/usr/bin/ffmpeg
YTDLP_PATH=/opt/helltube/tools/bin/yt-dlp
MAX_TRANSCODERS=1
MAX_STORAGE_BYTES=21474836480
MAX_USER_STORAGE_BYTES=10737418240
The example caps concurrent transcoders at one and uploaded
storage at 20 GiB total / 10 GiB per user. Adjust deliberately for
your machine. Use the actual FFmpeg path if you installed a custom
build. ALLOWED_ORIGINS is an exact origin, with
scheme and no trailing slash; it is not a wildcard domain or a
room URL. Leave BARE_METAL_ORIGIN and
EDGE_PROXY_SECRET unset for this single-origin setup.
Secure cookies require HTTPS at the browser; direct public HTTP
logins will not work as a workaround.
Install the systemd unit
Create /etc/systemd/system/helltube.service with
sudoedit:
[Unit]
Description=Helltube watch parties
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=helltube
Group=helltube
WorkingDirectory=/opt/helltube/app
Environment=PATH=/usr/local/bin:/usr/bin:/bin
EnvironmentFile=/etc/helltube/helltube.env
EnvironmentFile=-/etc/helltube/desktop.env
ExecStart=/usr/local/bin/node /opt/helltube/app/server/main.js
Restart=on-failure
RestartSec=5
UMask=0077
NoNewPrivileges=true
PrivateTmp=true
ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/helltube
[Install]
WantedBy=multi-user.target
sudo chmod 600 /etc/helltube/helltube.env
sudo systemd-analyze verify /etc/systemd/system/helltube.service
sudo systemctl daemon-reload
sudo systemctl enable --now helltube
sudo systemctl status helltube --no-pager
curl -fsS http://127.0.0.1:3000/api/health
sudo ss -lntp 'sport = :3000'
Expect the HTTP listener on loopback and a successful health
response. Now add exactly one reverse proxy. On Fedora, inspect
sudo ausearch -m AVC -ts recent if SELinux denies
service execution, data access or proxy networking. Use
appropriate file labels and the distro's documented service
policy/booleans; do not switch enforcement off to hide a
permissions mistake.
Native Windows and macOS: local experiment
These foreground commands are for a local machine, not a persistent public deployment. Install Git, a current Node 24 LTS, FFmpeg with libx264/AAC, and current yt-dlp first. Windows may need the C++/Python build tools if mediasoup has to compile; macOS may need Xcode Command Line Tools. Check all tool versions in the same terminal that will run npm.
Windows PowerShell (installers are interactive; reopen the terminal after PATH changes):
winget install --id OpenJS.NodeJS.LTS -e
winget install --id Git.Git -e
winget install --id Gyan.FFmpeg -e
winget install --id yt-dlp.yt-dlp -e
git clone https://github.com/M-ax/helltube.git
Set-Location helltube
git checkout --detach b8edab6a0faca32fdddadc1ccfbba74444f7d8bf
npm ci
npm run build
$env:HOST = '127.0.0.1'
$env:ALLOWED_ORIGINS = 'http://127.0.0.1:3000'
npm start
macOS, with Homebrew already installed:
xcode-select --install
brew install node@24 ffmpeg yt-dlp git
export PATH="$(brew --prefix node@24)/bin:$PATH"
git clone https://github.com/M-ax/helltube.git
cd helltube
git checkout --detach b8edab6a0faca32fdddadc1ccfbba74444f7d8bf
npm ci
npm run build
HOST=127.0.0.1 ALLOWED_ORIGINS=http://127.0.0.1:3000 npm start
Open http://127.0.0.1:3000 locally. This native local
path uses upstream's seeded admin /
garbageTime_ credentials; change the password
immediately in Account before any broader access. Stop with
Ctrl+C. Persistent state is in the checkout's
data directory unless you set DATA_DIR.
Do not expose the development server or seeded credentials to the
Internet. For persistent hosting, use the Linux service and HTTPS
procedure.
12 / Reverse proxying without breaking half the app
Proxy Helltube's HTTP and WebSockets. Mumble and desktop WebRTC
use different protocols and listeners. Preserve Host, Origin,
cookies, range requests, and upgrade headers; do not add blanket
caching. Block /internal and its descendants outside
loopback. Serve the app at the root of its own hostname; this
guide does not configure a subdirectory deployment.
Caddy: our manual-install preference
Caddy automatically manages HTTPS and handles WebSocket upgrades
through reverse_proxy. DNS must resolve correctly and
the ACME challenge must reach the host. See
automatic HTTPS
and
reverse proxy behavior. Keep Caddy's persistent certificate storage across restarts.
On Ubuntu/Debian, install the distribution's
caddy package with
sudo apt-get install caddy, or use the
official stable repository
if your distribution does not provide it. On Fedora, Caddy
documents sudo dnf install dnf5-plugins,
sudo dnf copr enable @caddy/caddy, then
sudo dnf install caddy. Do not start Caddy while
nginx already owns 80/443.
On a fresh Caddy install, edit /etc/caddy/Caddyfile.
On a shared proxy, add a site block and preserve its existing
sites. Substitute your real domain:
watch.example.com {
@private path /internal /internal/*
handle @private {
respond 404
}
handle {
reverse_proxy 127.0.0.1:3000
}
}
sudo caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo systemctl enable --now caddy
sudo systemctl reload caddy
curl -fsS https://watch.example.com/api/health
curl -s -o /dev/null -w '%{http_code}\n' https://watch.example.com/internal
Expect health to return 200 and the private path 404. No
tls_insecure_skip_verify, wildcard CORS, cookie
stripping, or global frame-header removal is needed. Avoid access
logging full media URLs because they can contain access tokens. If
you enable logging, redact sensitive URLs and headers.
nginx: for an existing nginx host
The Ubuntu installer configures this already. For a manual nginx
deployment, install nginx and provision a browser-trusted
certificate with your ACME client first. For HTTP-01 issuance on a
fresh host, install
nginx certbot python3-certbot-nginx on Ubuntu/Debian,
create an HTTP server block for the hostname, then run
sudo certbot --nginx -d watch.example.com. Confirm
certificate paths from sudo certbot certificates. A
DNS-01 client/plugin is an alternative when HTTP-01 is
unavailable.
The following example belongs in an nginx file included from the
http context, such as
/etc/nginx/conf.d/helltube.conf. Replace the hostname
and certificate paths. The map must be outside the
server blocks. Remove duplicate blocks for this same hostname
after preserving a backup; do not overwrite unrelated sites.
map $http_upgrade $helltube_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name watch.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name watch.example.com;
ssl_certificate /etc/letsencrypt/live/watch.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/watch.example.com/privkey.pem;
access_log off;
error_log /var/log/nginx/helltube-error.log crit;
client_max_body_size 2m;
location = /internal { return 404; }
location ^~ /internal/ { return 404; }
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header Origin $http_origin;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $helltube_upgrade;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
Helltube uploads use 512 KiB chunks, so a 2 MiB per-request limit does not restrict the total video to 2 MiB. Its own quotas still apply. nginx requires explicit WebSocket upgrade handling. This example listens on IPv4; add and verify IPv6 listeners before publishing AAAA. Error logging is deliberately restricted to reduce sensitive URL logging; temporarily increased diagnostic logs need careful handling.
sudo nginx -t
sudo systemctl enable --now nginx
sudo systemctl reload nginx
sudo certbot renew --dry-run
curl -fsS https://watch.example.com/api/health
Confirm your ACME client has a renewal timer and a deploy hook that tests/reloads nginx after renewal. Caddy handles its own lifecycle. Do not run two independent certificate managers for the same listener without a specific reason.
Cloudflare DNS, reverse proxies, and the optional Worker split
Use DNS-only for Mumble: Cloudflare's ordinary HTTP proxy does not transport your 64738 TCP/UDP service. See its supported network ports. Start Helltube DNS-only as well. A tunnel does not automatically carry its separate desktop media listener, and a Cloudflare Origin CA certificate alone is not browser-trusted for direct access.
Helltube also supports an optional Worker frontend plus a DNS-only
HTTPS metal backend. That is a separate, advanced deployment: set
matching BARE_METAL_ORIGIN in Worker and backend, the
exact frontend in ALLOWED_ORIGINS, and a matching
random EDGE_PROXY_SECRET through each system's secret
store. Keep backend /internal/* blocked, preserve
X-Helltube-Edge, and allow direct uploads/keys/media
to reach metal. Do not put the metal hostname behind Cloudflare
Tunnel or the ordinary orange-cloud proxy. Deploy matching
frontend/backend versions. Follow the
upstream split-deployment procedure
after the single-host setup is working.
13 / Desktop sharing: the second networking job
The default media bind is 127.0.0.1:44444. Remote
participants cannot use it until you change it. HTTPS/WSS
establishes the session; WebRTC carries screen video/audio
directly between each browser and the Helltube relay. Neither
nginx nor the Worker carries those media packets.
For the managed Ubuntu install or the manual unit above, create
/etc/helltube/desktop.env with sudoedit.
Substitute the server's real reachable public IP. An explicit IPv4
avoids browser DNS differences for ICE candidates:
DESKTOP_LISTEN_IP=0.0.0.0
DESKTOP_ANNOUNCED_ADDRESS=203.0.113.10
DESKTOP_PORT=44444
DESKTOP_ICE_SERVERS=[]
sudo chmod 600 /etc/helltube/desktop.env
sudo systemctl restart helltube
sudo ss -lntup 'sport = :44444'
Open 44444 UDP and TCP in the host/provider firewalls and forward it through NAT using the same external port. The relay can initialize when a desktop session starts; absence before use is not by itself proof of failure. Test an actual share from another network. A wildcard bind requires an announced address. Do not announce 127.0.0.1 or a private LAN address to Internet users.
For restrictive client networks, deploy a separate TURN service
such as coturn. A typical design allows 3478 UDP/TCP, 5349 TCP for
TLS, and a deliberately configured relay-port range. It needs its
own DNS-only hostname, trusted certificate, authentication,
bandwidth budget and firewall rules. Configure Helltube's
DESKTOP_ICE_SERVERS and
DESKTOP_TURN_SECRET to match the relay. Never publish
the shared REST-auth secret in frontend code. STUN discovers
connectivity; it does not relay traffic when direct access is
blocked. See
coturn configuration
and
Helltube's TURN settings.
Screen capture additionally needs HTTPS/localhost, OS permission, and a compatible browser/webview. Sound capture varies by OS and selected window/tab. Test in an external browser to separate a server connectivity problem from a desktop webview permission problem.
14 / Install Strife on each person's computer
Use the platform downloads and their published checksums. Select your computer's CPU architecture, not the server's architecture. Packages include .NET and the native voice engine; there is no need to install a second Mumble client just to use Strife. You may still want upstream Mumble for advanced administration.
Windows x64
- Use Windows 10 build 19041+ or Windows 11 on x64. Download the setup EXE for the simplest installation. It includes the WebView2 and Visual C++ prerequisites.
- Verify the file's SHA-256 with the command below and compare it with the platform card/checksum download. The installer is currently unsigned, so Windows may show a publisher warning. Confirm the source and checksum before choosing to run it.
- Run setup, choose your installation options, and launch Strife from the Start Menu. Allow microphone access under Windows privacy settings.
- For portable use, extract the complete ZIP to a writable directory and launch Strife.exe. Keep the accompanying files together. The portable package requires WebView2 and the VC++ x64 runtime already installed.
# PowerShell, in the directory containing your download:
Get-FileHash .\Strife-0.1.0-preview.2-win-x64-Setup.exe -Algorithm SHA256
If the UI is blank, check WebView2. If a native DLL is missing, check the VC++ runtime and that the whole portable folder was extracted. Install prerequisites from Microsoft or use the bundled setup; do not fetch individual DLLs from random sites. Profiles survive normal upgrades and uninstall.
Linux x64: Ubuntu 24.04 baseline
The shipped tarball targets Ubuntu 24.04 x64 with GTK 3, WebKitGTK 4.1 and audio/X11 libraries. Use a desktop session with an audio device, not a headless VPS shell. Install these runtime packages on Ubuntu 24.04:
sudo apt-get update
sudo apt-get install -y libgtk-3-0 libwebkit2gtk-4.1-0 libnotify4 libasound2t64 \
libsm6 libice6 libx11-xcb1 libxi6 libxrender1 libxcb-cursor0 \
libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 \
libxcb-xinerama0 libxcb-xkb1 libxkbcommon-x11-0 libgl1 libegl1
# Download the archive and adjacent checksum from the platform card.
sha256sum -c Strife-0.1.0-preview.2-linux-x64.tar.gz.sha256
tar -xzf Strife-0.1.0-preview.2-linux-x64.tar.gz
./Strife/Strife
Extract into a fresh directory when upgrading instead of mixing old and new files. Newer Ubuntu/Debian desktops may work but package names/ABI requirements must match; Fedora and other distributions need their own equivalent libraries. The server's Fedora support does not imply a tested Fedora desktop package. There is no published Linux ARM desktop build in this release. On Wayland, test global shortcuts and screen-capture permissions in your actual session.
macOS 14+: Apple Silicon or Intel
- Check About This Mac: Apple Silicon uses the arm64 ZIP; an Intel processor uses x64. Download the matching archive/checksum.
-
Verify with
shasum -a 256 -c Strife-0.1.0-preview.2-osx-arm64.zip.sha256(change the filename for Intel), extract, and move Strife.app to Applications. - Launch it. The preview build is ad-hoc signed and not notarized. After confirming its origin, use the specific app's approval flow in System Settings → Privacy & Security if macOS blocks it. Do not disable Gatekeeper globally.
- Grant microphone access; grant accessibility/input or screen-capture permissions only for features you use. Relaunch if the OS requires it after a permission change.
Keep the app bundle intact. If a build will not launch on its documented minimum OS, collect its version/architecture and the specific OS error. Native build requirements and packaging details are in Strife's release guide.
15 / Connect the humans
-
Open Connect to server. Enter
voice.example.comas the hostname (no https://), port64738, your ordinary username, and the optional server join password. - Review the native certificate dialog. Compare unfamiliar or changed fingerprints with the operator. Do not train your group to accept every changed certificate.
- Join a channel in the left tree. Channel chat goes to the current Mumble channel. Verify mute/deafen and input/output devices.
- Open Menu → Voice settings & shortcuts. For push-to-talk, select Push To Talk in Audio Input and bind a Push-to-Talk action in Shortcuts. Test while another application has focus. Elevated applications on Windows can require matching privileges for shortcuts.
-
Open Helltube → Server and enter
https://watch.example.com. Sign in inside the video pane with a Helltube account. A Mumble password is not a Helltube login. - Create/join a Helltube room with friends. Test a small known-good upload and then the intended remote media sources. Provider availability and permissions can vary independently of your server.
New Strife profiles start with RNNoise enabled. Imported Mumble settings preserve their previous processing choice. Use the audio wizard and a headset, select the intended microphone explicitly, and verify gain/voice activation before blaming the network.
Channel chat and images
Channel chat preserves message line breaks, and links open through your system's browser or registered application. Source builds containing the chat image fix also display incoming embedded PNG, JPEG, GIF, WebP, and BMP attachments inline. Images fit the chat pane, keep their proportions, and retain any link target. This fix is newer than the packaged download currently advertised on this site.
An [Image unavailable] placeholder means an
attachment is unsupported, unreadable, too large, or outside the
retained image history. Remote image URLs and other rich HTML are
not loaded in the chat pane. Reloading restores the retained
attachments from the running voice session.
Import your existing identity
Close Mumble so its latest settings are saved and disconnect Strife voice. Choose Menu → Import from Mumble, review the detected profile, and select the categories you want. Imported settings, server data, and certificate identity replace those selected Strife categories. Unselected categories and Helltube/layout remain. Strife creates an import backup. Including the client certificate preserves registered server identity; merely copying your username does not.
The Windows profile is under %LOCALAPPDATA%\Strife;
other platforms use .NET's LocalApplicationData location.
STRIFE_PROFILE can select an explicit directory.
Protect identity/profile backups as credentials and do not share a
profile between simultaneous instances.
A useful invitation contains
Send the client download link, Mumble hostname/port/join password, a trusted certificate fingerprint, Helltube HTTPS URL and account-request instructions, and the channel/room to join. Keep SuperUser, Helltube admin credentials, SSH keys, DNS tokens, cookie exports and TURN shared secrets out of it. Use an ordinary test account to confirm the invitation actually works.
16 / Acceptance tests: prove each layer works
A green process indicator is only the beginning. Work outward from the server, then repeat from a different Internet connection. Record the hostname, OS, deployed revision, image digest, date, and results so future failures have a baseline.
# Server-side checks:
sudo docker compose --project-directory /opt/strife-mumble ps
sudo systemctl is-active helltube
curl -fsS http://127.0.0.1:3000/api/health
curl -fsS https://watch.example.com/api/health
sudo ss -lntup
# On a Linux/macOS client on another network:
set -o pipefail
curl -fsSL https://strife.zip/scripts/doctor.sh | bash -s -- voice.example.com watch.example.com
- DNS: resolve both names outside your LAN. Check A and AAAA individually if configured. No unexpected Cloudflare proxy addresses for voice/metal.
- TLS: browse to the watch URL without certificate warnings; verify expiration and hostname. Confirm HTTP redirects to HTTPS. Voice certificate trust is a separate test.
-
Private interfaces: port 3000 should be
unreachable remotely. Both
/internaland/internal/anythingmust be blocked externally. - Voice: two ordinary users on separate networks join, exchange audio, mute/deafen, change channels, and send channel text. Inspect the native connection information for UDP use; working tunneled TCP voice can conceal blocked UDP.
- Accounts: verify Helltube login, logout, password change and non-admin access; reload Strife and confirm expected session restoration.
- WebSockets: two viewers see queue/play/pause changes promptly. In browser developer tools, check the authenticated WebSocket upgrade and ongoing messages; a page loading alone proves very little.
- Media: upload a small file, play and seek it from both clients, then test a representative longer video while watching CPU/RAM/disk/egress. Test remote providers separately.
- Desktop: share from an external network and watch from another, including optional audio. Test TURN separately if you deployed it.
- Reboot: schedule a brief interruption, reboot the VPS, reconnect and verify both services return with accounts, channels, uploads and certificates intact.
- Restore: restore a backup to a disposable isolated machine and repeat a login/media check. An archive that has never been restored is an unproven recovery plan.
Our doctor checks DNS, TCP/TLS, HTTP status, and relevant local listeners. It cannot validate an admin's ACL decisions, actual audio, certificate fingerprint agreement, UDP media, transcoder performance, or TURN allocation. It does not dump secrets or logs.
17 / Backups, observability, and maintenance
Know what must survive
| Data | Location in this guide | Why it matters |
|---|---|---|
| Mumble state/config | /opt/strife-mumble | Database, certificate, accounts, ACLs, passwords and pinned Compose image. |
| Helltube data | /var/lib/helltube | Database, uploads and persistent application state. Copy consistently with the service stopped. |
| Helltube configuration | /etc/helltube; optional /etc/helltube-cookies | Environment, initial credentials, DNS/edge/TURN secrets and optional media credentials. |
| Service/proxy/TLS | Your systemd unit/drop-ins; nginx or Caddy config; /etc/letsencrypt or Caddy's data directory | Reconstruct listeners and renewal. Preserve certificate-manager account state securely. |
| Deployment record | Chosen by you, off-host | Source revision, Node version, image digest, DNS/firewall settings and restore order. |
| Client identity | Each user's private profile/certificate backup | Retains their Mumble registration; the server backup does not replace it. |
Backups contain passwords and private keys. Encrypt off-host copies and restrict access. Define how much data you can afford to lose (for example a day's uploads) and how long recovery may take. Keep more than one generation; a backup taken after accidental deletion may faithfully preserve the deletion.
A consistent baseline backup
Schedule downtime. Run this as one block in Bash on the server. It stops the two apps, records whether each was running, and tries to restart only those it stopped even if archiving fails. Ensure free space before starting. The archive includes the core app data/config; additionally capture the proxy/TLS and optional files in the inventory above.
sudo bash <<'BACKUP'
set -euo pipefail
umask 077
install -d -m 700 /var/backups/strife
voice_was_running=$(docker compose --project-directory /opt/strife-mumble ps --status running -q)
video_was_running=no
if systemctl is-active --quiet helltube; then video_was_running=yes; fi
resume() {
if [[ -n $voice_was_running ]]; then docker compose --project-directory /opt/strife-mumble start; fi
if [[ $video_was_running == yes ]]; then systemctl start helltube; fi
}
trap resume EXIT
docker compose --project-directory /opt/strife-mumble stop
systemctl stop helltube
stamp=$(date -u +%Y%m%dT%H%M%SZ)
archive="/var/backups/strife/strife-$stamp.tar.gz"
tar -czf "$archive" -C / opt/strife-mumble var/lib/helltube etc/helltube
sha256sum "$archive" > "$archive.sha256"
tar -tzf "$archive" >/dev/null
BACKUP
Copy the encrypted backup and checksum to another machine/provider. After restoring on a clean host, preserve numeric ownership or deliberately remap it to the recreated service UID; do not assume a newly created user has the same UID. Reinstall dependencies, restore configuration, validate proxy syntax and start services before moving DNS. Restoring the Mumble data preserves its certificate and registrations. Restore SQLite data as a consistent set rather than cherry-picking database/WAL files.
A maintenance rhythm
- Daily: review backup completion, free disk, service availability and provider billing/egress alerts.
- Weekly: install supported OS security updates, schedule necessary reboots, review certificate renewal and unusual resource growth.
- Before updates: capture a consistent backup and versions; test the change on a spare host or restore first.
- Periodically: restore a backup, rotate access when administrators leave, verify ordinary user permissions, and review provider/OS lifecycle dates.
Useful commands are df -h, free -h,
top, sudo docker stats --no-stream,
sudo journalctl -u helltube --since '1 hour ago', and
your provider's network graph. Keep log retention bounded. Redact
tokens, cookies, private IPs as needed and media bearer URLs
before sharing diagnostics. Do not paste environment files into an
issue.
18 / Upgrade deliberately, retain a rollback
Mumble container
The script pins 1.5.915 and its multi-architecture digest;
compose pull alone will not move that pin. For an
upgrade, read upstream release notes, record the old image string,
make a stopped-data backup, resolve and review the new image
digest, and change only the image in your Compose file. Then:
sudo docker compose --project-directory /opt/strife-mumble config --quiet
sudo docker compose --project-directory /opt/strife-mumble pull
sudo docker compose --project-directory /opt/strife-mumble up -d
sudo docker compose --project-directory /opt/strife-mumble ps
Verify two-client voice and channel permissions. If a version
migrated the database, reverting only the image may not be enough:
stop the new service and restore the matching old data/config
backup with the old image. Keep the failed new data separately for
investigation. Do not run down -v as an upgrade step.
Helltube managed install
The launcher always starts from its published source pin. It is not a “get whatever is newest” updater. To deploy a newer revision, review that revision's upstream installer, back up data/config, and run it from the trusted updated checkout. The upstream installer replaces managed infrastructure files. Opt-in automatic updates track upstream main and can restart services; understand that trust/availability trade-off before enabling them. A split Worker frontend must be deployed separately and kept compatible.
Helltube manual install
-
Record
git -C /opt/helltube/app rev-parse HEAD, Node version, yt-dlp version and environment values (privately). Make a consistent backup. -
Build the selected revision in a new staging directory as an
unprivileged builder with
npm ciandnpm run build. Run that revision's relevant checks. Do not build over the live application. - Schedule downtime and stop Helltube. Preserve the old application directory, install the new complete build at the service's application path, set ownership correctly, and keep data/config separate.
- Start, verify local/public health, login, uploads, playback and screen sharing. If it fails, stop it and restore the previous application plus matching pre-migration data as needed.
Update yt-dlp in its isolated environment when provider changes
require it:
sudo /opt/helltube/tools/bin/pip install --upgrade
'yt-dlp[default]'. Record the resulting version. Keep Node on a supported patched
release and update your service path intentionally. A TLS proxy or
DNS change does not repair a broken provider extractor.
19 / The “it doesn't work” decision tree
| Symptom | Check / next action |
|---|---|
| SSH suddenly fails | Use provider console. Check address, SSH unit, key ownership and firewall source rules. Keep working sessions open while fixing it. |
| Script says unsupported OS or no terminal | Check /etc/os-release and architecture. Use the manual route for that OS. Helltube needs systemd and a controlling SSH terminal; reconnect with ssh -t. |
| Mumble connects but audio stutters or never arrives | Check mute/input/PTT first, then UDP 64738 in every firewall/NAT layer. Confirm DNS-only records. Examine loss/jitter and CPU load during encodes. |
| Mumble container restarts | Inspect Compose logs; check port conflicts, data ownership and SELinux labeling. Verify the pinned image can be pulled for your CPU. |
| 502 Bad Gateway | Probe 127.0.0.1:3000/api/health on the host. If it fails, inspect helltube.service, Node path, env/data permissions and native worker dependencies. If it works, inspect proxy upstream/SELinux. |
| Certificate issuance fails | Check A/AAAA, public routing, CAA records, challenge method, DNS-token scope and system time. Avoid repeatedly hitting production ACME rate limits; fix the cause first. |
| Login loops or 403 Origin errors | Use HTTPS; match ALLOWED_ORIGINS exactly, preserve Origin/cookies, and check TRUST_PROXY. Enter the intended Helltube URL in Strife. Do not weaken TLS or SameSite as a first fix. |
| Page loads, queue changes don't arrive | Check WSS upgrade (101), nginx upgrade headers and proxy timeouts. A static HTML response does not establish a working WebSocket. |
| Video buffers; voice also suffers | Measure FFmpeg speed, CPU contention, RAM/swap and egress. Lower concurrency/bitrate or move video to a larger/separate host. |
| Upload returns 413 / fails midway | Check per-request proxy limits, app storage/user quotas, disk space and chunk routing. Do not confuse per-chunk size with total file size. |
| Desktop share starts but viewers see nothing | Check announced public address, bind interface, 44444 UDP/TCP and NAT. Test from another network, then TURN. HTTPS proxy success is not media success. |
| One remote media provider fails | Check current yt-dlp/FFmpeg, source availability and upstream logs. Optional cookies/VPN are separate operational features; protect any imported account sessions. |
| Works until reboot | Check enabled Docker/Helltube/proxy services, persistent mounts and boot ordering. Re-test recovery before inviting everyone back. |
Recover an interrupted Mumble bootstrap
The script deliberately refuses to overwrite
/opt/strife-mumble. Inspect it first. If Compose and
the password file were written, fix the reported error and resume
with the commands below. The directory should remain root-owned
and private. Never run a fresh bootstrap over existing data to
“fix” a password problem.
sudo docker compose --project-directory /opt/strife-mumble config --quiet
sudo docker compose --project-directory /opt/strife-mumble up -d
sudo docker compose --project-directory /opt/strife-mumble logs --tail=100
sudo docker compose --project-directory /opt/strife-mumble ps
If initialization failed before creating a usable Compose file, verify no strife-mumble container is running, then preserve the incomplete directory under a clearly named backup path and rerun. Review exactly what exists before moving anything. If there is a working database, use the recovery/backup route instead of regenerating credentials.
Recover Helltube
The launcher removes only its private temporary source download; upstream-created app data/config remain. Read the installer error and service journal. Save modified environment/proxy files before rerunning the pinned installer because it replaces managed configuration. Restore a matched source/data backup if a deployment changed the database incompatibly. Confirm services after recovery; a successful installer exit does not replace your external media test.
Stop or retire the installation without deleting the wrong thing
# Stops/removes this Compose project's containers; bind-mounted data remains:
sudo docker compose --project-directory /opt/strife-mumble down
# Stops Helltube and prevents boot startup; application data remains:
sudo systemctl disable --now helltube
# Managed install only, if its optional updater was enabled:
sudo systemctl disable --now helltube-update.timer helltube-update.path
Then remove only this site's proxy block, validate/reload the shared proxy, and close its provider/host firewall rules. Archive verified data/config before any permanent removal. Revoke dedicated DNS/edge/TURN credentials when no other service uses them. Release DNS records and provider resources deliberately; stopping an app does not stop VPS, disk, snapshot or reserved-IP billing. Do not disable a shared proxy or renewal service used by other sites.
20 / Sources, versions, and limits
The application details here follow Strife's source and connection guide and the pinned Helltube checkout. External package repositories, cloud offerings and media providers change; check the linked upstream documentation before a later deployment. Hardware sizing is an estimate and needs workload measurement.
The scripts are checked for Bash syntax, installation boundaries and failure behavior, and the website is checked for links, downloads and accessibility. They do not constitute a live deployment certification for every OS/provider combination. In particular, real DNS issuance, public firewall behavior, native media processing, OS microphone permissions and TURN require testing on your infrastructure. Manual Fedora and native Windows/macOS hosting have additional platform-specific dependencies.
For a website/wiki/script problem, open an issue in strife-web. For the desktop use Strife issues; for video service behavior use Helltube issues. Include versions, OS/architecture, the failing step, expected behavior and redacted logs. Exclude credential files, cookie exports and private keys.