Data Backup
To backup your Cadmus data, you must:
- backup the Mongo database (data), conventionally named as follows:
cadmus-PRJ
- backup 2 or 3 PostgreSQL database(s) (indexes, user accounts, and optionally graph). Conventionally they are named as follows:
cadmus-PRJ(the index anyway can be rebuilt from data if required)cadmus-PRJ-authcadmus-PRJ-graph(present only when using the graph)
If you expose the database services from your Docker containers, as it is usually the case, you just have to use the corresponding database tools to dump databases. Just be sure to use the right port, as often ports are remapped when several services run in the same host machine.
Note that usually in Docker omitting
portsfor database services altogether is the safest option. Anyway, exposing the database ports to the loopback address (127.0.0.1) on your host machine is better than exposing them to all interfaces (- 27017:27017). Since only the API containers need to access the databases, we could remove theportssection entirely from the database services. The API services will still be able to connect using the service name and internal port (e.g.cadmus-PRJ-mongo:27017) because they share the same Docker network. This is the most secure configuration as the databases are completely isolated from the host machine’s external network interfaces. Anyway, as we need to access the DB locally for backup, it is acceptable to use the loopback address.
In Linux, which is the most typical host, you can just have a .sh batch file saving your data somewhere, and then launch it periodically with crontab.
Backup
👉 In this script replace PRJ with your project name.
#!/bin/bash
# Backup script for Cadmus databases.
# You can launch this by editing cron with crontab -e, using a line like this (daily dump at 3 AM):
# 00 03 * * * /home/crontab-scripts/cadmus-dump.sh
# --- Configuration ---
# Set the base directory for backups
BASE_BACKUP_DIR="./backup"
# Get the current date in YYYYMMDD format for the directory name
DATE_DIR_NAME=`date +%Y%m%d`
# Define the full path for today's backup directory
TODAY_BACKUP_DIR="${BASE_BACKUP_DIR}/${DATE_DIR_NAME}"
# Ensure the base directory exists
mkdir -p "${BASE_BACKUP_DIR}"
# Create the date-stamped folder for today's backup
echo "Creating backup directory: ${TODAY_BACKUP_DIR}"
mkdir -p "${TODAY_BACKUP_DIR}"
# --- MongoDB Dump ---
echo "Dumping MongoDB databases..."
# Dump cadmus-PRJ (main data)
mongodump --port=27017 --db cadmus-PRJ --archive="${TODAY_BACKUP_DIR}/cadmus-PRJ-mongo.gz" --gzip
# Dump cadmus-PRJ-log (logs)
mongodump --port=27017 --db cadmus-PRJ-log --archive="${TODAY_BACKUP_DIR}/cadmus-PRJ-log-mongo.gz" --gzip
# --- PostgreSQL Dump ---
echo "Dumping PostgreSQL databases..."
# Note: Using '-h 127.0.0.1' requires your DB services to be configured with '127.0.0.1:PORT:PORT' in docker-compose.yml
# export the PostgreSQL password so child processes (pg_dump) can see it
export PGPASSWORD='postgres'
# use the -w flag to ensure it fails rather than hangs if something goes wrong
pg_dump -h 127.0.0.1 -U postgres -d cadmus-PRJ -w | gzip > "${TODAY_BACKUP_DIR}/cadmus-PRJ-pgsql.gz"
pg_dump -h 127.0.0.1 -U postgres -d cadmus-PRJ-auth -w | gzip > "${TODAY_BACKUP_DIR}/cadmus-PRJ-auth-pgsql.gz"
# security best practice: unset it after the dump is done
unset PGPASSWORD
echo "Backup completed successfully in ${TODAY_BACKUP_DIR}"
⚠️ Note that usually for PostgreSQL you should set the password in the home folder of your user (get it via echo $HOME) in a file named .pgpass with this content:
127.0.0.1:5432:*:postgres:YOURPASSWORDHERE
Be sure to set its permissions:
chmod 0600 /root/.pgpass
Anyway, this often does not work because when put it in a script the PGPASSWORD variable gets “lost” if not handled correctly. So, the approach to set the password explicitly is more effective.
💡 If you want to download files, just connect to your VM (using your account credentials) via SCP (use your VM IP and port 22). You can either use GUI like WinSCP or command line tools.
Restore
👉 In this script replace PRJ with your project name.
#!/bin/bash
# Restore script for Cadmus databases.
# Usage: ./restore.sh YYYYMMDD
set -e
# --- Configuration & Validation ---
BASE_BACKUP_DIR="./backup"
TARGET_DATE=$1
if [ -z "$TARGET_DATE" ]; then
echo "ERROR: Please provide a date folder name (YYYYMMDD) as an argument."
echo "Usage: $0 YYYYMMDD"
exit 1
fi
TODAY_BACKUP_DIR="${BASE_BACKUP_DIR}/${TARGET_DATE}"
if [ ! -d "$TODAY_BACKUP_DIR" ]; then
echo "ERROR: Backup directory ${TODAY_BACKUP_DIR} does not exist."
exit 1
fi
echo "===================================================="
echo " Starting Cadmus Database Restore from: ${TARGET_DATE}"
echo "===================================================="
# --- MongoDB Restore ---
echo "--> Restoring MongoDB databases via docker exec..."
# Added --drop to clear seeded collections before writing backup data
if [ -f "${TODAY_BACKUP_DIR}/cadmus-PRJ-mongo.gz" ]; then
echo "Restoring cadmus-PRJ..."
docker exec -i cadmus-PRJ-mongo mongorestore --drop --archive --gzip < "${TODAY_BACKUP_DIR}/cadmus-PRJ-mongo.gz"
else
echo "WARNING: ${TODAY_BACKUP_DIR}/cadmus-PRJ-mongo.gz not found. Skipping."
fi
if [ -f "${TODAY_BACKUP_DIR}/cadmus-PRJ-log-mongo.gz" ]; then
echo "Restoring cadmus-PRJ-log..."
docker exec -i cadmus-PRJ-mongo mongorestore --drop --archive --gzip < "${TODAY_BACKUP_DIR}/cadmus-PRJ-log-mongo.gz"
else
echo "WARNING: ${TODAY_BACKUP_DIR}/cadmus-PRJ-log-mongo.gz not found. Skipping."
fi
Cleanup
This script can be periodically run to cleanup the backup folder from oldest dumps.
#!/bin/bash
# Script to delete old local backups
# --- Configuration ---
# Match this exactly with your backup script location (use absolute paths if run via cron)
BASE_BACKUP_DIR="./backup"
# Number of latest backup folders to KEEP (e.g., 7 days)
KEEP_DAYS=7
echo "Starting cleanup: retaining the last ${KEEP_DAYS} backup folders in ${BASE_BACKUP_DIR}"
# Ensure directory exists before searching
if [ ! -d "${BASE_BACKUP_DIR}" ]; then
echo "Error: Directory ${BASE_BACKUP_DIR} does not exist."
exit 1
fi
# Find all daily directories, sort chronologically reverse, skip the first X, and delete
find "${BASE_BACKUP_DIR}" -mindepth 1 -maxdepth 1 -type d | sort -r | tail -n +$((KEEP_DAYS + 1)) | while read dir_to_delete; do
echo "Deleting old backup folder: ${dir_to_delete}"
rm -rf "${dir_to_delete}"
done
echo "Cleanup completed."
Transfer - LFTP
Of course, you can then transfer your files somewhere else, e.g. (this script is placed in backup folder). This script just uses some FTP account.
#!/bin/bash
# Transfer script to upload the latest backup archive using lftp
# --- Configuration ---
BASE_BACKUP_DIR="./backup"
DATE_DIR_NAME=`date +%Y%m%d`
ARCHIVE_NAME="cadmus-backup-${DATE_DIR_NAME}.tar.gz"
FULL_ARCHIVE_PATH="${BASE_BACKUP_DIR}/${ARCHIVE_NAME}"
FTP_HOST="ftp.myserver.net"
FTP_USER="user"
FTP_PASS="password"
# Verify source folder exists
if [ ! -d "${BASE_BACKUP_DIR}/${DATE_DIR_NAME}" ]; then
echo "ERROR: Today's backup directory (${BASE_BACKUP_DIR}/${DATE_DIR_NAME}) not found!"
exit 1
fi
# --- Archiving ---
echo "Creating single archive for upload: ${ARCHIVE_NAME}"
tar -czf "${FULL_ARCHIVE_PATH}" -C "${BASE_BACKUP_DIR}" "${DATE_DIR_NAME}"
# --- Upload ---
echo "Starting upload using lftp..."
# Fixed: Pass the explicit local path to the 'put' command
lftp -e "set cmd:prompt ''; put ${FULL_ARCHIVE_PATH}; bye" -u "${FTP_USER}","${FTP_PASS}" "${FTP_HOST}"
# Check the exit status of lftp
if [ $? -eq 0 ]; then
echo "Upload completed successfully!"
echo "Removing local archive file: ${FULL_ARCHIVE_PATH}"
rm "${FULL_ARCHIVE_PATH}"
else
echo "ERROR: Upload failed! Keeping archive for inspection at ${FULL_ARCHIVE_PATH}"
exit 1
fi
echo "Transfer process finished."
Transfer - GDrive
Another popular option is using GDrive as your backup target. To this end, you could use a script like this:
#!/bin/bash
# Backup and upload script using rclone to Google Drive
# --- Configuration ---
BASE_BACKUP_DIR="./backup"
DATE_DIR_NAME=$(date +%Y%m%d)
ARCHIVE_NAME="cadmus-backup-${DATE_DIR_NAME}.tar.gz"
FULL_ARCHIVE_PATH="${BASE_BACKUP_DIR}/${ARCHIVE_NAME}"
RCLONE_REMOTE="gdrive" # Name of your rclone remote
RCLONE_DESTINATION="backups" # Folder in Google Drive
# Verify source folder exists
if [ ! -d "${BASE_BACKUP_DIR}/${DATE_DIR_NAME}" ]; then
echo "ERROR: Today's backup directory (${BASE_BACKUP_DIR}/${DATE_DIR_NAME}) not found!"
exit 1
fi
# --- Archiving ---
echo "Creating archive: ${ARCHIVE_NAME}"
tar -czf "${FULL_ARCHIVE_PATH}" -C "${BASE_BACKUP_DIR}" "${DATE_DIR_NAME}"
# --- Upload ---
echo "Uploading to Google Drive via rclone..."
rclone copy "${FULL_ARCHIVE_PATH}" "${RCLONE_REMOTE}:${RCLONE_DESTINATION}" --progress
if [ $? -eq 0 ]; then
echo "Upload successful. Cleaning up local archive..."
rm "${FULL_ARCHIVE_PATH}"
else
echo "ERROR: Upload failed. Archive retained for inspection at ${FULL_ARCHIVE_PATH}"
exit 1
fi
echo "Backup process complete."
💡 Use
rclone moveinstead ofcopyif you want to delete local files after upload.
To setup rclone in the VM:
curl -O https://downloads.rclone.org/rclone-current-linux-amd64.deb
sudo apt install ./rclone-current-linux-amd64.deb
To test the installation and see the GDrive files listed:
rclone ls gdrive:
If you need to create the target folder:
rclone mkdir gdrive:backups
To configure rclone with your GDrive account you need a headless setup via its --copy-config method. These are the instructions for the machine with access to your GDrive account:
- install rclone from https://rclone.org/downloads.
- run
rclone configand create a remote namedgdrive: choose Google Drive and follow the OAuth flow in browser, then save the configuration. - locate the configuration file you saved (e.g. in Windows it’s usually under your user folder
.config\rclone\rclone.conf) and copy it to the VM hosting Cadmus, e.g. via SCP:
scp ~/.config/rclone/rclone.conf user@your-vm:/home/user/.config/rclone/rclone.conf
Crontab
You could launch all these scripts sequentially:
00 03 * * * /home/crontab-scripts/cadmus-dump.sh && \
/home/crontab-scripts/cadmus-transfer.sh && \
/home/crontab-scripts/cadmus-cleanup.sh
⚠️ Ensure all scripts are executable:
chmod +x /home/crontab-scripts/*.sh.
Windows Scripts
The following scripts can be used on Windows Powershell and correspond to the above for Linux. Note that:
- PostgreSQL requires the target databases (
cadmus-PRJandcadmus-PRJ-auth) to already exist prior to running psql. If restoring to a fresh environment, create empty databases first (createdb -h 127.0.0.1 -U postgres cadmus-PRJ). - the
mongorestorecommand includes--drop, which drops existing collections before restoring to prevent duplicate key conflicts. Remove--dropif you prefer merging into existing collections. -
ensure
mongorestoreandpsqlare available in your systemPATH. - 📁 backup (replace
PRJwith your project name):
# Backup script for Cadmus databases (Windows PowerShell 5.1 or PowerShell 7+).
# Requires mongodump (MongoDB Database Tools) and pg_dump (PostgreSQL client tools) in PATH.
# You can schedule this in Windows Task Scheduler (e.g., daily at 3:00 AM).
# Task Action: powershell.exe -NoProfile -ExecutionPolicy Bypass -File "C:\path\to\backup.ps1"
# --- Configuration ---
# Set the base directory for backups. A relative path is resolved against this script's folder
# (Task Scheduler starts scripts in C:\Windows\System32, so the current directory is unreliable).
$BaseBackupDir = ".\backup"
$MongoPort = 27017
# Note: Using 127.0.0.1 requires your DB services to be configured with '127.0.0.1:PORT:PORT' in docker-compose.yml
$PgHost = "127.0.0.1"
$PgPort = 5432
$PgUser = "postgres"
$PgPassword = "postgres"
# --- Setup ---
if (-not [System.IO.Path]::IsPathRooted($BaseBackupDir)) {
$BaseBackupDir = Join-Path -Path $PSScriptRoot -ChildPath $BaseBackupDir
}
# Absolute path is required: .NET file APIs do not follow PowerShell's current location
$BaseBackupDir = [System.IO.Path]::GetFullPath($BaseBackupDir)
# Get the current date in YYYYMMDD format for the directory name
$DateDirName = Get-Date -Format "yyyyMMdd"
# Define the full path for today's backup directory
$TodayBackupDir = Join-Path -Path $BaseBackupDir -ChildPath $DateDirName
# Ensure the required tools are available
foreach ($tool in "mongodump", "pg_dump") {
if (-not (Get-Command $tool -CommandType Application -ErrorAction SilentlyContinue)) {
Write-Host "ERROR: $tool not found in PATH." -ForegroundColor Red
exit 1
}
}
$PgDumpExe = (Get-Command "pg_dump" -CommandType Application | Select-Object -First 1).Source
# Create the date-stamped folder for today's backup (also creates the base directory)
Write-Host "Creating backup directory: $TodayBackupDir"
New-Item -ItemType Directory -Path $TodayBackupDir -Force | Out-Null
# Names of databases whose dump failed
$Failures = New-Object System.Collections.Generic.List[string]
# --- MongoDB Dump ---
function Export-MongoDump {
param (
[string]$Database,
[string]$OutputFile
)
Write-Host "Dumping $Database..."
& mongodump "--port=$MongoPort" "--db=$Database" "--archive=$OutputFile" --gzip
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: mongodump failed for $Database (exit code $LASTEXITCODE)." -ForegroundColor Red
Remove-Item -LiteralPath $OutputFile -Force -ErrorAction SilentlyContinue
$script:Failures.Add($Database)
}
}
Write-Host "Dumping MongoDB databases..."
# Dump cadmus-PRJ (main data)
Export-MongoDump -Database "cadmus-PRJ" -OutputFile (Join-Path $TodayBackupDir "cadmus-PRJ-mongo.gz")
# Dump cadmus-PRJ-log (logs)
Export-MongoDump -Database "cadmus-PRJ-log" -OutputFile (Join-Path $TodayBackupDir "cadmus-PRJ-log-mongo.gz")
# --- PostgreSQL Dump ---
# Runs pg_dump and gzips its binary output directly to file
# (piping through PowerShell would re-encode the output as text).
function Export-PgDumpGzip {
param (
[string]$Database,
[string]$OutputFile
)
Write-Host "Dumping $Database..."
$fileStream = $null
$gzipStream = $null
$process = $null
$exitCode = -1
try {
$fileStream = [System.IO.File]::Create($OutputFile)
$gzipStream = New-Object System.IO.Compression.GZipStream($fileStream, [System.IO.Compression.CompressionMode]::Compress)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PgDumpExe
# -w ensures it fails rather than hangs waiting for a password
$psi.Arguments = "-h $PgHost -p $PgPort -U $PgUser -d `"$Database`" -w"
$psi.RedirectStandardOutput = $true
$psi.UseShellExecute = $false
$process = [System.Diagnostics.Process]::Start($psi)
$process.StandardOutput.BaseStream.CopyTo($gzipStream)
$process.WaitForExit()
$exitCode = $process.ExitCode
}
catch {
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
}
finally {
# Closing the gzip stream flushes the gzip footer and closes the file stream
if ($null -ne $gzipStream) { $gzipStream.Dispose() }
if ($null -ne $fileStream) { $fileStream.Dispose() }
if ($null -ne $process) { $process.Dispose() }
}
if ($exitCode -ne 0) {
Write-Host "ERROR: pg_dump failed for $Database (exit code $exitCode)." -ForegroundColor Red
Remove-Item -LiteralPath $OutputFile -Force -ErrorAction SilentlyContinue
$script:Failures.Add($Database)
}
}
Write-Host "Dumping PostgreSQL databases..."
# Export the PostgreSQL password so child processes (pg_dump) can see it
$env:PGPASSWORD = $PgPassword
try {
Export-PgDumpGzip -Database "cadmus-PRJ" -OutputFile (Join-Path $TodayBackupDir "cadmus-PRJ-pgsql.gz")
Export-PgDumpGzip -Database "cadmus-PRJ-auth" -OutputFile (Join-Path $TodayBackupDir "cadmus-PRJ-auth-pgsql.gz")
}
finally {
# Security best practice: remove the password from the environment
Remove-Item Env:\PGPASSWORD -ErrorAction SilentlyContinue
}
if ($Failures.Count -gt 0) {
Write-Host "Backup completed with errors in $TodayBackupDir. Failed: $($Failures -join ', ')" -ForegroundColor Red
exit 1
}
Write-Host "Backup completed successfully in $TodayBackupDir"
exit 0
- 📁 restore (replace
PRJwith your project name):
# Restore script for Cadmus databases (Windows PowerShell 5.1 or PowerShell 7+).
# Requires mongorestore (MongoDB Database Tools) and psql, dropdb, createdb (PostgreSQL client tools) in PATH.
# Usage: .\restore.ps1 -DateDir 20260928
# Or pass the folder name as the first positional argument: .\restore.ps1 20260928
# WARNING: existing data in the target databases is replaced by the backup.
param (
[Parameter(Mandatory = $true, Position = 0)]
[ValidatePattern('^\d{8}$')]
[string]$DateDir,
# A relative path is resolved against this script's folder, matching backup.ps1
[string]$BaseBackupDir = ".\backup"
)
# --- Configuration ---
$MongoPort = 27017
# Note: Using 127.0.0.1 requires your DB services to be configured with '127.0.0.1:PORT:PORT' in docker-compose.yml
$PgHost = "127.0.0.1"
$PgPort = 5432
$PgUser = "postgres"
$PgPassword = "postgres"
# --- Path Validation ---
if (-not [System.IO.Path]::IsPathRooted($BaseBackupDir)) {
$BaseBackupDir = Join-Path -Path $PSScriptRoot -ChildPath $BaseBackupDir
}
# Absolute path is required: .NET file APIs do not follow PowerShell's current location
$BaseBackupDir = [System.IO.Path]::GetFullPath($BaseBackupDir)
$TargetBackupDir = Join-Path -Path $BaseBackupDir -ChildPath $DateDir
if (-not (Test-Path -LiteralPath $TargetBackupDir -PathType Container)) {
Write-Host "ERROR: Backup directory $TargetBackupDir does not exist." -ForegroundColor Red
exit 1
}
# Ensure the required tools are available
foreach ($tool in "mongorestore", "psql", "dropdb", "createdb") {
if (-not (Get-Command $tool -CommandType Application -ErrorAction SilentlyContinue)) {
Write-Host "ERROR: $tool not found in PATH." -ForegroundColor Red
exit 1
}
}
$PsqlExe = (Get-Command "psql" -CommandType Application | Select-Object -First 1).Source
Write-Host "===================================================="
Write-Host " Starting Cadmus Database Restore from: $DateDir"
Write-Host "===================================================="
# Names of databases whose restore failed
$Failures = New-Object System.Collections.Generic.List[string]
# --- MongoDB Restore ---
function Import-MongoDump {
param (
[string]$Database,
[string]$InputFile
)
if (-not (Test-Path -LiteralPath $InputFile -PathType Leaf)) {
Write-Warning "$InputFile not found. Skipping."
return
}
Write-Host "Restoring $Database..."
# The archive already holds the database name, so --db is not used (it is deprecated with --archive).
# --drop clears seeded collections before writing backup data.
& mongorestore "--port=$MongoPort" "--nsInclude=$Database.*" --drop "--archive=$InputFile" --gzip
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: mongorestore failed for $Database (exit code $LASTEXITCODE)." -ForegroundColor Red
$script:Failures.Add($Database)
}
}
Write-Host "`n[1/2] Restoring MongoDB databases..." -ForegroundColor Yellow
Import-MongoDump -Database "cadmus-PRJ" -InputFile (Join-Path $TargetBackupDir "cadmus-PRJ-mongo.gz")
Import-MongoDump -Database "cadmus-PRJ-log" -InputFile (Join-Path $TargetBackupDir "cadmus-PRJ-log-mongo.gz")
# --- PostgreSQL Restore ---
# Recreates the database (the plain SQL dump would otherwise clash with seeded tables),
# then decompresses the dump and streams it into psql's standard input.
function Import-PgDumpGzip {
param (
[string]$Database,
[string]$InputFile
)
if (-not (Test-Path -LiteralPath $InputFile -PathType Leaf)) {
Write-Warning "$InputFile not found. Skipping."
return
}
Write-Host "Restoring $Database..."
# --force (PostgreSQL 13+) terminates open connections, e.g. from a running Cadmus API
& dropdb -h $PgHost -p $PgPort -U $PgUser -w --if-exists --force $Database
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: dropdb failed for $Database (exit code $LASTEXITCODE)." -ForegroundColor Red
$script:Failures.Add($Database)
return
}
& createdb -h $PgHost -p $PgPort -U $PgUser -w $Database
if ($LASTEXITCODE -ne 0) {
Write-Host "ERROR: createdb failed for $Database (exit code $LASTEXITCODE)." -ForegroundColor Red
$script:Failures.Add($Database)
return
}
$fileStream = $null
$gzipStream = $null
$process = $null
$exitCode = -1
try {
$fileStream = [System.IO.File]::OpenRead($InputFile)
$gzipStream = New-Object System.IO.Compression.GZipStream($fileStream, [System.IO.Compression.CompressionMode]::Decompress)
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = $PsqlExe
# -X: ignore psqlrc; -q: quiet; -1: single transaction; ON_ERROR_STOP: fail on first error
$psi.Arguments = "-h $PgHost -p $PgPort -U $PgUser -d `"$Database`" -w -X -q -1 -v ON_ERROR_STOP=1"
$psi.RedirectStandardInput = $true
$psi.UseShellExecute = $false
$process = [System.Diagnostics.Process]::Start($psi)
try {
$gzipStream.CopyTo($process.StandardInput.BaseStream)
}
catch [System.IO.IOException] {
# psql exited early (its error is already on the console); exit code is checked below
}
finally {
$process.StandardInput.Close()
}
$process.WaitForExit()
$exitCode = $process.ExitCode
}
catch {
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
}
finally {
if ($null -ne $gzipStream) { $gzipStream.Dispose() }
if ($null -ne $fileStream) { $fileStream.Dispose() }
if ($null -ne $process) { $process.Dispose() }
}
if ($exitCode -ne 0) {
Write-Host "ERROR: psql failed for $Database (exit code $exitCode)." -ForegroundColor Red
$script:Failures.Add($Database)
}
}
Write-Host "`n[2/2] Restoring PostgreSQL databases..." -ForegroundColor Yellow
# Export the PostgreSQL password for child processes
$env:PGPASSWORD = $PgPassword
try {
Import-PgDumpGzip -Database "cadmus-PRJ" -InputFile (Join-Path $TargetBackupDir "cadmus-PRJ-pgsql.gz")
Import-PgDumpGzip -Database "cadmus-PRJ-auth" -InputFile (Join-Path $TargetBackupDir "cadmus-PRJ-auth-pgsql.gz")
}
finally {
# Remove the password from the environment
Remove-Item Env:\PGPASSWORD -ErrorAction SilentlyContinue
}
if ($Failures.Count -gt 0) {
Write-Host "`nRestore completed with errors. Failed: $($Failures -join ', ')" -ForegroundColor Red
exit 1
}
Write-Host "`nRestore operation completed successfully!" -ForegroundColor Green
exit 0
Host Setup
The host would require the database client tools and FTP utility. Should you need to install them, you can follow the procedures outlined here.
MongoDB Client
This procedure is for Ubuntu 24 (“noble”):
curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor --yes
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt-get update
# this installs the shell and the backup/restore tools only
sudo apt-get install -y mongodb-mongosh mongodb-database-tools
💡 To restore a whole MongoDB database, use a command like:
mongorestore --drop --archive="cadmus-PRJ-mongo.gz" --gzip --db cadmus-PRJ. To restore a single collection, e.g. the facets, in an easy way, export thefacetscollection via a tool like Studio3T: you will get a folder named after the database, including a couple of.gzfiles for thefacetscollection. Upload this folder to the VM (e.g. via SCP) and run a command like this from the PARENT folder of the folder containing the uploaded folder:mongorestore --drop --nsInclude "cadmus-PRJ.facets" --gzip ./xfer. So, if the folder was uploaded to/opt/xfer, you must run this command from/opt.
Old procedure (for versions before 24, change version numbers as required):
wget -qO - https://www.mongodb.org/static/pgp/server-8.0.asc | sudo apt-key add -
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update
sudo apt install -y mongodb-database-tools
# for mongosh
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -sc)/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update
sudo apt install -y mongodb-mongosh
PostgreSQL Client
(1) add the APT repository:
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/pgdg.list
(2) import its GPG key:
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg
(3) Update the package list (if not recently done):
sudo apt update
(4) Install the client package (change client version accordingly):
sudo apt install -y postgresql-client-18
To open the client shell:
psql -h 127.0.0.1 -p 5432 -U postgres
LFTP Tool
Install the lftp tool:
sudo apt install -y lftp