Files
pgsql-jellyfin/POSTGRES_BACKUP_LOCAL_ONLY_IMPLEMENTATION.md
T
wjones 88dba54087 Add user-configurable PostgreSQL backup system
Introduced backup/restore via external pg_dump/pg_restore tools, configurable in database.xml. Added DatabaseBackupOptions, PostgresBackupService, and example/config docs. Backup features are enabled only for local databases; remote DBs require manual management. Logging and documentation clarify external tool usage, error handling, and security. Updated provider logic and assembly files accordingly.
2026-02-23 18:31:27 -05:00

8.6 KiB

PostgreSQL Backup - Local-Only Implementation Summary

Overview

The PostgreSQL backup functionality using pg_dump and pg_restore has been updated to ONLY work with local databases (localhost or 127.0.0.1). For remote PostgreSQL servers, users must manage backups externally.

Changes Made

1. PostgresDatabaseProvider.cs

Added Fields:

private readonly IConfigurationManager? configurationManager;
private PostgresBackupService? backupService;
private string? currentHost;

Updated Constructor:

  • Added optional IConfigurationManager parameter
  • Allows backup service initialization when configuration is available

New Method: IsLocalHost()

private static bool IsLocalHost(string? host)
{
    return host.Equals("localhost", StringComparison.OrdinalIgnoreCase) ||
           host.Equals("127.0.0.1", StringComparison.Ordinal) ||
           host.Equals("::1", StringComparison.Ordinal); // IPv6 localhost
}

Updated Initialise() Method:

  • Captures the database host from connection string
  • Initializes PostgresBackupService only if host is local
  • Logs appropriate messages based on whether database is local or remote
// Store the host for backup operations
currentHost = connectionBuilder.Host;

// Initialize backup service if host is local and configuration manager is available
if (IsLocalHost(currentHost) && configurationManager is not null)
{
    backupService = new PostgresBackupService(backupLogger, configurationManager);
    logger.LogInformation("PostgreSQL backup service initialized for local database");
}
else if (!IsLocalHost(currentHost))
{
    logger.LogInformation("PostgreSQL database is on remote server ({Host}). Backup operations via pg_dump/pg_restore are disabled", currentHost);
}

Updated Backup Methods:

MigrationBackupFast():

  • Local database: Uses PostgresBackupService.CreateBackupAsync()
  • Remote database: Returns timestamp key, logs warning

RestoreBackupFast():

  • Local database: Uses PostgresBackupService.RestoreBackupAsync()
  • Remote database: Logs warning only

DeleteBackup():

  • Local database: Deletes backup file from disk
  • Remote database: Logs warning

2. Updated Log Messages

All messages now specify "on a remote server" for clarity:

Old Message New Message
"Backup deletion is not implemented for PostgreSQL. Manage backups externally." "Backup deletion is not implemented for PostgreSQL on a remote server. Manage backups externally."
"Fast backup is not implemented for PostgreSQL. Use pg_dump for proper backups." "Fast backup is not implemented for PostgreSQL on a remote server. Use pg_dump manually for proper backups."
"Fast restore is not implemented for PostgreSQL. Use pg_restore for proper restoration." "Fast restore is not implemented for PostgreSQL on a remote server. Use pg_restore manually for proper restoration."

3. Updated Configuration Documentation

database.xml.example:

<!--
  IMPORTANT: pg_dump/pg_restore backup features are ONLY available when the
  PostgreSQL database host is localhost or 127.0.0.1. For remote databases,
  you must manage backups externally using pg_dump/pg_restore commands manually.
-->

BACKUP_CONFIGURATION.md:

  • Added prominent warning about local-only requirement
  • Clarified behavior for remote databases
  • Updated examples and troubleshooting sections

Behavior Matrix

Database Host Backup Service Initialized? Backup Operations Log Message
localhost Yes Fully functional via pg_dump/pg_restore "PostgreSQL backup service initialized for local database"
127.0.0.1 Yes Fully functional via pg_dump/pg_restore "PostgreSQL backup service initialized for local database"
::1 (IPv6) Yes Fully functional via pg_dump/pg_restore "PostgreSQL backup service initialized for local database"
192.168.1.10 (remote) No Disabled, external management required "PostgreSQL database is on remote server ({Host}). Backup operations via pg_dump/pg_restore are disabled"
db.example.com (remote) No Disabled, external management required "PostgreSQL database is on remote server ({Host}). Backup operations via pg_dump/pg_restore are disabled"

