Files
pgsql-jellyfin/docs/database/postgres-backup-configuration.md
wjones c76853a442 PostgreSQL: Production fixes—UPSERT, remote backup, auth logs
- 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
2026-03-03 16:35:27 -05:00

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.