# 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.
