A lightweight, production-ready video streaming platform for playing large remote video files (MKV/MP4) from CDN URLs. Features a modern OTT-style player with advanced controls, multi-audio/subtitle support, and instant progressive streaming.
- β HTTP Range request forwarding
- β CDN streaming proxy
- β Support for large files (multi-GB)
- β Automatic retry on timeout
- β Token expiry handling (401/403)
- β CORS enabled
- β Rate limiting protection
- β No transcoding overhead
- β Video.js based player
- β Instant playback with progressive streaming
- β 10-second skip forward/backward
- β Timeline scrubbing with preview
- β Multiple audio track switching
- β Subtitle track support
- β Quality selector (720p/1080p)
- β Playback speed control (0.25x - 2x)
- β Volume control with slider
- β Fullscreen support
- β Auto-resume from last position
- β Modern OTT-style dark UI
- β Keyboard shortcuts
- β Mobile responsive
Space/K- Play/Pauseβ- Rewind 10 secondsβ- Forward 10 secondsF- Toggle fullscreenM- Mute/Unmuteβ- Increase volumeβ- Decrease volume
User Browser
β
React Frontend (Video.js Player)
β
Node.js Express Proxy (HTTP Range forwarding)
β
CDN (Video Files)
Flow:
- User pastes CDN video URL
- Frontend requests video through proxy
- Proxy forwards Range requests to CDN
- Video streams directly to browser
- Player buffers and plays progressively
- Node.js 16+
- npm or yarn
- Modern web browser with HTML5 video support
cd video-streaming-systemcd backend
npm install
cp .env.example .env
npm startBackend will start on http://localhost:3001
cd frontend
npm install
cp .env.example .env
npm startFrontend will start on http://localhost:3000
Navigate to http://localhost:3000 and paste your video URL!
# Update system
sudo apt update && sudo apt upgrade -y
# Install Node.js (using NodeSource)
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt install -y nodejs
# Install Nginx
sudo apt install -y nginx
# Install PM2 (process manager)
sudo npm install -g pm2# On your local machine
scp -r video-streaming-system user@your-server-ip:/home/user/
# Or use git
ssh user@your-server-ip
cd /home/user
git clone your-repo-url video-streaming-systemcd /home/user/video-streaming-system/backend
npm install --production
cp .env.example .env
# Edit .env if needed
nano .env
# Start with PM2
pm2 start server.js --name video-proxy
pm2 save
pm2 startupcd /home/user/video-streaming-system/frontend
# Update proxy URL for production
echo "REACT_APP_PROXY_URL=http://your-server-ip:3001" > .env
npm install
npm run buildsudo nano /etc/nginx/sites-available/video-streamingAdd this configuration:
server {
listen 80;
server_name your-domain.com; # or your-server-ip
# Frontend (React build)
location / {
root /home/user/video-streaming-system/frontend/build;
try_files $uri $uri/ /index.html;
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
# Backend API proxy
location /stream {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# Important for streaming
proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 3600s;
proxy_connect_timeout 3600s;
proxy_send_timeout 3600s;
}
location /health {
proxy_pass http://localhost:3001;
}
}Enable the site:
sudo ln -s /etc/nginx/sites-available/video-streaming /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginxsudo ufw allow 'Nginx Full'
sudo ufw allow OpenSSH
sudo ufw enableVisit http://your-server-ip or http://your-domain.com
Create docker-compose.yml:
version: '3.8'
services:
backend:
build: ./backend
ports:
- "3001:3001"
environment:
- NODE_ENV=production
- PORT=3001
restart: unless-stopped
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
environment:
- REACT_APP_PROXY_URL=http://backend:3001
restart: unless-stoppedDeploy:
docker-compose up -dsudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.comCertbot will automatically configure SSL and update your Nginx config.
- Open the player in your browser
- Paste a direct CDN video URL (e.g.,
https://cdn.example.com/movie.mp4) - Click "Start Streaming"
- Video plays instantly with all controls
- Check "Add multiple quality sources"
- Enter URLs for different qualities:
- Main URL: Auto/Original
- 720p URL: Lower quality
- 1080p URL: High quality
- Use the quality selector during playback to switch
The player automatically saves your playback position every 5 seconds. When you reload the same URL, it will resume from where you left off.
If your CDN URL expires (403/401 error):
- Click "Change URL" button
- Paste a new/refreshed URL
- Player will resume from your last position
PORT=3001 # Server port
NODE_ENV=production # Environment modeREACT_APP_PROXY_URL=http://localhost:3001 # Backend proxy URL- Uses streaming (no full file buffering)
- Efficient HTTP Range forwarding
- Connection pooling for CDN requests
- Rate limiting to prevent abuse
- Lazy loading components
- Video.js optimized buffering
- LocalStorage for playback position
- Minimal re-renders with React hooks
Check:
- Is the URL a direct video file link?
- Does the URL support HTTP Range requests?
- Is CORS enabled on the CDN?
- Check browser console for errors
Test the proxy directly:
curl -I "http://localhost:3001/stream?url=YOUR_VIDEO_URL"Possible causes:
- CDN bandwidth limitations
- Large file size
- Network congestion
Solutions:
- Use a CDN with better bandwidth
- Enable lower quality sources
- Check your VPS network speed
This is normal for tokenized CDN links. Simply:
- Get a fresh URL
- Click "Change URL"
- Paste new URL
- Playback resumes automatically
MKV files:
- Audio tracks usually detected automatically
- Subtitle tracks depend on browser support
- Some formats may need conversion
MP4 files:
- Multiple audio tracks supported
- External subtitle files not currently supported
- Use embedded subtitles
Edit backend/server.js:
// Increase timeout for very large files
timeout: 60000, // 60 secondsAdd to frontend/src/components/VideoPlayer.jsx:
// After player initialization
vjsPlayer.somePlugin();Edit frontend/src/styles.css to customize colors, fonts, etc.
Stream video with Range support.
Query Parameters:
url(required): CDN video URL
Headers:
Range: Byte range (optional)
Response:
- Status: 200 (full file) or 206 (partial)
- Headers: Content-Type, Accept-Ranges, Content-Range
- Body: Video stream
Example:
curl "http://localhost:3001/stream?url=https://cdn.example.com/video.mp4" \
-H "Range: bytes=0-1023"Health check endpoint.
Response:
{
"status": "ok",
"timestamp": "2024-03-01T12:00:00.000Z"
}Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
MIT License - feel free to use for personal or commercial projects.
- Video.js - Excellent HTML5 video player
- Express.js - Fast Node.js framework
- React - UI library
- Axios - HTTP client
For issues and questions:
- Check troubleshooting section above
- Review browser console errors
- Ensure URLs are direct video links
- Test with sample videos first
Future enhancements:
- External subtitle file upload
- Video thumbnails preview on timeline
- Chromecast support
- Download option
- Playlist support
- Watch party mode
- Picture-in-picture
- Video filters/effects
Built with β€οΈ for seamless video streaming