From 8d28a50a17ae3f54cad33c8368e71ea68079e9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20DEM=C4=B0RC=C4=B0?= Date: Sun, 20 Apr 2025 12:14:41 +0000 Subject: [PATCH 1/2] fix(backup): handle multiple container IDs in backup command Ensure only one container ID is used when running `docker exec` for pg_dump to avoid errors caused by multiple matching containers. Fixes INTERNAL_SERVER_ERROR from backup.manualBackupWebServer path. Co-authored-by: Merloss 54235902+Merloss@users.noreply.github.com --- packages/server/src/utils/backups/web-server.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/server/src/utils/backups/web-server.ts b/packages/server/src/utils/backups/web-server.ts index ef2249d0a..1870a08c9 100644 --- a/packages/server/src/utils/backups/web-server.ts +++ b/packages/server/src/utils/backups/web-server.ts @@ -24,6 +24,7 @@ export const runWebServerBackup = async (backup: BackupSchedule) => { await execAsync(`mkdir -p ${tempDir}/filesystem`); // First get the container ID + // Returns: ID\nID\nID... const { stdout: containerId } = await execAsync( "docker ps --filter 'name=dokploy-postgres' -q", ); @@ -32,14 +33,20 @@ export const runWebServerBackup = async (backup: BackupSchedule) => { throw new Error("PostgreSQL container not found"); } + // ID\nID\nID... => [ "ID", "ID", ... ] + const containers = containerId.trim().split("\n").filter(Boolean); + // Then run pg_dump with the container ID - const postgresCommand = `docker exec ${containerId.trim()} pg_dump -v -Fc -U dokploy -d dokploy > '${tempDir}/database.sql'`; - await execAsync(postgresCommand); + for (const containerId of containers) { + // Maybe we can find a better identification for this part vvv + const postgresCommand = `docker exec ${containerId.trim()} pg_dump -v -Fc -U dokploy -d dokploy > '${tempDir}/database-${containerId}.sql'`; + await execAsync(postgresCommand); + } await execAsync(`cp -r ${BASE_PATH}/* ${tempDir}/filesystem/`); - await execAsync( - `cd ${tempDir} && zip -r ${backupFileName} database.sql filesystem/ > /dev/null 2>&1`, + await execAsync( // Zip all .sql files since we created more than one + `cd ${tempDir} && zip -r ${backupFileName} *.sql filesystem/ > /dev/null 2>&1`, ); const uploadCommand = `rclone copyto ${rcloneFlags.join(" ")} "${tempDir}/${backupFileName}" "${s3Path}"`; From 461d7c530ac40757a5ace7aa2b554e3f5613faa8 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 26 Apr 2025 16:07:50 -0600 Subject: [PATCH 2/2] fix(restore): streamline container ID retrieval for database operations Refactor the database restore process to consistently use a single container ID for the PostgreSQL container. This change enhances reliability by ensuring that commands are executed against the correct container, preventing potential errors from multiple matches. Co-authored-by: Merloss 54235902+Merloss@users.noreply.github.com --- .../server/src/utils/backups/web-server.ts | 17 +++++-------- .../server/src/utils/restore/web-server.ts | 24 +++++++++++++------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/server/src/utils/backups/web-server.ts b/packages/server/src/utils/backups/web-server.ts index 1870a08c9..2dea3d818 100644 --- a/packages/server/src/utils/backups/web-server.ts +++ b/packages/server/src/utils/backups/web-server.ts @@ -24,28 +24,23 @@ export const runWebServerBackup = async (backup: BackupSchedule) => { await execAsync(`mkdir -p ${tempDir}/filesystem`); // First get the container ID - // Returns: ID\nID\nID... const { stdout: containerId } = await execAsync( - "docker ps --filter 'name=dokploy-postgres' -q", + `docker ps --filter "name=dokploy-postgres" --filter "status=running" -q | head -n 1`, ); if (!containerId) { throw new Error("PostgreSQL container not found"); } - // ID\nID\nID... => [ "ID", "ID", ... ] - const containers = containerId.trim().split("\n").filter(Boolean); + const postgresContainerId = containerId.trim(); - // Then run pg_dump with the container ID - for (const containerId of containers) { - // Maybe we can find a better identification for this part vvv - const postgresCommand = `docker exec ${containerId.trim()} pg_dump -v -Fc -U dokploy -d dokploy > '${tempDir}/database-${containerId}.sql'`; - await execAsync(postgresCommand); - } + const postgresCommand = `docker exec ${postgresContainerId} pg_dump -v -Fc -U dokploy -d dokploy > '${tempDir}/database.sql'`; + await execAsync(postgresCommand); await execAsync(`cp -r ${BASE_PATH}/* ${tempDir}/filesystem/`); - await execAsync( // Zip all .sql files since we created more than one + await execAsync( + // Zip all .sql files since we created more than one `cd ${tempDir} && zip -r ${backupFileName} *.sql filesystem/ > /dev/null 2>&1`, ); diff --git a/packages/server/src/utils/restore/web-server.ts b/packages/server/src/utils/restore/web-server.ts index 46aa92395..8397dcf20 100644 --- a/packages/server/src/utils/restore/web-server.ts +++ b/packages/server/src/utils/restore/web-server.ts @@ -83,44 +83,54 @@ export const restoreWebServerBackup = async ( throw new Error("Database file not found after extraction"); } + const { stdout: postgresContainer } = await execAsync( + `docker ps --filter "name=dokploy-postgres" --filter "status=running" -q | head -n 1`, + ); + + if (!postgresContainer) { + throw new Error("Dokploy Postgres container not found"); + } + + const postgresContainerId = postgresContainer.trim(); + // Drop and recreate database emit("Disconnecting all users from database..."); await execAsync( - `docker exec $(docker ps --filter "name=dokploy-postgres" -q) psql -U dokploy postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'dokploy' AND pid <> pg_backend_pid();"`, + `docker exec ${postgresContainerId} psql -U dokploy postgres -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = 'dokploy' AND pid <> pg_backend_pid();"`, ); emit("Dropping existing database..."); await execAsync( - `docker exec $(docker ps --filter "name=dokploy-postgres" -q) psql -U dokploy postgres -c "DROP DATABASE IF EXISTS dokploy;"`, + `docker exec ${postgresContainerId} psql -U dokploy postgres -c "DROP DATABASE IF EXISTS dokploy;"`, ); emit("Creating fresh database..."); await execAsync( - `docker exec $(docker ps --filter "name=dokploy-postgres" -q) psql -U dokploy postgres -c "CREATE DATABASE dokploy;"`, + `docker exec ${postgresContainerId} psql -U dokploy postgres -c "CREATE DATABASE dokploy;"`, ); // Copy the backup file into the container emit("Copying backup file into container..."); await execAsync( - `docker cp ${tempDir}/database.sql $(docker ps --filter "name=dokploy-postgres" -q):/tmp/database.sql`, + `docker cp ${tempDir}/database.sql ${postgresContainerId}:/tmp/database.sql`, ); // Verify file in container emit("Verifying file in container..."); await execAsync( - `docker exec $(docker ps --filter "name=dokploy-postgres" -q) ls -l /tmp/database.sql`, + `docker exec ${postgresContainerId} ls -l /tmp/database.sql`, ); // Restore from the copied file emit("Running database restore..."); await execAsync( - `docker exec $(docker ps --filter "name=dokploy-postgres" -q) pg_restore -v -U dokploy -d dokploy /tmp/database.sql`, + `docker exec ${postgresContainerId} pg_restore -v -U dokploy -d dokploy /tmp/database.sql`, ); // Cleanup the temporary file in the container emit("Cleaning up container temp file..."); await execAsync( - `docker exec $(docker ps --filter "name=dokploy-postgres" -q) rm /tmp/database.sql`, + `docker exec ${postgresContainerId} rm /tmp/database.sql`, ); emit("Restore completed successfully!");