Since: 0.18.0
TL;DR โ
Phlix needs three things to survive a disaster: the database (users, watch history, library metadata), config files (JWT secret, DB credentials, server settings), and metadata images (posters, fanart). You do NOT need to back up the transcode cache, active job state, or scan cache โ these are regenerated automatically. Back up regularly (daily is recommended), store off-site, and test restores quarterly.
1. What to Back Up โ
1. Database โ
What: All Phlix data โ users, watch history, media library metadata, playback state, sessions.
mysqldump -u phlix -p phlix_db > phlix-db-$(date +%Y%m%d).sqlFor MariaDB the command is identical. Verify the dump is valid:
# Check the dump starts correctly
head -5 phlix-db-20250601.sql
# Should show: -- MySQL dump 10.x ... or -- MariaDB dump ...2. Config Files โ
What: config/ directory โ server.php, database.php, ffmpeg.php, backups.php (if present). These contain your JWT_SECRET, DB credentials, and all server settings.
tar czf phlix-config-$(date +%Y%m%d).tar.gz -C /path/to/phlix config/3. Metadata Images โ
What: data/metadata/ โ poster.jpg, fanart.jpg, and all artwork downloaded from TMDB/TVDB. These are not stored in the DB; they live on disk.
tar czf phlix-metadata-images-$(date +%Y%m%d).tar.gz -C /path/to/phlix data/metadata/These can be re-downloaded by re-scanning your library, but re-downloading from TMDB/TVDB takes significant time and may hit rate limits. A local backup is much faster to restore.
4. Plugin Configs โ
What: data/plugins/ if you have custom plugins installed that store configuration on disk.
tar czf phlix-plugins-$(date +%Y%m%d).tar.gz -C /path/to/phlix data/plugins/5. TLS Certificates โ
What: config/ssl/ for self-hosted deployments using custom HTTPS certificates.
NOT Needed โ
| What | Why |
|---|---|
data/transcode/* | Regenerated on next transcode |
| Active transcode job state | Lost on crash, not recoverable |
| Scan cache | Regenerated on library rescan |
*.log files | Regenerated by the logging system |
2. Backup Methods โ
2.1 Manual Backup (CLI) โ
# Database
mysqldump -u phlix -p phlix_db > phlix-db-$(date +%Y%m%d).sql
# Full tarball โ everything that matters (excluding transcode and logs)
tar czf phlix-backup-$(date +%Y%m%d).tar.gz \
-C /path/to/phlix \
config/ data/metadata/ data/plugins/ \
--exclude='data/transcode/*' \
--exclude='*.log'2.2 Built-in Backup Manager โ
Phlix ships a BackupManager (src/Admin/BackupManager.php) that packages the MySQL dump, config/*.php, the data/ directory, and SSL certificates into a single tar.gz, with optional S3 upload and retention cleanup. There is no admin CLI command for this yet โ backups are driven by configuration: set auto_backup_interval_days and retention_count in config/backup.php and the server creates and prunes backups automatically. See Backup for the full configuration reference (local path, S3 credentials, retention).
For an on-demand backup without the manager, use the manual tarball shown in ยง2.1 above.
2.3 Automated (Cron / systemd timer) โ
If you prefer OS-level scheduling over the built-in interval, run the manual backup from cron:
# /etc/cron.d/phlix-backup โ daily at 03:00
0 3 * * * root /usr/bin/mysqldump -u phlix -pYOURPASS phlix_db \
> /backups/phlix-db-$(date +\%Y\%m\%d).sql && \
/usr/bin/tar czf /backups/phlix-$(date +\%Y\%m\%d).tar.gz \
-C /path/to/phlix config/ data/metadata/ data/plugins/ \
--exclude='data/transcode/*' --exclude='*.log' && \
/usr/bin/find /backups -name 'phlix-*' -mtime +7 -deleteThis creates a daily backup and removes backups older than 7 days. Adjust -mtime +7 to retain more or fewer days.
For systemd instead of cron:
# /etc/systemd/system/phlix-backup.timer
[Unit]
Description=Daily Phlix backup
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target2.4 Third-Party Tools (Restic / Borg / rsync) โ
Wrap the tarball or point rsync/restic directly at the above paths:
# Restic โ backup to S3/B2/NAS
restic -r s3:s3.amazonaws.com/bucket/phlix-backups \
backup /path/to/phlix/config /path/to/phlix/data/metadata
# rsync to NAS
rsync -avz --exclude='data/transcode' --exclude='*.log' \
/path/to/phlix/ backup-server:/backups/phlix/For off-site copies:
rclone copy phlix-backup-$(date +%Y%m%d).tar.gz b2:my-bucket/phlix/3. Restore Process โ
Critical: Always restore the database and config from the same backup point. Mixing configs from different points can cause JWT_SECRET mismatches (see Failure 2 below).
Step-by-step โ
- Stop Phlix
systemctl stop phlix
# or, if running in the foreground, stop the `php public/index.php` process (Ctrl+C)- Restore database
mysql -u phlix -p phlix_db < phlix-db-20250601.sql- Restore config and data
tar -xzf phlix-backup-20250601.tar.gz -C /
# Verify paths match your installation
ls /path/to/phlix/config/
ls /path/to/phlix/data/metadata/- Start Phlix
systemctl start phlix
# or, for development, run in the foreground:
php public/index.php- Verify
Log in, check your library items are visible, confirm watch history is present. If metadata images are missing, trigger a full library rescan from the admin UI, or via the API:
curl -X POST http://localhost:32400/api/v1/libraries/{id}/rescan \
-H "Authorization: Bearer $TOKEN"4. Docker / docker-compose Backup โ
Using docker compose exec โ
# Inside the container โ dump the DB and tar the data, landing in a mounted volume
docker compose exec phlix-server sh -c \
'mysqldump -u phlix -pYOURPASS phlix_db > /backups/phlix-db-$(date +%Y%m%d).sql && \
tar czf /backups/phlix-$(date +%Y%m%d).tar.gz -C /app config/ data/metadata/ data/plugins/ \
--exclude="data/transcode/*" --exclude="*.log"'
# Copy the backup out of the container
docker compose cp phlix-server:/backups/phlix-20250601.tar.gz ./phlix-backup-20250601.tar.gzBacking up named volumes directly โ
# Backup the named volumes directly (does not need Phlix running)
docker run --rm \
-v phlix_data:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/phlix_data.tar.gz -C /data .Restoring Docker volumes โ
# Restore
docker run --rm \
-v phlix_data:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/phlix_data.tar.gz -C /data
# Restart Phlix
docker compose up -d phlix-server5. What Can Go Wrong โ
Failure 1 โ Corrupt or Incomplete Backup โ
Symptom: Restore succeeds but some tables are empty or SQL errors on import.
Fix: Always verify checksums after backup:
sha256sum phlix-backup-20250601.tar.gz
# Store the checksum alongside the backup or in a separate logTest restores periodically (e.g., monthly) in a staging environment. A backup that was never tested is not a reliable backup.
Failure 2 โ JWT Secret Mismatch (Users Can't Log In) โ
Symptom: Database restored, but all login attempts fail with auth errors.
Cause: JWT_SECRET in config/server.php was not restored, or the backup config used a different secret than the one the server is currently using.
Fix: Restore config/server.php from the same backup as the database. Never rotate JWT_SECRET without also backing up the old value and all existing refresh tokens (stored hashed in the DB).
# Verify JWT_SECRET is consistent between backup and running config
grep JWT_SECRET /path/to/phlix/config/server.phpFailure 3 โ Media Not Re-Scanning After Restore (Stale mtime) โ
Symptom: Library shows items but poster/fanart missing; rescan doesn't re-download metadata.
Cause: FolderWatcher uses mtime as its checksum. If the backup was restored to the same filesystem paths, mtimes are preserved and the watcher sees "no change."
Fix: Force a full rescan after restore from the admin UI or the API:
curl -X POST http://localhost:32400/api/v1/libraries/{id}/rescan \
-H "Authorization: Bearer $TOKEN"
# OR touch all media files to update mtime, then rescan
find /path/to/media -type f -exec touch {} \;Failure 4 โ Backup Too Large (Transcode Cache Included) โ
Symptom: Backups are 50 GB+, slow to transfer, fill up backup storage.
Cause: data/transcode/ directory included in tarball.
Fix: Always exclude data/transcode/* from tar commands:
tar czf phlix-backup-$(date +%Y%m%d).tar.gz \
-C /path/to/phlix \
config/ data/metadata/ data/plugins/ \
--exclude='data/transcode/*' \
--exclude='*.log'Active transcode job state is not recoverable anyway โ excluding it saves space with zero data loss.
6. Next Steps โ
- Troubleshooting โ general recovery help if restore has unexpected issues, including reading server logs in
.logs/ - Reverse proxy โ verify your server is correctly exposed after restore
- Consider setting up monitoring/alerting on backup job success/failure (e.g., check your cron/timer exit status, or the
backupstable for recent successful entries)