In this guide I will attempt to explain how I was able to migrate my entire Uptime Kuma back end MariaDB to a new host machine. This serves as the alterative in version 2 since the Backup/Restore function has been depricated.
#Setup Information:
To add some context so you can gauge how similar our setups are, here is my docker-compose.yml file
services:
uptime-kuma:
image: louislam/uptime-kuma:2
restart: unless-stopped
volumes:
- /uptime-kuma/data:/app/data
ports:
# <Host Port>:<Container Port>
- "3009:3001"You can see here that the only important detail is /uptime-kuma/data/
So we need to backup /uptime-kuma/data/ and restore it onto the new machine
Backup Script
To back up this directory I used a BASH script to backup the MariaDB within the /data directory and drop the backup inside /uptime-kuma/backups
#!/bin/bash
# Uptime Kuma Backup Script
# Performs a live SQL dump of the embedded MariaDB database
# Schedule via cron: 0 2 * * * root /usr/local/bin/backup-uptimekuma.sh >> /var/log/uptimekuma-backup.log 2>&1
BACKUP_DIR="/uptime-kuma/backups"
RETENTION_DAYS=30
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
CONTAINER="uptime-kuma-uptime-kuma-1"
mkdir -p "$BACKUP_DIR"
# Verify container is running
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
echo "$(date) ERROR: Container $CONTAINER is not running. Backup skipped."
exit 1
fi
# Dump via the running container's MariaDB socket
docker exec "$CONTAINER" \
mariadb-dump --skip-lock-tables -S /app/data/run/mariadb.sock kuma \
| gzip > "$BACKUP_DIR/kuma-$TIMESTAMP.sql.gz"
# Verify backup isn't empty or truncated
if [ ! -s "$BACKUP_DIR/kuma-$TIMESTAMP.sql.gz" ]; then
echo "$(date) ERROR: Backup file is empty!"
exit 1
fi
LAST_LINE=$(zcat "$BACKUP_DIR/kuma-$TIMESTAMP.sql.gz" | tail -1)
if [ "$LAST_LINE" != "-- Dump completed" ]; then
echo "$(date) WARNING: Backup may be incomplete! Last line: $LAST_LINE"
fi
# Grab config files
cp /uptime-kuma/data/db-config.json "$BACKUP_DIR/db-config-$TIMESTAMP.json" 2>/dev/null
cp /uptime-kuma/compose.yaml "$BACKUP_DIR/compose-$TIMESTAMP.yaml" 2>/dev/null
# Prune old backups
find "$BACKUP_DIR" -name "kuma-*.sql.gz" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "db-config-*.json" -mtime +$RETENTION_DAYS -delete
find "$BACKUP_DIR" -name "compose-*.yaml" -mtime +$RETENTION_DAYS -delete
FILESIZE=$(du -h "$BACKUP_DIR/kuma-$TIMESTAMP.sql.gz" | cut -f1)
echo "$(date) Backup complete: kuma-$TIMESTAMP.sql.gz ($FILESIZE)"
Then I made a cron job out of it, however you just need to run the script once.
btw, to run the script, you run to do
sudo bash backupscript.sh
Transferring the backup
I chose to use SFTP however you can do literally whatever you want to move the files over, essentially you will need to copy the files that look like this
db-config-20260210-133044.json
kuma-20260210-133044.sql.gz
Notice how the days match, if you were running this as a cron job make sure you pull the .json and .sql from the same day, then just send over your files. On the new host system I chose to use the same directory structure so I created the directories on the new host
# On the New Host
sudo mkdir -p /uptime-kuma/data
sudo mkdir -p /uptime-kuma/backupsYou will transfer the files into the /backup directory. DO NOT transfer them into /data immediately unless you hate yourself and your data.
Restoring the backup on the new host
I will assume now that your files are transferred into /uptime-kuma/backup on the new host
Also make sure the new host has docker installed
Next, using the same compose file, bring up the container as an empty uptime-kuma instance to allow for database initialization.
# on the new host
sudo nano docker-compose.yml
# paste in the compose CTRL+SHIFT+V
# paste in your compose, CTRL+X + CTRL+Y + ENTER to save
docker compose up -d
# wait for database initialisation
you can check the logs with
docker logs -f uptime-kuma
# if your container is named something different check the name with 'docker ps'
# once that is done, bring down the container
docker stop uptime-kumaNow that the container is shut down, and the database was able to initialize, then we can insert the data. To do that, run these commands
cp /uptime-kuma/backups/db-config-20260212-020001.json /uptime-kuma/data/db-config.json
docker compose up -d Once that starts up, it will be time for the big import
zcat /uptime-kuma/backups/kuma-20260212-020001.sql.gz | \
docker exec -i uptime-kuma-uptime-kuma-1 \
mariadb -S /app/data/run/mariadb.sock kumaThis command will import the SQL file into the new blank mariaDB, this can take a while depending on how large of a backup you are importing.
Then when that finishes up, restart the container
docker restart uptime-kuma-1Now you can verify that your data has been 100% transfered

