A video streaming server that allows you to securely share your personal video library over the internet. Built with robust security, monitoring, and performance features.
- Multi-layer Authentication: HTTP Basic Auth + Session Management
- Path Traversal Protection: Prevents unauthorized file access
- Security Headers: XSS, SameSite cookie protection, clickjacking protection
- Rate Limiting: Configurable request throttling
- Security Audit Logging: Comprehensive security event tracking
- Session Management: Secure sessions with configurable timeouts
- Universal Format Support: MP4, MKV, AVI, MOV, WebM, M4V, FLV
- Subtitle Support: SRT and WebVTT (
.srt,.vtt) subtitle files - Audio Support: MP3, AAC, OGG, WAV
- Range Requests: Efficient streaming with seek support
- Mobile Optimized: Responsive design for all devices
- Health Check Endpoint: Real-time server status
- Performance Metrics: Request timing and throughput monitoring
- Comprehensive Logging: Application, security, error, and performance logs
- Multi-threaded: Configurable concurrency for high performance
- Resource Monitoring: CPU, memory, and disk snapshot logged at server startup (
log_system_info)
- Environment Configuration: Full environment variable support
- 90%+ Test Coverage: Comprehensive test suite with branch coverage and security tests
- Service Management: System service configurations β see Deployment Guide
- Log Rotation: Automatic log rotation and archival
- API Support: RESTful JSON API for integration
- Python: 3.12 or higher
- Operating System: Windows 10+, macOS 10.15+, or Linux (Ubuntu 20.04+ recommended)
- Memory: Minimum 2GB RAM, 4GB+ recommended for optimal performance
- Storage: 1GB for application, additional space for video content
- Network: Stable internet connection for remote access
Recommended β install from PyPI:
# Create virtual environment (recommended)
python -m venv venv
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
pip install mediarelayThat installs the mediarelay, mediarelay-config, mediarelay-genpass, and mediarelay-validate commands. No need to clone the repository.
Windows users can alternatively download a pre-built executable from GitHub Releases. Place a .env file in the same directory as MediaRelay.exe and run the executable.
From source (development or contributing):
git clone https://github.com/tboy1337/MediaRelay.git
cd MediaRelay
python -m venv venv
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
pip install -e ".[dev]"Use pip install -e . instead of pip install -e ".[dev]" if you only need the application without test and lint tools.
# Generate sample configuration
mediarelay-config
# Copy and edit configuration
copy .env.example .env # Windows
cp .env.example .env # Linux/macOS
# Edit .env with your settingsGenerate required security credentials:
# Generate Flask secret key and password hash
mediarelay-genpassThe script will:
- Ask for your preferred username (e.g.,
admin,user, etc.) - Generate or create your password:
- Choose 'y' to generate a secure 35-character password automatically
- Choose 'n' to enter your own password (minimum 12 characters)
- Generate a Flask secret key (for session security)
- Create a password hash (for secure authentication)
Example output:
============================================================
CONFIGURATION VALUES FOR .env FILE
============================================================
VIDEO_SERVER_SECRET_KEY=a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890
VIDEO_SERVER_USERNAME=admin
VIDEO_SERVER_PASSWORD_HASH=scrypt:32768:8:1$abc123$def456...
Important Security Notes:
- Save your password securely - you'll need it to log in to the web interface
- Copy all three generated values to your
.envfile immediately - Never share your secret key or password hash - treat them like private keys
- Regenerate credentials if you suspect they've been compromised
- The script uses cryptographically secure random generation for maximum security
# Start the server
mediarelay
# Or with custom configuration
mediarelay --host 0.0.0.0 --port 8080Once the server is running, you can access it in your web browser at:
- Local access: http://localhost:5000
- Network access: http://YOUR_IP_ADDRESS:5000 (if configured with --host 0.0.0.0)
-
Create your configuration file (if you do not already have
.env.examplefrom a source checkout, runmediarelay-configfirst):copy .env.example .env # Windows cp .env.example .env # Linux/macOS
-
Generate security credentials:
mediarelay-genpass
-
Update your
.envfile with the generated values:- Replace
VIDEO_SERVER_SECRET_KEY=your-secret-key-herewith your generated secret key - Replace
VIDEO_SERVER_USERNAME=tboy1337with your chosen username - Replace
VIDEO_SERVER_PASSWORD_HASH=your-password-hash-herewith your generated hash
- Replace
-
Configure other settings as needed (video directory, port, etc.)
-
Validate configuration before production deployment:
mediarelay-validate
Set
VIDEO_SERVER_PRODUCTION=trueand follow the full Deployment Guide pre-deploy checklist and SECURITY.md production requirements (unique username, absolute paths, TLS at reverse proxy, non-symlink media directory). -
Start the server (configuration is validated on startup):
mediarelay
See Configuration Reference for the complete list. Production-critical settings:
# Server Configuration
VIDEO_SERVER_HOST=0.0.0.0
VIDEO_SERVER_PORT=5000
VIDEO_SERVER_DIRECTORY=/path/to/videos
VIDEO_SERVER_THREADS=6
# Security (Required - Generate using mediarelay-genpass)
VIDEO_SERVER_USERNAME=your_username # Your chosen username
VIDEO_SERVER_PASSWORD_HASH=your_secure_hash # Generated password hash
VIDEO_SERVER_SECRET_KEY=your_secret_key # Generated Flask secret key
# Production mode (required for live deployment; enforces secure cookies and credential checks)
VIDEO_SERVER_PRODUCTION=true
VIDEO_SERVER_RATE_LIMIT=true # Required in production
# Reverse proxy (set true ONLY when behind a trusted reverse proxy)
VIDEO_SERVER_BEHIND_PROXY=false
VIDEO_SERVER_PROXY_TRUSTED=false # Required true with BEHIND_PROXY in production
# Optional monitoring token for detailed /health via X-Health-Token
# VIDEO_SERVER_HEALTH_TOKEN=
# Performance
VIDEO_SERVER_RATE_LIMIT_PER_MIN=60
VIDEO_SERVER_STREAM_RATE_LIMIT_PER_MINUTE=600
VIDEO_SERVER_SESSION_TIMEOUT=3600
VIDEO_SERVER_MAX_FILE_SIZE=21474836480 # 20GB default, set to 0 to disable
# Session Cookies (set Secure=true when serving over HTTPS)
VIDEO_SERVER_SESSION_COOKIE_SECURE=true
VIDEO_SERVER_SESSION_COOKIE_HTTPONLY=true
VIDEO_SERVER_SESSION_COOKIE_SAMESITE=Strict
# Account lockout (failed login protection)
VIDEO_SERVER_LOCKOUT_MAX_ATTEMPTS=5
VIDEO_SERVER_LOCKOUT_DURATION=900
# Logging
VIDEO_SERVER_LOG_LEVEL=INFO
VIDEO_SERVER_LOG_DIR=./logs
VIDEO_SERVER_LOG_CONSOLE=trueRun the full quality gate locally:
python scripts/verify.pyThis runs black, isort, mypy, bandit, pylint, pip-audit, and pytest with 90% branch coverage.
# Multi-layer authentication
HTTP_BASIC_AUTH + SESSION_MANAGEMENT + SAMESITE_COOKIESX-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
Strict-Transport-Security: max-age=31536000 # When VIDEO_SERVER_HSTS=true or VIDEO_SERVER_BEHIND_PROXY=true
Content-Security-Policy: default-src 'self'; media-src 'self'; style-src 'self' 'unsafe-inline'
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
X-Permitted-Cross-Domain-Policies: noneX-XSS-Protection is intentionally omitted (deprecated in modern browsers).
Set VIDEO_SERVER_BEHIND_PROXY=true and VIDEO_SERVER_PROXY_TRUSTED=true only when MediaRelay runs behind a trusted reverse proxy (nginx, Caddy, etc.) and is bound to localhost. Without PROXY_TRUSTED, client IP and rate limits use the direct connection address, not X-Forwarded-For. Direct internet exposure with proxy headers enabled allows IP spoofing. See SECURITY.md.
All security events are logged:
- Authentication attempts (success/failure)
- Path traversal attempts
- Rate limit violations
- File access attempts
- Account lockout events
Logout requires POST /logout with a CSRF token via the X-CSRF-Token header or csrf_token form field (see API documentation). GET /logout is rejected with 405 Method Not Allowed.
VIDEO_SERVER_HOST is validated at startup (must be a valid IP address or hostname).
- Multi-threading: Configurable worker threads
- Range Requests: Efficient video streaming
- HTTP Caching: Browser caching for static content
- Connection Pooling: Supports multiple users simultaneously
- Memory Management: Automatic resource cleanup
# Health check (no auth required)
GET /health
# Directory listing
GET /api/files?path=movies
# File streaming
GET /stream/path/to/video.mp4
# Web interface
GET /
GET /path/to/directory/import requests
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth('username', 'password')
# Get file listing
response = requests.get(
'http://localhost:5000/api/files',
auth=auth
)
files = response.json()
# Stream video
video_url = 'http://localhost:5000/stream/movie.mp4'
response = requests.get(video_url, auth=auth, stream=True)Server won't start: Check logs in logs/error.log
Authentication issues:
- Verify your
.envfile has all three security values frommediarelay-genpass - Ensure you're using the correct username and password you generated
- Regenerate credentials if needed:
mediarelay-genpassPerformance problems: Increase thread count (VIDEO_SERVER_THREADS) Network access: Check firewall and port forwarding Missing .env file: Copy.env.exampleto.envand configure
VIDEO_SERVER_DEBUG=true
VIDEO_SERVER_LOG_LEVEL=DEBUG
mediarelay- Documentation: docs/README.md
- Logs: Review application logs in
logs/ - Health Check:
curl http://localhost:5000/health - Security: SECURITY.md
- Issues: Create GitHub issue with logs and configuration
This project is licensed under the CRL License - see the LICENSE.md file for details.