Version: 1.0
Last Updated: October 20, 2025
TrueNAS Version: 25.04.2.4
Deployment Type: Docker Compose Custom App
- Overview
- Prerequisites
- Architecture
- Step 1: Prepare TrueNAS Environment
- Step 2: Build and Publish Docker Images
- Step 3: Deploy Application
- Step 4: Verify Deployment
- Step 5: Access Application
- Maintenance
- Troubleshooting
- Backup and Recovery
- Upgrading
This guide walks through deploying RehearseKit on TrueNAS SCALE 25.04+ using Docker Compose. The deployment connects to your existing PostgreSQL database and stores audio files on TrueNAS datasets for reliability and easy backup.
- ✅ Physical access for debugging
- ✅ No cloud costs (vs. $200-400/month on GCP)
- ✅ ZFS storage for data integrity
- ✅ Existing infrastructure (PostgreSQL, networking)
- ✅ SMB/SSH access for management
- PostgreSQL: Use existing TrueNAS database (not containerized)
- Redis: Deploy in container (ephemeral cache)
- Storage: TrueNAS datasets mounted as volumes
- Services: Frontend, Backend, Worker, WebSocket (all containerized)
- TrueNAS SCALE 25.04.2.4 or later
- Docker/Kubernetes support enabled
- At least 20GB free storage for datasets
- 8GB+ RAM available for containers
- 4+ CPU cores recommended
- ✅ PostgreSQL database accessible via TCP/IP
- ✅ Network connectivity to TrueNAS
- ✅ SSH/SMB access to TrueNAS
- Docker Hub account (for storing images)
- GitHub account (for building images via Actions)
- Git installed on development machine
- Python 3.11+ (for development/testing)
- Node.js 20+ (for development/testing)
- Docker 24+ (for local testing)
┌─────────────────────────────────────────────────────────────────┐
│ TrueNAS SCALE │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Docker Compose Stack (rehearsekit) │ │
│ │ │ │
│ │ ┌───────────┐ ┌──────────┐ ┌───────────┐ │ │
│ │ │ Frontend │ │ Backend │ │ WebSocket │ │ │
│ │ │ (Next.js) │ │ (FastAPI)│ │ (FastAPI)│ │ │
│ │ │ :3000 │ │ :8000 │ │ :8001 │ │ │
│ │ └─────┬─────┘ └────┬─────┘ └─────┬─────┘ │ │
│ │ │ │ │ │ │
│ │ └──────┬──────┴───────┬───────┘ │ │
│ │ │ │ │ │
│ │ ┌──────▼──────┐ ┌────▼─────┐ │ │
│ │ │ Worker │ │ Redis │ │ │
│ │ │ (Celery) │ │ :6379 │ │ │
│ │ └──────┬──────┘ └────┬─────┘ │ │
│ │ │ │ │ │
│ └───────────────┼──────────────┼─────────────────────────┘ │
│ │ │ │
│ ┌────────▼──────────────▼─────┐ │
│ │ Redis Data Volume │ │
│ │ /mnt/tank/apps/.../redis │ │
│ └─────────────────────────────┘ │
│ │ │
│ ┌────────▼──────────────────────┐ │
│ │ Storage Volume (ZFS Dataset) │ │
│ │ /mnt/tank/apps/.../storage │ │
│ │ - uploads/ │ │
│ │ - stems/ │ │
│ │ - packages/ │ │
│ └───────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Existing PostgreSQL (Not Containerized) │ │
│ │ postgresql://rehearsekit:***@IP:5432 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────▼─────────┐
│ Docker Hub │
│ (Image Registry)│
└───────────────────┘
SSH into your TrueNAS server:
ssh admin@<truenas-ip>Create datasets for RehearseKit:
# Navigate to your apps pool (adjust 'tank' to your pool name)
cd /mnt/tank
# Create base directory
sudo mkdir -p apps/rehearsekit
# Create datasets
sudo zfs create tank/apps/rehearsekit/storage
sudo zfs create tank/apps/rehearsekit/redis
# Set permissions
# 1000:1000 is the default user:group in backend/worker containers
sudo chown -R 1000:1000 /mnt/tank/apps/rehearsekit/storage
# 999:999 is the default redis user:group
sudo chown -R 999:999 /mnt/tank/apps/rehearsekit/redis
# Verify creation
zfs list | grep rehearsekitExpected output:
tank/apps/rehearsekit/storage 96K 500G 96K /mnt/tank/apps/rehearsekit/storage
tank/apps/rehearsekit/redis 96K 500G 96K /mnt/tank/apps/rehearsekit/redis
If PostgreSQL is already running on TrueNAS:
# Connect to PostgreSQL
sudo -u postgres psql
# Create database and user
CREATE DATABASE rehearsekit;
CREATE USER rehearsekit WITH PASSWORD 'YOUR_SECURE_PASSWORD_HERE';
GRANT ALL PRIVILEGES ON DATABASE rehearsekit TO rehearsekit;
# Exit psql
\qIf you need to install PostgreSQL:
# Install via pkg (if not using containers)
sudo pkg install postgresql16-server postgresql16-client
# Or deploy PostgreSQL as a separate container/app
# (See TrueNAS app catalog for PostgreSQL)Test connectivity from TrueNAS:
psql -h <postgres-host> -U rehearsekit -d rehearsekit -c "SELECT version();"Note the connection details:
- Host:
<postgres-host-ip>(e.g., 192.168.1.100) - Port:
5432(default) - Database:
rehearsekit - User:
rehearsekit - Password:
<your-password>
Create a directory for deployment files:
sudo mkdir -p /mnt/tank/apps/rehearsekit/config
cd /mnt/tank/apps/rehearsekit/config- Create a Docker Hub account: https://hub.docker.com/signup
- Create an access token:
- Go to Account Settings → Security → Access Tokens
- Click "New Access Token"
- Name:
rehearsekit-github-actions - Permissions: Read, Write, Delete
- Save the token (you won't see it again!)
In your GitHub repository:
- Go to Settings → Secrets and variables → Actions
- Add the following secrets:
DOCKERHUB_USERNAME: Your Docker Hub usernameDOCKERHUB_TOKEN: The access token from step 2.1
The images build automatically when you push to the main branch:
# From your local development machine
git add .
git commit -m "Prepare for TrueNAS deployment"
git push origin mainMonitor the build:
- Go to your GitHub repository
- Click "Actions" tab
- Watch "Build and Push Docker Images" workflow
Trigger the workflow manually:
- Go to GitHub repository → Actions
- Select "Build and Push Docker Images"
- Click "Run workflow"
- Choose branch:
main - Enter tag (or leave as
latest) - Click "Run workflow"
After the build completes (5-10 minutes), verify on Docker Hub:
https://hub.docker.com/u/<your-username>/repositories
You should see:
<your-username>/rehearsekit-backend:latest<your-username>/rehearsekit-frontend:latest<your-username>/rehearsekit-websocket:latest
Before deploying to TrueNAS, test locally:
# Pull images
docker pull <your-username>/rehearsekit-backend:latest
docker pull <your-username>/rehearsekit-frontend:latest
docker pull <your-username>/rehearsekit-websocket:latest
# Test backend
docker run --rm <your-username>/rehearsekit-backend:latest python -c "import app; print('OK')"From your development machine:
# Clone repository (if not already)
git clone https://github.com/<your-org>/RehearseKit.git
cd RehearseKit
# Copy deployment files to TrueNAS via SCP
scp infrastructure/truenas/docker-compose.truenas.yml admin@<truenas-ip>:/mnt/tank/apps/rehearsekit/config/docker-compose.yml
scp infrastructure/truenas/env.example admin@<truenas-ip>:/mnt/tank/apps/rehearsekit/config/env.exampleAlternatively, use SMB:
- Mount TrueNAS SMB share
- Navigate to
apps/rehearsekit/config/ - Copy files directly
SSH into TrueNAS:
ssh admin@<truenas-ip>
cd /mnt/tank/apps/rehearsekit/configCreate .env file:
cp env.example .env
nano .env # or vi, emacs, etc.Fill in your values:
# Docker Registry
DOCKER_REGISTRY=docker.io
DOCKER_USERNAME=your-dockerhub-username
IMAGE_TAG=latest
# Network
TRUENAS_IP=192.168.1.100 # Your TrueNAS IP
FRONTEND_PORT=3000
BACKEND_PORT=8000
WEBSOCKET_PORT=8001
REDIS_PORT=6379
# Database (from Step 1.2)
DATABASE_URL=postgresql+asyncpg://rehearsekit:YOUR_PASSWORD@192.168.1.100:5432/rehearsekit
# Application URLs
API_URL=http://192.168.1.100:8000
WS_URL=ws://192.168.1.100:8001
# Storage Paths (from Step 1.1)
STORAGE_PATH=/mnt/tank/apps/rehearsekit/storage
REDIS_DATA_PATH=/mnt/tank/apps/rehearsekit/redisSecurity Tip: Restrict permissions on .env:
chmod 600 .envStill in /mnt/tank/apps/rehearsekit/config/:
# Pull latest images
docker-compose pull
# Start services
docker-compose up -d
# Verify containers started
docker-compose psExpected output:
NAME IMAGE STATUS
rehearsekit-backend your-user/rehearsekit-backend:latest Up
rehearsekit-frontend your-user/rehearsekit-frontend:latest Up
rehearsekit-websocket your-user/rehearsekit-websocket:latest Up
rehearsekit-worker your-user/rehearsekit-backend:latest Up
rehearsekit-redis redis:7-alpine Up
Monitor startup logs:
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f backend
# Last 50 lines
docker-compose logs --tail=50 workerLook for:
- ✅
Backend services are healthy - ✅
Connected to database - ✅
Celery worker ready - ❌ Any errors or stack traces
Test backend health:
curl http://localhost:8000/api/healthExpected response:
{
"status": "healthy",
"database": "healthy",
"redis": "healthy"
}Test frontend:
curl -I http://localhost:3000Should return HTTP/1.1 200 OK.
Check if database tables were created:
psql -h localhost -U rehearsekit -d rehearsekit -c "\dt"Expected tables:
Schema | Name | Type | Owner
--------+-----------------+-------+------------
public | alembic_version | table | rehearsekit
public | jobs | table | rehearsekit
If tables are missing, run migrations manually:
# Enter backend container
docker exec -it rehearsekit-backend /bin/bash
# Run migrations
alembic upgrade head
# Exit container
exitCreate a test job via API:
curl -X POST http://localhost:8000/api/jobs/create \
-F "project_name=Test Job" \
-F "quality_mode=fast" \
-F "input_url=https://www.youtube.com/watch?v=jNQXAC9IVRw"Check response for job ID, then monitor:
# Watch worker logs
docker-compose logs -f workerYou should see processing stages: CONVERTING → ANALYZING → SEPARATING → COMPLETED
From any device on the same network:
http://<truenas-ip>:3000
Example: http://192.168.1.100:3000
Configure your router to forward port 3000 to TrueNAS:
- External Port: 3000
- Internal IP:
<truenas-ip> - Internal Port: 3000
Access via: http://<your-public-ip>:3000
Security Warning: Exposes application to internet. Use firewall rules.
Set up Nginx on TrueNAS or separate server:
# /etc/nginx/sites-available/rehearsekit
server {
listen 80;
server_name rehearsekit.yourdomain.com;
location / {
proxy_pass http://<truenas-ip>:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /api {
proxy_pass http://<truenas-ip>:8000;
proxy_set_header Host $host;
}
location /ws {
proxy_pass http://<truenas-ip>:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Add SSL with Let's Encrypt:
sudo certbot --nginx -d rehearsekit.yourdomain.comUse mesh VPN for secure remote access without port forwarding.
cd /mnt/tank/apps/rehearsekit/config
docker-compose ps# Restart all
docker-compose restart
# Restart specific service
docker-compose restart worker# Continuous logs
docker-compose logs -f
# Last 100 lines
docker-compose logs --tail=100
# Specific service
docker-compose logs -f backenddocker statsShows CPU, memory, network usage.
# Check dataset usage
zfs list | grep rehearsekit
# Check storage contents
du -sh /mnt/tank/apps/rehearsekit/storage/*Jobs accumulate over time. Clean up manually or create a cron job:
# List old jobs (>7 days)
find /mnt/tank/apps/rehearsekit/storage/uploads -type f -mtime +7
# Delete old jobs
find /mnt/tank/apps/rehearsekit/storage/uploads -type f -mtime +7 -delete
find /mnt/tank/apps/rehearsekit/storage/stems -type d -mtime +7 -exec rm -rf {} +
find /mnt/tank/apps/rehearsekit/storage/packages -type f -mtime +7 -deleteAutomated cleanup (cron):
# Edit crontab
crontab -e
# Add daily cleanup at 3 AM
0 3 * * * find /mnt/tank/apps/rehearsekit/storage/uploads -type f -mtime +7 -delete
0 3 * * * find /mnt/tank/apps/rehearsekit/storage/packages -type f -mtime +7 -deleteSymptom: docker-compose ps shows container with status "Exited (1)"
Diagnosis:
docker-compose logs <service-name>Common Causes:
-
Database connection failed
- Check
DATABASE_URLin.env - Verify PostgreSQL is running:
pg_isready -h <db-host> - Check firewall:
telnet <db-host> 5432
- Check
-
Missing environment variable
- Review
.envfile for typos - Restart after changes:
docker-compose up -d
- Review
-
Port conflict
- Check if port already in use:
netstat -tulpn | grep <port> - Change port in
.env
- Check if port already in use:
Symptom: Jobs stuck in PENDING status
Diagnosis:
# Check worker logs
docker-compose logs -f worker
# Check Celery connection to Redis
docker exec -it rehearsekit-worker celery -A app.celery_app inspect pingSolutions:
-
Restart worker:
docker-compose restart worker
-
Check Redis connectivity:
docker exec -it rehearsekit-redis redis-cli ping # Should return: PONG
-
Purge task queue:
docker exec -it rehearsekit-worker celery -A app.celery_app purge
Symptom: Frontend loads but shows "Cannot connect to backend"
Diagnosis:
# Test from TrueNAS
curl http://localhost:8000/api/health
# Test from frontend container
docker exec -it rehearsekit-frontend curl http://backend:8000/api/healthSolutions:
-
Check API_URL in .env:
- Must be accessible from browser (not from container)
- Use TrueNAS IP, not
localhostor container name
-
Verify backend is running:
docker-compose ps backend
-
Check CORS settings:
- Backend logs should not show CORS errors
- Update
CORS_ORIGINSin backend environment
Symptom: Jobs fail with "Permission denied" when writing files
Diagnosis:
# Check ownership
ls -la /mnt/tank/apps/rehearsekit/storage/
# Check from container
docker exec -it rehearsekit-backend ls -la /mnt/storage/rehearsekit/Solution:
# Fix permissions
sudo chown -R 1000:1000 /mnt/tank/apps/rehearsekit/storage/
sudo chmod -R 755 /mnt/tank/apps/rehearsekit/storage/
# Restart services
docker-compose restartSymptom: Progress updates stop after a few seconds
Solutions:
-
Check WebSocket service logs:
docker-compose logs -f websocket
-
Verify WS_URL in .env:
- Use
ws://(nothttp://) - Use TrueNAS IP (not localhost)
- Use
-
Test WebSocket connection:
# Install wscat npm install -g wscat # Test connection wscat -c ws://<truenas-ip>:8001/ws/jobs/<job-id>
# Manual backup
pg_dump -h <db-host> -U rehearsekit rehearsekit > /mnt/tank/backups/rehearsekit-db-$(date +%Y%m%d).sql
# Automated daily backup (cron)
0 2 * * * pg_dump -h localhost -U rehearsekit rehearsekit > /mnt/tank/backups/rehearsekit-db-$(date +\%Y\%m\%d).sql# Create snapshot
sudo zfs snapshot tank/apps/rehearsekit/storage@$(date +%Y%m%d)
# List snapshots
zfs list -t snapshot | grep rehearsekit
# Automated snapshots (TrueNAS periodic snapshot task)
# Go to: Data Protection → Periodic Snapshot Tasks → Add# Backup .env and docker-compose.yml
tar -czf /mnt/tank/backups/rehearsekit-config-$(date +%Y%m%d).tar.gz \
-C /mnt/tank/apps/rehearsekit/config .# Drop existing database (if needed)
psql -h <db-host> -U postgres -c "DROP DATABASE rehearsekit;"
psql -h <db-host> -U postgres -c "CREATE DATABASE rehearsekit OWNER rehearsekit;"
# Restore from backup
psql -h <db-host> -U rehearsekit rehearsekit < /mnt/tank/backups/rehearsekit-db-20251020.sql# Rollback to snapshot
sudo zfs rollback tank/apps/rehearsekit/storage@20251020
# Or clone snapshot
sudo zfs clone tank/apps/rehearsekit/storage@20251020 tank/apps/rehearsekit/storage-restoredcd /mnt/tank/apps/rehearsekit/config
tar -xzf /mnt/tank/backups/rehearsekit-config-20251020.tar.gz-
Pull new code:
cd ~/RehearseKit git pull origin main
-
Build new images (via GitHub Actions)
- Push to main, or manually trigger workflow
-
On TrueNAS, pull new images:
cd /mnt/tank/apps/rehearsekit/config docker-compose pull -
Stop services:
docker-compose down
-
Run database migrations (if needed):
docker-compose run --rm backend alembic upgrade head
-
Start services:
docker-compose up -d
-
Verify:
docker-compose ps docker-compose logs -f curl http://localhost:8000/api/health
If upgrade fails:
# Use previous image tag
nano .env
# Change: IMAGE_TAG=previous-version
# Pull old images
docker-compose pull
# Restart
docker-compose up -dAfter successful deployment:
- ✅ Test complete workflow: Upload → Process → Download
- ✅ Set up automated backups (database + ZFS snapshots)
- ✅ Configure monitoring (optional: Grafana + Prometheus)
- ✅ Set up job cleanup cron (prevent storage bloat)
- ✅ Document your specific configuration (IPs, credentials, etc.)
- Documentation:
docs/directory - GitHub Issues: https://github.com//RehearseKit/issues
- Local logs:
docker-compose logs
Deployment Complete! 🎉
Your RehearseKit instance should now be running on TrueNAS SCALE.