Docker Deployment
Docker is the easiest and recommended way to deploy Rust-Srec.
Prerequisites
Quick Start
One-Line Install (Linux/macOS)
Run this command to automatically set up Rust-Srec:
curl -fsSL https://docs.srec.rs/docker-install.sh | bashOne-Line Install (Windows PowerShell)
irm https://docs.srec.rs/install.ps1 | iexThe scripts will:
- Download configuration files
- Generate secure secrets automatically
- Optionally start the application
Customizing Installation
The script auto-detects your system language. You can also customize the installation using environment variables:
Linux/macOS:
# Install dev version to custom directory
RUST_SREC_DIR=/opt/rust-srec VERSION=dev curl -fsSL https://docs.srec.rs/docker-install.sh | bashWindows PowerShell:
# Install dev version to custom directory
$env:RUST_SREC_DIR = "C:\rust-srec"; $env:VERSION = "dev"; irm https://docs.srec.rs/install.ps1 | iex| Variable | Description | Default |
|---|---|---|
SREC_LANG | Language (zh or en) | Auto-detect |
RUST_SREC_DIR | Installation directory | ./rust-srec |
VERSION | Docker image tag (latest or dev) | latest |
Manual Setup
Create a project directory:
bashmkdir rust-srec && cd rust-srecDownload the example configuration files:
Rename the files:
bash# On Linux/macOS mv docker-compose.example.yml docker-compose.yml mv .env.example .env # On Windows rename docker-compose.example.yml docker-compose.yml rename .env.example .envEdit
.env: Make sure to set a secureJWT_SECRETandSESSION_SECRET(at least 32 characters).
Security Note
You can generate a secure random string using:
- Linux/macOS:
openssl rand -hex 32 - Windows (PowerShell):
$bytes = New-Object Byte[] 32; [Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes); -join ($bytes | ForEach-Object { "{0:x2}" -f $_ })
- Start the application:bash
docker-compose up -d
Data Persistence
Ensure your DATA_DIR and OUTPUT_DIR are on a drive with sufficient space. Streaming recordings can consume disk space very quickly.
Configuration
The .env file contains all the necessary environment variables.
| Variable | Description |
|---|---|
JWT_SECRET | Secret key for JWT signing (Required) |
SESSION_SECRET | Secret for frontend session encryption (Required) |
Browser Notifications (Web Push)
To enable browser push notifications, generate VAPID keys and set them in .env:
docker run --rm ghcr.io/hua0512/rust-srec:latest /app/rust-srec-vapid
# or: npx --yes web-push generate-vapid-keys| Variable | Description |
|---|---|
WEB_PUSH_VAPID_PUBLIC_KEY | VAPID public key (base64url, unpadded) |
WEB_PUSH_VAPID_PRIVATE_KEY | VAPID private key (base64url, unpadded) |
WEB_PUSH_VAPID_SUBJECT | VAPID subject (e.g. mailto:admin@localhost) |
Note
Web Push requires HTTPS (or localhost).
Full Reference
For a complete list of all available environment variables and their descriptions, see the Environment Variables Reference.
docker-compose.yml
Our standard example includes:
- Automatic Restart:
unless-stopped - Healthchecks: Ensures the frontend only starts after the backend is ready
- Resource Limits: Configurable CPU and memory limits
- Log Rotation: Prevents logs from filling up your disk
Proxy Configuration
If you are behind a corporate proxy or in a region with restricted access, you can configure proxy settings for both the application and the download engines.
1. Configure Environment Variables
Add HTTP_PROXY and HTTPS_PROXY to your .env file:
# .env
HTTP_PROXY=http://your-proxy-host:port
HTTPS_PROXY=http://your-proxy-host:port
NO_PROXY=localhost,127.0.0.1,rust-srec2. Update docker-compose.yml
Ensure these variables are passed to the rust-srec service:
services:
rust-srec:
# ...
environment:
- HTTP_PROXY=${HTTP_PROXY:-}
- HTTPS_PROXY=${HTTPS_PROXY:-}
- NO_PROXY=${NO_PROXY:-}
# ...3. Enable in Application Settings
After starting the application, go to Global Settings > Downloader > Proxy:
- Enable Proxy.
- Check Use System Proxy.
- Save settings.
This will instruct the application and its engines (FFmpeg, Streamlink, Mesio) to respect the environment variables you configured.
GPU Hardware Acceleration (NVIDIA)
If you have an NVIDIA GPU, you can enable hardware-accelerated video transcoding (NVENC/NVDEC) to dramatically reduce CPU usage and speed up remuxing/transcoding.
Prerequisites
- NVIDIA GPU drivers installed on the host machine
- NVIDIA Container Toolkit installed on the host — this allows Docker containers to access the GPU:
- Installation Guide
- Quick install (Ubuntu/Debian):bash
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker
Enable GPU in docker-compose
Download the GPU compose override file alongside your docker-compose.yml:
Then start with both files:
docker compose -f docker-compose.yml -f docker-compose.gpu.yml up -dOr set COMPOSE_FILE in your .env so docker compose up -d picks it up automatically:
echo "COMPOSE_FILE=docker-compose.yml:docker-compose.gpu.yml" >> .envThe override file adds the NVIDIA device reservation:
services:
rust-srec:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu, video]Automatic Setup
If you use our one-line install script, it will automatically detect your NVIDIA GPU and offer to enable this for you.
Verify GPU Access
After starting the container, verify the GPU is accessible:
docker exec rust-srec nvidia-smiYou should see your GPU model and driver version. If you get an error, the NVIDIA Container Toolkit is not properly configured.
Enable in Application
Once the GPU is accessible to the container, go to your recording preset settings and enable Hardware Acceleration with the cuda device to use NVENC for encoding.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
Cannot load libnvcuvid.so.1 in ffmpeg logs | Container cannot access GPU drivers | Install NVIDIA Container Toolkit and restart Docker |
nvidia-smi not found inside container | Container Toolkit not configured | Run sudo nvidia-ctk runtime configure --runtime=docker && sudo systemctl restart docker |
| High CPU usage despite GPU enabled | Wrong encoder selected | Ensure the preset uses h264_nvenc or hevc_nvenc, not software encoders |
Failed to initialize NVML: Unknown Error after the container has been running for a while (and cu->cuInit(0) failed -> CUDA_ERROR_NO_DEVICE in pipeline logs) | Host systemd reloaded the device cgroup and silently dropped the container's GPU access — a known NVIDIA Container Toolkit issue on cgroup-v2 hosts. Often triggered by a Docker daemon reload, a package upgrade that touches systemd units, or nvidia-ctk reconfiguration. | Set no-cgroups = true in /etc/nvidia-container-runtime/config.toml and restart Docker, or switch Docker's cgroup driver to cgroupfs. As a quick recovery, docker restart rust-srec restores access. The gpu row on System Health turns red and you'll get a notification the moment the GPU becomes unavailable, so you don't need to find out from a failed remux job. |
Freeing up disk space when using bind mounts
Read this before using BaoTa, cPanel, or any other host-side file manager to clean up recordings.
Cleaning up recordings through the host filesystem on a directory that is bind-mounted into the rust-srec container can leave the container unable to write recordings until it is restarted — even though the host shows free space. This is a Linux VFS behavior, not a rust-srec bug. The workaround is simple once you know about it.
Safe cleanup paths (recommended)
In order of preference:
- Delete recordings through the rust-srec web UI. The app deletes files from inside the container via its own filesystem view — always safe, always correct.
docker exec -it <container> rm -rf /rec/<path>— operates inside the container's mount namespace, always safe.docker exec -it <container> shand clean up interactively.- Expand the underlying host volume (any method — cloud-disk resize, LVM extend, adding a new disk). Always safe.
Dangerous cleanup paths (causes "recordings don't resume after disk was cleared")
These are the patterns that trigger issue #508 and similar reports:
- Host-side
mv /host/rec /host/rec_backupor any rename of the mount source directory. - Host-side
rm -rf /host/recfollowed bymkdir /host/recto recreate it. The new directory is a different inode that the existing bind mount does NOT point at. - Using BaoTa (宝塔) panel's file manager default delete action on a directory that backs a Docker bind mount. BaoTa's "delete" is implemented as "move to trash", which is the same as pattern 1.
- Any GUI or CLI tool that implements "safe delete" by moving the target to a trash/backup directory.
Why it happens (short version)
Docker bind mounts are bound to an inode, not a path. When you rename or recreate the host directory, the inode underneath the container's /rec mount stays the same — but on most Linux filesystems (ext4, xfs), the kernel refuses to add new entries to a directory with nlink == 0 (which is what a "deleted but still-referenced" inode is). So create_dir_all returns ENOENT forever, even though the disk has plenty of free space. Only destroying and recreating the container's mount namespace (docker restart) fixes it.
How rust-srec detects and reports it
The output-root write gate catches this failure mode within one monitor tick and:
- Flips
output-rootin/healthtoDegradedwitherror_kind: not_foundand the path of the affected mount. - Emits exactly one critical
output_path_inaccessiblenotification through every enabled channel (Discord, Email, Telegram, Gotify, Webhook, Web Push). The text branches on the error kind — thenot_foundvariant includes the "restart the container" recovery instruction, translated if you setRUST_SREC_LOCALE=zh-CN. - Short-circuits subsequent download attempts at the filesystem boundary so the logs don't fill up with cascading retries and the DB outbox doesn't get churned.
- Transitions every affected streamer to the
OUT_OF_SPACEstate, visible in the streamer list.
After you docker restart the container, the gate reinitializes on boot (via a bounded 5-second startup probe). If the host path is fixed, the gate returns to Healthy and recordings resume on the next monitor tick.
If the error is actually disk-full (not stale mount)
If output-root in /health shows Degraded with error_kind: storage_full, no restart is needed. Free space via any of the safe cleanup paths above, and the gate will auto-recover within 30 seconds of the next attempted download — the recovery hook clears every affected streamer's backoff so the whole fleet resumes on the same monitor tick.
Multi-mount deployments: RUST_SREC_OUTPUT_ROOTS
The startup probe automatically discovers mount roots from every configuration layer — global, platform, template, and per-streamer output_folder settings. It merges the effective config for each streamer in parallel using the same caching path the runtime uses, deduplicates the resolved roots, and probes them concurrently at container boot. For the typical setup (one mount like /rec) this just works, and for heterogeneous layouts every mount any streamer could actually write to is preflighted from second zero.
You only need to set RUST_SREC_OUTPUT_ROOTS explicitly when:
- you want to probe mounts that aren't yet referenced by any streamer config (e.g. a new volume you plan to migrate to), or
- you want to override the resolution heuristic — for example, forcing a single
/recgate key on a/rec/{platform}/...layout to consolidate all platforms under one gate entry.
RUST_SREC_OUTPUT_ROOTS=/rec,/mnt/backup-slowValues are comma-separated absolute paths. See the configuration guide for details.
Accessing the Application
- Web Interface:
http://localhost:[FRONTEND_PORT](Default: http://localhost:15275) - API reference:
http://localhost:[API_PORT]/api/docs(Default: http://localhost:12555/api/docs)
Updating
To update to the latest version:
docker-compose pull
docker-compose up -d