From a5a4a1a818dfbc039eeac0bc55bd2b0b2d79e2e9 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Sat, 7 Mar 2026 01:48:11 -0600 Subject: [PATCH] refactor: update backup file paths to include app name for better organization --- packages/server/src/utils/backups/compose.ts | 2 +- packages/server/src/utils/backups/index.ts | 12 ++++-------- packages/server/src/utils/backups/mariadb.ts | 2 +- packages/server/src/utils/backups/mongo.ts | 2 +- packages/server/src/utils/backups/mysql.ts | 2 +- packages/server/src/utils/backups/postgres.ts | 2 +- packages/server/src/utils/backups/web-server.ts | 2 +- packages/server/src/utils/volume-backups/backup.ts | 5 +---- packages/server/src/utils/volume-backups/utils.ts | 7 ++----- 9 files changed, 13 insertions(+), 23 deletions(-) diff --git a/packages/server/src/utils/backups/compose.ts b/packages/server/src/utils/backups/compose.ts index 1963f2c91..28124f809 100644 --- a/packages/server/src/utils/backups/compose.ts +++ b/packages/server/src/utils/backups/compose.ts @@ -20,7 +20,7 @@ export const runComposeBackup = async ( const { prefix, databaseType } = backup; const destination = backup.destination; const backupFileName = `${new Date().toISOString()}.sql.gz`; - const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`; + const bucketDestination = `${backup.appName}/${normalizeS3Path(prefix)}${backupFileName}`; const deployment = await createDeploymentBackup({ backupId: backup.backupId, title: "Compose Backup", diff --git a/packages/server/src/utils/backups/index.ts b/packages/server/src/utils/backups/index.ts index cd88539d5..c747c8656 100644 --- a/packages/server/src/utils/backups/index.ts +++ b/packages/server/src/utils/backups/index.ts @@ -1,4 +1,3 @@ -import path from "node:path"; import { CLEANUP_CRON_JOB } from "@dokploy/server/constants"; import { member } from "@dokploy/server/db/schema"; import type { BackupSchedule } from "@dokploy/server/services/backup"; @@ -11,7 +10,7 @@ import { startLogCleanup } from "../access-log/handler"; import { cleanupAll } from "../docker/utils"; import { sendDockerCleanupNotifications } from "../notifications/docker-cleanup"; import { execAsync, execAsyncRemote } from "../process/execAsync"; -import { getS3Credentials, scheduleBackup } from "./utils"; +import { getS3Credentials, normalizeS3Path, scheduleBackup } from "./utils"; export const initCronJobs = async () => { console.log("Setting up cron jobs...."); @@ -117,18 +116,15 @@ export const keepLatestNBackups = async ( try { const rcloneFlags = getS3Credentials(backup.destination); - const backupFilesPath = path.join( - `:s3:${backup.destination.bucket}`, - backup.prefix, - ); + const backupFilesPath = `:s3:${backup.destination.bucket}/${backup.appName}/${normalizeS3Path(backup.prefix)}`; // --include "*.sql.gz" or "*.zip" ensures nothing else other than the dokploy backup files are touched by rclone const rcloneList = `rclone lsf ${rcloneFlags.join(" ")} --include "*${backup.databaseType === "web-server" ? ".zip" : ".sql.gz"}" ${backupFilesPath}`; // when we pipe the above command with this one, we only get the list of files we want to delete const sortAndPickUnwantedBackups = `sort -r | tail -n +$((${backup.keepLatestCount}+1)) | xargs -I{}`; // this command deletes the files - // to test the deletion before actually deleting we can add --dry-run before ${backupFilesPath}/{} - const rcloneDelete = `rclone delete ${rcloneFlags.join(" ")} ${backupFilesPath}/{}`; + // to test the deletion before actually deleting we can add --dry-run before ${backupFilesPath}{} + const rcloneDelete = `rclone delete ${rcloneFlags.join(" ")} ${backupFilesPath}{}`; const rcloneCommand = `${rcloneList} | ${sortAndPickUnwantedBackups} ${rcloneDelete}`; diff --git a/packages/server/src/utils/backups/mariadb.ts b/packages/server/src/utils/backups/mariadb.ts index 56cb1a9aa..292b08cc8 100644 --- a/packages/server/src/utils/backups/mariadb.ts +++ b/packages/server/src/utils/backups/mariadb.ts @@ -20,7 +20,7 @@ export const runMariadbBackup = async ( const { prefix } = backup; const destination = backup.destination; const backupFileName = `${new Date().toISOString()}.sql.gz`; - const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`; + const bucketDestination = `${backup.appName}/${normalizeS3Path(prefix)}${backupFileName}`; const deployment = await createDeploymentBackup({ backupId: backup.backupId, title: "MariaDB Backup", diff --git a/packages/server/src/utils/backups/mongo.ts b/packages/server/src/utils/backups/mongo.ts index 2071478a0..10a434560 100644 --- a/packages/server/src/utils/backups/mongo.ts +++ b/packages/server/src/utils/backups/mongo.ts @@ -17,7 +17,7 @@ export const runMongoBackup = async (mongo: Mongo, backup: BackupSchedule) => { const { prefix } = backup; const destination = backup.destination; const backupFileName = `${new Date().toISOString()}.sql.gz`; - const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`; + const bucketDestination = `${backup.appName}/${normalizeS3Path(prefix)}${backupFileName}`; const deployment = await createDeploymentBackup({ backupId: backup.backupId, title: "MongoDB Backup", diff --git a/packages/server/src/utils/backups/mysql.ts b/packages/server/src/utils/backups/mysql.ts index d131090fa..26c3105a4 100644 --- a/packages/server/src/utils/backups/mysql.ts +++ b/packages/server/src/utils/backups/mysql.ts @@ -17,7 +17,7 @@ export const runMySqlBackup = async (mysql: MySql, backup: BackupSchedule) => { const { prefix } = backup; const destination = backup.destination; const backupFileName = `${new Date().toISOString()}.sql.gz`; - const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`; + const bucketDestination = `${backup.appName}/${normalizeS3Path(prefix)}${backupFileName}`; const deployment = await createDeploymentBackup({ backupId: backup.backupId, title: "MySQL Backup", diff --git a/packages/server/src/utils/backups/postgres.ts b/packages/server/src/utils/backups/postgres.ts index 9241f2103..de493f0bd 100644 --- a/packages/server/src/utils/backups/postgres.ts +++ b/packages/server/src/utils/backups/postgres.ts @@ -26,7 +26,7 @@ export const runPostgresBackup = async ( const { prefix } = backup; const destination = backup.destination; const backupFileName = `${new Date().toISOString()}.sql.gz`; - const bucketDestination = `${normalizeS3Path(prefix)}${backupFileName}`; + const bucketDestination = `${backup.appName}/${normalizeS3Path(prefix)}${backupFileName}`; try { const rcloneFlags = getS3Credentials(destination); const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`; diff --git a/packages/server/src/utils/backups/web-server.ts b/packages/server/src/utils/backups/web-server.ts index 84f6b863a..1a51d23ea 100644 --- a/packages/server/src/utils/backups/web-server.ts +++ b/packages/server/src/utils/backups/web-server.ts @@ -31,7 +31,7 @@ export const runWebServerBackup = async (backup: BackupSchedule) => { const { BASE_PATH } = paths(); const tempDir = await mkdtemp(join(tmpdir(), "dokploy-backup-")); const backupFileName = `webserver-backup-${timestamp}.zip`; - const s3Path = `:s3:${destination.bucket}/${normalizeS3Path(backup.prefix)}${backupFileName}`; + const s3Path = `:s3:${destination.bucket}/${backup.appName}/${normalizeS3Path(backup.prefix)}${backupFileName}`; try { await execAsync(`mkdir -p ${tempDir}/filesystem`); diff --git a/packages/server/src/utils/volume-backups/backup.ts b/packages/server/src/utils/volume-backups/backup.ts index ad3eea29f..dd1575563 100644 --- a/packages/server/src/utils/volume-backups/backup.ts +++ b/packages/server/src/utils/volume-backups/backup.ts @@ -13,10 +13,7 @@ export const backupVolume = async ( const { VOLUME_BACKUPS_PATH, VOLUME_BACKUP_LOCK_PATH } = paths(!!serverId); const destination = volumeBackup.destination; const backupFileName = `${volumeName}-${new Date().toISOString()}.tar`; - const effectivePrefix = prefix - ? normalizeS3Path(prefix) - : `${volumeBackup.appName}/`; - const bucketDestination = `${effectivePrefix}${backupFileName}`; + const bucketDestination = `${volumeBackup.appName}/${normalizeS3Path(prefix || "")}${backupFileName}`; const rcloneFlags = getS3Credentials(volumeBackup.destination); const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`; const volumeBackupPath = path.join(VOLUME_BACKUPS_PATH, volumeBackup.appName); diff --git a/packages/server/src/utils/volume-backups/utils.ts b/packages/server/src/utils/volume-backups/utils.ts index d179dd096..dc2a4504f 100644 --- a/packages/server/src/utils/volume-backups/utils.ts +++ b/packages/server/src/utils/volume-backups/utils.ts @@ -81,11 +81,8 @@ const cleanupOldVolumeBackups = async ( try { const rcloneFlags = getS3Credentials(destination); - const normalizedPrefix = prefix - ? normalizeS3Path(prefix) - : `${volumeBackup.appName}/`; - const backupFilesPath = `:s3:${destination.bucket}/${normalizedPrefix}`; - const listCommand = `rclone lsf ${rcloneFlags.join(" ")} --include \"${volumeName}-*.tar\" :s3:${destination.bucket}/${normalizedPrefix}`; + const backupFilesPath = `:s3:${destination.bucket}/${volumeBackup.appName}/${normalizeS3Path(prefix || "")}`; + const listCommand = `rclone lsf ${rcloneFlags.join(" ")} --include \"${volumeName}-*.tar\" ${backupFilesPath}`; const sortAndPick = `sort -r | tail -n +$((${keepLatestCount}+1)) | xargs -I{}`; const deleteCommand = `rclone delete ${rcloneFlags.join(" ")} ${backupFilesPath}{}`; const fullCommand = `${listCommand} | ${sortAndPick} ${deleteCommand}`;