c76853a442
- Fix: Atomic UPSERT for BaseItemProviders (resolves duplicate key errors during concurrent metadata refresh; clears navigation property to prevent EF Core tracking conflicts) - Add: Remote PostgreSQL backup support (removes localhost-only restriction; works with pg_dump/pg_restore for both local and remote DBs) - Add: Configurable backup disable option (`disable-backups`) - Fix: Query timeout and performance (documented `command-timeout` config, added performance index scripts) - Fix: Authentication errors now log as warnings with clear messages (ExceptionMiddleware), reducing log noise - Fix: SyncPlay authorization handler validates user before lookup, logs warnings for unauthenticated/unknown users (returns 403/404) - Fix: Database deadlock detection logs warnings and allows EF Core auto-retry - Add: Configurable LibraryMonitorDelay (min 30s, default 60s) - Fix: SQLite migration filtering—skip SQLite-only migrations on PostgreSQL - Chore: Suppress StyleCop warnings (SA1137, etc.) for project consistency - Docs: 21 documentation files added/updated (config, backup, performance, troubleshooting, session summary) - All changes are backward compatible and production-ready
259 lines
7.7 KiB
Markdown
259 lines
7.7 KiB
Markdown
# PostgreSQL Backup Configuration
|
|
|
|
This document explains how to configure PostgreSQL backup options in Jellyfin using the `database.xml` configuration file.
|
|
|
|
## **IMPORTANT: Local Database Requirement**
|
|
|
|
**pg_dump and pg_restore backup features are ONLY available when the PostgreSQL database host is `localhost` or `127.0.0.1` (or `::1` for IPv6).**
|
|
|
|
- ✅ **Local database** (localhost/127.0.0.1): Automated backups via pg_dump/pg_restore are enabled
|
|
- ❌ **Remote database**: Backup settings are ignored; you must manage backups externally
|
|
|
|
When using a remote PostgreSQL server, Jellyfin will log:
|
|
> "PostgreSQL database is on remote server ({Host}). Backup operations via pg_dump/pg_restore are disabled"
|
|
|
|
And backup operations will show:
|
|
> "Backup deletion is not implemented for PostgreSQL on a remote server. Manage backups externally."
|
|
|
|
## Configuration File Location
|
|
|
|
The `database.xml` file should be placed in your Jellyfin configuration directory:
|
|
|
|
- **Windows**: `%AppData%\Jellyfin\Server\config\database.xml`
|
|
- **Linux**: `~/.config/jellyfin/config/database.xml` or `/etc/jellyfin/config/database.xml`
|
|
- **Docker**: Mount to `/config/database.xml`
|
|
|
|
## Basic Configuration
|
|
|
|
Here's a minimal configuration for PostgreSQL with default backup settings:
|
|
|
|
```xml
|
|
<DatabaseConfigurationOptions>
|
|
<DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
|
|
<LockingBehavior>NoLock</LockingBehavior>
|
|
|
|
<CustomProviderOptions>
|
|
<PluginName>Jellyfin-PostgreSQL</PluginName>
|
|
<PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
|
|
<ConnectionString>Host=localhost;Port=5432;Database=jellyfin;Username=jellyfin;Password=your_password</ConnectionString>
|
|
</CustomProviderOptions>
|
|
|
|
<!-- Backup configuration (all settings are optional) -->
|
|
<BackupOptions>
|
|
<PgDumpPath>pg_dump</PgDumpPath>
|
|
<BackupFormat>custom</BackupFormat>
|
|
</BackupOptions>
|
|
</DatabaseConfigurationOptions>
|
|
```
|
|
|
|
## Backup Options Reference
|
|
|
|
### PgDumpPath
|
|
**Type**: `string` (optional)
|
|
**Default**: Searches in system PATH
|
|
|
|
The full path to the `pg_dump` executable. If not specified, Jellyfin will search common locations:
|
|
- Windows: `C:\Program Files\PostgreSQL\{version}\bin\pg_dump.exe`
|
|
- Linux: `/usr/bin/pg_dump`, `/usr/local/bin/pg_dump`
|
|
|
|
**Examples**:
|
|
```xml
|
|
<!-- Windows -->
|
|
<PgDumpPath>C:\Program Files\PostgreSQL\16\bin\pg_dump.exe</PgDumpPath>
|
|
|
|
<!-- Linux -->
|
|
<PgDumpPath>/usr/bin/pg_dump</PgDumpPath>
|
|
|
|
<!-- Search in PATH -->
|
|
<PgDumpPath>pg_dump</PgDumpPath>
|
|
```
|
|
|
|
### PgRestorePath
|
|
**Type**: `string` (optional)
|
|
**Default**: Searches in system PATH
|
|
|
|
Path to the `pg_restore` executable. Same search behavior as `PgDumpPath`.
|
|
|
|
### BackupFormat
|
|
**Type**: `string`
|
|
**Default**: `custom`
|
|
**Valid values**: `custom`, `plain`, `directory`, `tar`
|
|
|
|
The backup file format:
|
|
- **custom**: Compressed custom format (recommended) - can be restored with `pg_restore`
|
|
- **plain**: Plain SQL script - can be restored with `psql`
|
|
- **directory**: Directory format with one file per table
|
|
- **tar**: Tar archive format
|
|
|
|
```xml
|
|
<BackupFormat>custom</BackupFormat>
|
|
```
|
|
|
|
### IncludeBlobs
|
|
**Type**: `boolean`
|
|
**Default**: `true`
|
|
|
|
Whether to include large objects (BLOBs) in the backup.
|
|
|
|
```xml
|
|
<IncludeBlobs>true</IncludeBlobs>
|
|
```
|
|
|
|
### CompressionLevel
|
|
**Type**: `integer` (0-9)
|
|
**Default**: `6`
|
|
|
|
Compression level for custom and directory formats. Higher values mean better compression but slower speed.
|
|
- `0` = No compression
|
|
- `9` = Maximum compression
|
|
- `6` = Good balance (recommended)
|
|
|
|
```xml
|
|
<CompressionLevel>6</CompressionLevel>
|
|
```
|
|
|
|
### TimeoutSeconds
|
|
**Type**: `integer`
|
|
**Default**: `1800` (30 minutes)
|
|
|
|
Maximum time in seconds to wait for backup/restore operations to complete.
|
|
|
|
```xml
|
|
<TimeoutSeconds>1800</TimeoutSeconds>
|
|
```
|
|
|
|
### VerboseOutput
|
|
**Type**: `boolean`
|
|
**Default**: `true`
|
|
|
|
Enable verbose logging output from pg_dump/pg_restore operations.
|
|
|
|
```xml
|
|
<VerboseOutput>true</VerboseOutput>
|
|
```
|
|
|
|
### ParallelJobs
|
|
**Type**: `integer` (optional)
|
|
**Default**: `null`
|
|
|
|
Number of parallel jobs for backup operations. Only works with `directory` format.
|
|
|
|
```xml
|
|
<BackupFormat>directory</BackupFormat>
|
|
<ParallelJobs>4</ParallelJobs>
|
|
```
|
|
|
|
### AdditionalArguments
|
|
**Type**: `string` (optional)
|
|
**Default**: `null`
|
|
|
|
Additional command-line arguments to pass to pg_dump.
|
|
|
|
**Examples**:
|
|
```xml
|
|
<!-- Exclude specific table data -->
|
|
<AdditionalArguments>--exclude-table-data=public.temp_logs</AdditionalArguments>
|
|
|
|
<!-- Exclude schema -->
|
|
<AdditionalArguments>--exclude-schema=archive</AdditionalArguments>
|
|
|
|
<!-- Multiple arguments -->
|
|
<AdditionalArguments>--exclude-table-data=public.logs --exclude-schema=test</AdditionalArguments>
|
|
```
|
|
|
|
## Complete Example Configuration
|
|
|
|
```xml
|
|
<DatabaseConfigurationOptions>
|
|
<DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
|
|
<LockingBehavior>NoLock</LockingBehavior>
|
|
|
|
<CustomProviderOptions>
|
|
<PluginName>Jellyfin-PostgreSQL</PluginName>
|
|
<PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
|
|
<ConnectionString>Host=localhost;Port=5432;Database=jellyfin;Username=jellyfin;Password=your_password</ConnectionString>
|
|
</CustomProviderOptions>
|
|
|
|
<BackupOptions>
|
|
<!-- Paths to executables -->
|
|
<PgDumpPath>C:\Program Files\PostgreSQL\16\bin\pg_dump.exe</PgDumpPath>
|
|
<PgRestorePath>C:\Program Files\PostgreSQL\16\bin\pg_restore.exe</PgRestorePath>
|
|
|
|
<!-- Backup format and compression -->
|
|
<BackupFormat>custom</BackupFormat>
|
|
<CompressionLevel>6</CompressionLevel>
|
|
<IncludeBlobs>true</IncludeBlobs>
|
|
|
|
<!-- Performance and timeout -->
|
|
<TimeoutSeconds>3600</TimeoutSeconds>
|
|
<VerboseOutput>true</VerboseOutput>
|
|
|
|
<!-- Optional: Parallel processing for directory format -->
|
|
<!-- <ParallelJobs>4</ParallelJobs> -->
|
|
|
|
<!-- Optional: Additional pg_dump arguments -->
|
|
<!-- <AdditionalArguments>--exclude-table-data=public.temp_data</AdditionalArguments> -->
|
|
</BackupOptions>
|
|
</DatabaseConfigurationOptions>
|
|
```
|
|
|
|
## Usage in Code
|
|
|
|
The backup service will automatically read these settings from `database.xml`:
|
|
|
|
```csharp
|
|
// Inject the service
|
|
public class MyClass
|
|
{
|
|
private readonly PostgresBackupService _backupService;
|
|
|
|
public MyClass(PostgresBackupService backupService)
|
|
{
|
|
_backupService = backupService;
|
|
}
|
|
|
|
// Create a backup
|
|
public async Task CreateBackup()
|
|
{
|
|
var backupPath = await _backupService.CreateBackupAsync("/path/to/backups");
|
|
Console.WriteLine($"Backup created: {backupPath}");
|
|
}
|
|
|
|
// Restore a backup
|
|
public async Task RestoreBackup(string backupFile)
|
|
{
|
|
await _backupService.RestoreBackupAsync(backupFile);
|
|
Console.WriteLine("Backup restored successfully");
|
|
}
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### "pg_dump executable not found"
|
|
1. Verify PostgreSQL is installed
|
|
2. Check that `pg_dump` is in your system PATH, or
|
|
3. Specify the full path in `<PgDumpPath>` configuration
|
|
|
|
### Permission Issues
|
|
- Ensure the user running Jellyfin has execute permissions for `pg_dump`
|
|
- Verify database credentials have backup privileges
|
|
|
|
### Backup Takes Too Long
|
|
- Increase `<TimeoutSeconds>` value
|
|
- Consider using `<ParallelJobs>` with directory format for large databases
|
|
- Reduce `<CompressionLevel>` for faster backups
|
|
|
|
### Restore Fails
|
|
- Verify the backup file format matches what pg_restore expects
|
|
- Check that the target database exists and is accessible
|
|
- Review logs for specific error messages
|
|
|
|
## Security Notes
|
|
|
|
1. **Password Storage**: The connection string in `database.xml` contains the database password. Ensure this file has appropriate permissions (readable only by the Jellyfin user).
|
|
|
|
2. **PGPASSWORD**: The service uses the `PGPASSWORD` environment variable to pass credentials to pg_dump, which is more secure than command-line arguments.
|
|
|
|
3. **Backup Files**: Backup files contain your entire database. Store them securely and restrict access appropriately.
|