Moved to a repo at https://github.com/Geczy/coolify-migration
-
Star
(126)
You must be signed in to star a gist -
Fork
(31)
You must be signed in to fork a gist
-
-
Save Geczy/83c1c77389be94ed4709fc283a0d7e23 to your computer and use it in GitHub Desktop.
Here's a modified version of @AspireOne's ssh-agent version. It fixes the volumes being separated wrong when extracting the volumes from a container.
#!/bin/bash
# This script will backup your Coolify instance and move everything to a new server. Docker volumes, Coolify database, and ssh keys
# 1. Script must run on the source server
# 2. Have all the containers running that you want to migrate
# Configuration - Modify as needed
sshKeyPath="$HOME/.ssh/your_private_key" # Key to destination server
destinationHost="server.example.com" # destination server IP or domain
# -- Shouldn't need to modify anything below --
backupSourceDir="/data/coolify/"
backupFileName="coolify_backup.tar.gz"
# Function to initialize ssh-agent and add the SSH key
initialize_ssh_agent() {
# Check if ssh-agent is already running
if [ -z "$SSH_AGENT_PID" ] || ! ps -p "$SSH_AGENT_PID" > /dev/null 2>&1; then
echo "🔄 Starting ssh-agent..."
eval "$(ssh-agent -s)"
if [ $? -ne 0 ]; then
echo "❌ Failed to start ssh-agent"
exit 1
fi
echo "✅ ssh-agent started"
else
echo "✅ ssh-agent is already running"
fi
# Add the SSH key to the agent
echo "🔒 Adding SSH key to ssh-agent"
ssh-add "$sshKeyPath"
if [ $? -ne 0 ]; then
echo "❌ Failed to add SSH key. Please ensure the passphrase is correct."
exit 1
fi
echo "✅ SSH key added to ssh-agent"
}
# Initialize ssh-agent and add the SSH key
initialize_ssh_agent
# Check if the source directory exists
if [ ! -d "$backupSourceDir" ]; then
echo "❌ Source directory $backupSourceDir does not exist"
exit 1
fi
echo "✅ Source directory exists"
# Check if the SSH key file exists
if [ ! -f "$sshKeyPath" ]; then
echo "❌ SSH key file $sshKeyPath does not exist"
exit 1
fi
echo "✅ SSH key file exists"
# Check if we can SSH to the destination server, ignore "The authenticity of host can't be established." errors
if ! ssh -o "StrictHostKeyChecking no" -o "ConnectTimeout=5" root@"$destinationHost" "exit"; then
echo "❌ SSH connection to $destinationHost failed"
exit 1
fi
echo "✅ SSH connection successful"
# Get the names of all running Docker containers
containerNames=$(docker ps --format '{{.Names}}')
# Initialize an empty string to hold the volume paths
volumePaths=""
for containerName in $containerNames; do
# Use a delimiter to separate the volume names
volumeNames=$(docker inspect --format '{{range .Mounts}}{{.Name}}{{print "\n"}}{{end}}' "$containerName")
# Now, we process each line (volume name) from the output
while IFS= read -r volumeName; do
# Check if the volumeName is not empty
if [ -n "$volumeName" ]; then
echo "Adding path: /var/lib/docker/volumes/$volumeName"
volumePaths="$volumePaths /var/lib/docker/volumes/$volumeName"
fi
done <<< "$volumeNames"
done
echo "Final volumePaths: $volumePaths"
# Calculate the total size of the volumes
# shellcheck disable=SC2086
totalSize=$(du -csh $volumePaths 2>/dev/null | grep total | awk '{print $1}')
# Print the total size of the volumes
echo "✅ Total size of volumes to migrate: $totalSize"
# Print size of backupSourceDir
backupSourceDirSize=$(du -csh "$backupSourceDir" 2>/dev/null | grep total | awk '{print $1}')
echo "✅ Size of the source directory: $backupSourceDirSize"
# Check if the backup file already exists
if [ ! -f "$backupFileName" ]; then
echo "🚸 Backup file does not exist, creating"
# Recommend stopping docker before creating the backup
echo "🚸 It's recommended to stop all Docker containers before creating the backup"
read -rp "Do you want to stop Docker? (y/n): " answer
if [[ "$answer" =~ ^[Yy]$ ]]; then
if ! systemctl stop docker; then
echo "❌ Docker stop failed"
exit 1
fi
echo "✅ Docker stopped"
else
echo "🚸 Docker not stopped, continuing with the backup"
fi
# shellcheck disable=SC2086
if ! tar --exclude='*.sock' -Pczf "$backupFileName" -C / "$backupSourceDir" "$HOME/.ssh/authorized_keys" $volumePaths; then
echo "❌ Backup file creation failed"
exit 1
fi
echo "✅ Backup file created"
else
echo "🚸 Backup file already exists, skipping creation"
fi
# Define the remote commands to be executed
remoteCommands="
# Check if Docker is a service
if systemctl is-active --quiet docker; then
# Stop Docker if it's a service
if ! systemctl stop docker; then
echo '❌ Docker stop failed';
exit 1;
fi
echo '✅ Docker stopped';
else
echo 'ℹ️ Docker is not a service, skipping stop command';
fi
echo '🚸 Saving existing authorized keys...';
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys_backup;
echo '🚸 Extracting backup file...';
if ! tar -Pxzf - -C /; then
echo '❌ Backup file extraction failed';
exit 1;
fi
echo '✅ Backup file extracted';
echo '🚸 Merging authorized keys...';
cat ~/.ssh/authorized_keys_backup ~/.ssh/authorized_keys | sort | uniq > ~/.ssh/authorized_keys_temp;
mv ~/.ssh/authorized_keys_temp ~/.ssh/authorized_keys;
chmod 600 ~/.ssh/authorized_keys;
echo '✅ Authorized keys merged';
if ! curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash; then
echo '❌ Coolify installation failed';
exit 1;
fi
echo '✅ Coolify installed';
"
# SSH to the destination server, execute the remote commands
if ! ssh root@"$destinationHost" "$remoteCommands" < "$backupFileName"; then
echo "❌ Remote commands execution or Docker restart failed"
exit 1
fi
echo "✅ Remote commands executed successfully"
# Clean up - Ask the user for confirmation before removing the local backup file
echo "Do you want to remove the local backup file? (y/n)"
read -r answer
if [[ "$answer" =~ ^[Yy]$ ]]; then
if ! rm -f "$backupFileName"; then
echo "❌ Failed to remove local backup file"
exit 1
fi
echo "✅ Local backup file removed"
else
echo "🚸 Local backup file not removed"
fi
# Kill ssh-agent if it was started by this script
if [ -n "$SSH_AGENT_PID" ]; then
echo "🔒 Stopping ssh-agent..."
eval "$(ssh-agent -k)"
echo "✅ ssh-agent stopped"
fi
At this point we're ironically pummeling this with unmanaged versions on a version control platform :P
Time to make this a repo and accept PRs? I could do it but it's only right that you do it @Geczy considering you took the initiative :)
Good idea, I've made the repo here! https://github.com/Geczy/coolify-migration
Also updated this gist with a readme linking to the above
Thanks everyone for your contributions! Feel free to open a PR to manage these wonderful changes that are being suggested.
Just wanted to thanks for this perfect script.
Great script, thanks.
I created a coolify db restore, if backing up locally.
Long term we need a baseline CLI similar to Plesk provides for installation, updates, and recovery.
Also reporting that the original script works perfectly with the expected setup on v4.0.0-beta.406
I see that this script allows us to migrate Coolify instance, but how are you guys handling application migrations? For instance, running the script won't migrate the application such as Ghost CMS with underlying data to a new server?
I see that this script allows us to migrate Coolify instance, but how are you guys handling application migrations? For instance, running the script won't migrate the application such as Ghost CMS with underlying data to a new server?
Yes. The script also copies the volumes of each application (e.g. Ghost CMS and its database) to the new server. After running it, simply go to the Coolify dashboard on the destination and “Redeploy” each app. This will cause Traefik/Compose to create new containers for the applications by mounting the migrated volumes, preserving all the content (posts, themes, databases, uploads, etc.).
I used Codeium Windsurf to create this version that moves a service from the main Coolify server to another server managed by Coolify.
Hope this is useful for someone else.