Cutover and Validation
This is the final step — switching traffic from PeerTube to Vidra and confirming everything works. A well-planned cutover minimizes downtime and provides a clear rollback path.
Pre-Cutover Checklist
Before proceeding, verify all previous steps are complete:
- Database migration completed (API-driven or manual)
- Migration stats show acceptable success rates (check
failedcounts) - All media files copied to Vidra storage
- Media file counts match between source and destination
- Spot-check: at least 5 videos play correctly on Vidra
- Spot-check: thumbnails, avatars, and captions load
- PeerTube full backup exists and is verified (database + media)
- DNS TTL lowered to 60 seconds (done 24+ hours ago)
Cutover Sequence
Step 1: Put PeerTube in Maintenance Mode
Prevent new content from being created during the final sync:
# Option A: PeerTube maintenance mode (if available in your version)
# Edit production.yaml and restart
# maintenance:
# enabled: true
# Option B: Block write traffic at the reverse proxy
# Nginx example — allow only GET/HEAD, return 503 for writes
location /api/ {
if ($request_method !~ ^(GET|HEAD)$) {
return 503 "Instance is migrating to Vidra. Read-only mode.";
}
proxy_pass http://peertube:9000;
}
Step 2: Final Incremental Sync
Run one last data and media sync to capture any changes since the initial migration:
# Final database sync (API-driven)
# Start a new migration job — it will only import records newer than the last run
# Final media sync (rsync only transfers new/changed files)
rsync -avz --progress \
user@peertube-server:/var/www/peertube/storage/ \
/data/vidra/storage/
Step 3: Validate Vidra
Run the full validation suite before switching DNS:
# 1. Health check
curl http://your-vidra-host:8080/health
# Expected: 200 OK
# 2. Readiness check (verifies DB, Redis, storage)
curl http://your-vidra-host:8080/ready
# Expected: 200 OK
# 3. Auth flow
curl -X POST http://your-vidra-host:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "admin-password"}'
# Expected: 200 with access_token
# 4. Video listing
curl http://your-vidra-host:8080/api/v1/videos?count=5
# Expected: 200 with video objects
# 5. Channel listing
curl http://your-vidra-host:8080/api/v1/channels?count=5
# Expected: 200 with channel objects
# 6. Static file serving
curl -I http://your-vidra-host:8080/static/web-videos/{any-video-uuid}.mp4
# Expected: 200 OK
# 7. Federation discovery
curl http://your-vidra-host:8080/.well-known/nodeinfo
# Expected: 200 with nodeinfo links
curl http://your-vidra-host:8080/.well-known/webfinger?resource=acct:admin@your-domain.com
# Expected: 200 with webfinger response
# 8. Instance config
curl http://your-vidra-host:8080/api/v1/config
# Expected: 200 with instance configuration
Step 4: Switch DNS
Update your DNS records to point to the Vidra server:
# Example: Update A record
# peertube.example.com A → new-vidra-server-ip
# Or update reverse proxy upstream
# upstream backend {
# server vidra:8080; # Was: peertube:9000
# }
If using a reverse proxy (Nginx, Caddy, Traefik), update the upstream:
# /etc/nginx/sites-available/peertube.example.com
server {
listen 443 ssl;
server_name peertube.example.com;
location / {
proxy_pass http://vidra-server:8080; # Changed from peertube:9000
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support (for live chat)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Step 5: Verify Post-Cutover
Once DNS has propagated, verify through the public domain:
DOMAIN="peertube.example.com"
# API responds
curl -s "https://$DOMAIN/api/v1/config" | jq '.instance.name'
# Videos load
curl -s "https://$DOMAIN/api/v1/videos?count=1" | jq '.data[0].name'
# WebFinger works (critical for federation)
curl -s "https://$DOMAIN/.well-known/webfinger?resource=acct:admin@$DOMAIN"
# NodeInfo works
curl -s "https://$DOMAIN/.well-known/nodeinfo" | jq '.links[0].href'
# Static files serve
curl -I "https://$DOMAIN/static/web-videos/any-known-uuid.mp4"
# RSS feeds work
curl -s "https://$DOMAIN/feeds/videos.xml" | head -5
Post-Cutover Validation Checklist
Test these scenarios through the web UI or API:
User Flows
- User login works (note: users need to reset passwords)
- User profile page loads with correct avatar
- User can update their profile
- User can create a new video (tests full write path)
Content
- Video pages load with correct metadata
- Video playback works (web-video format)
- HLS adaptive streaming works (if using HLS)
- Thumbnails display correctly
- Captions/subtitles load and display
- Comments appear on video pages
- Comment threading (replies) works
Channels
- Channel pages load with correct info
- Channel video listings are correct
- Channel subscriptions are intact
Playlists
- Playlists load with correct items
- Playlist item order is preserved
- Playlist privacy settings are respected
Federation
- WebFinger returns correct actor URIs
- NodeInfo reports correct software name and version
- Remote instances can discover your instance
- ActivityPub inbox accepts activities
Admin
- Admin panel loads
- User management works
- Instance configuration is accessible
- Job queue is operational
Instance Configuration
After cutover, configure Vidra-specific settings that PeerTube didn't have:
# Set instance name and description
curl -X PUT http://localhost:8080/api/v1/admin/instance/config \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"instance": {
"name": "My Video Platform",
"description": "Powered by Vidra",
"terms": "...",
"contact": "admin@example.com"
}
}'
Optional: Enable Vidra-Only Features
These features extend beyond PeerTube and can be enabled after migration:
| Feature | Configuration | Documentation |
|---|---|---|
| IPFS Storage | IPFS_API_URL in .env | Architecture: Storage |
| IOTA Payments | ENABLE_IOTA=true in .env | Coming soon |
| ATProto/Bluesky | ATPROTO_PDS_HOST in .env | Coming soon |
| E2EE Messaging | Enabled by default | Coming soon |
Monitoring
Watch these metrics closely for the first 24-48 hours after cutover:
# Error rate in logs
docker compose logs -f vidra | grep -i error
# Health endpoint (set up monitoring)
curl http://localhost:8080/health
# Database connection pool
curl http://localhost:8080/metrics | grep db_pool
# Request latency
curl http://localhost:8080/metrics | grep http_request_duration
Rollback Plan
If critical issues are found after cutover:
Quick Rollback (DNS)
- Point DNS back to the PeerTube server
- Or revert the reverse proxy upstream configuration
- PeerTube should still be running with all original data
# Revert nginx upstream
# proxy_pass http://peertube-server:9000; # Revert to PeerTube
systemctl reload nginx
Full Rollback (if Vidra database was corrupted)
- Switch DNS/proxy back to PeerTube
- Drop Vidra's database and re-create from migrations
- Investigate the issue before retrying
# Reset Vidra database (destructive!)
dropdb vidra_prod
createdb vidra_prod
make migrate-up
When to Roll Back
Roll back if any of these are true:
- Video playback is broken for > 50% of content
- User authentication is completely non-functional
- Federation is broken and other instances can't discover you
- Data loss is detected (videos or users missing that were in PeerTube)
Do NOT roll back for:
- Minor styling differences (Vidra's API responses may differ slightly)
- Users needing to reset passwords (expected behavior)
- PeerTube plugins not working (not supported in Vidra)
After Successful Migration
Once you're confident the migration is stable:
- Notify users that the migration is complete and passwords need to be reset
- Raise DNS TTL back to normal (3600 seconds)
- Shut down PeerTube (but keep backups for 30+ days)
- Clean up staging resources (staging database, temporary files)
- Drop the PeerTube dump files from the Vidra server
- Enable Vidra-only features you want to use (IPFS, payments, etc.)
- Update federation peers — notify other instances of the platform change