Example Configurations

Local Database (Backups Enabled):

<DatabaseConfigurationOptions>
  <DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
  
  <CustomProviderOptions>
    <PluginName>Jellyfin-PostgreSQL</PluginName>
    <PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
    <ConnectionString>Host=localhost;Port=5432;Database=jellyfin;Username=jellyfin;Password=pwd</ConnectionString>
  </CustomProviderOptions>
  
  <BackupOptions>
    <PgDumpPath>pg_dump</PgDumpPath>
    <BackupFormat>custom</BackupFormat>
    <CompressionLevel>6</CompressionLevel>
  </BackupOptions>
</DatabaseConfigurationOptions>

Result: Backups work automatically via pg_dump/pg_restore

Remote Database (Backups Disabled):

<DatabaseConfigurationOptions>
  <DatabaseType>Jellyfin-PostgreSQL</DatabaseType>
  
  <CustomProviderOptions>
    <PluginName>Jellyfin-PostgreSQL</PluginName>
    <PluginAssembly>Jellyfin.Database.Providers.Postgres</PluginAssembly>
    <ConnectionString>Host=192.168.1.50;Port=5432;Database=jellyfin;Username=jellyfin;Password=pwd</ConnectionString>
  </CustomProviderOptions>
  
  <!-- BackupOptions are ignored for remote databases -->
  <BackupOptions>
    <PgDumpPath>pg_dump</PgDumpPath>
  </BackupOptions>
</DatabaseConfigurationOptions>

Result: Backup operations log warnings; users must manually run:

# Manual backup on remote server
pg_dump -h 192.168.1.50 -p 5432 -U jellyfin -d jellyfin -F c -f backup.dump

# Manual restore on remote server
pg_restore -h 192.168.1.50 -p 5432 -U jellyfin -d jellyfin backup.dump

Security Rationale

This restriction exists because:

  1. Local Access Required: pg_dump and pg_restore must be executed on the same machine as the PostgreSQL server for reliable filesystem access
  2. Credentials: Running pg_dump against remote servers requires storing remote credentials
  3. Network Overhead: Large backups over network connections can be slow and unreliable
  4. Best Practice: Remote PostgreSQL deployments should have their own backup infrastructure (scheduled pg_dump jobs, WAL archiving, replication, etc.)

Migration Path

If you previously had a remote PostgreSQL setup expecting automatic backups:

Before (Not Working):

  • Jellyfin connected to remote PostgreSQL
  • Expected automatic backups (didn't work)

After (Clear Behavior):

  • Jellyfin connects to remote PostgreSQL
  • Clear log messages indicate backups are disabled
  • Documentation provides manual backup commands
  1. On the PostgreSQL server, set up a cron job:

    # /etc/cron.daily/jellyfin-backup.sh
    pg_dump -U jellyfin -d jellyfin -F c -f /backups/jellyfin_$(date +%Y%m%d).dump
    
  2. Use PostgreSQL's native backup features:

    • Continuous archiving (WAL archiving)
    • Streaming replication
    • Point-in-time recovery (PITR)
    • pgBackRest or Barman for enterprise backups
  3. Cloud-native solutions:

    • AWS RDS automated backups
    • Azure Database for PostgreSQL automated backups
    • Google Cloud SQL automated backups

Testing

To test the local vs. remote behavior:

// Test with localhost
var localConfig = new DatabaseConfigurationOptions
{
    CustomProviderOptions = new CustomDatabaseOptions
    {
        Options = new[]
        {
            new CustomDatabaseOption { Key = "host", Value = "localhost" }
        }
    }
};
// Result: Backup service initialized

// Test with remote host
var remoteConfig = new DatabaseConfigurationOptions
{
    CustomProviderOptions = new CustomDatabaseOptions
    {
        Options = new[]
        {
            new CustomDatabaseOption { Key = "host", Value = "192.168.1.50" }
        }
    }
};
// Result: Backup service NOT initialized, warning logged

Summary

Local databases (localhost/127.0.0.1): Full automated backup support via pg_dump/pg_restore
Remote databases: Backup operations disabled, clear messaging, external management required
📝 Documentation: Updated to clearly explain the local-only restriction
🔒 Security: Follows best practices for remote database backup management

This implementation provides a clear, safe, and maintainable approach to PostgreSQL backups in Jellyfin.