Migrate Coolify Header Image

Coolify does not have a built-in feature to migrate itself from one server to another.

You will need to manually install Coolify on the new server and then copy over your data. This guide walks you through the process step-by-step.

This guide works for migrating a healthy or broken Coolify instance to a new server.

Note

We assume you have a new server ready and Coolify is not yet installed on it.


1. What to Migrate

To migrate Coolify, you need to move a few key pieces of data from your old server to the new one:

  • Coolify Database: This contains all your project configurations. It runs in a Docker container named coolify-db.
  • Application Key (APP_KEY): This is a secret key used to encrypt your database. Without it, your backup cannot be restored. It is stored in the .env file.
  • SSH Keys: Coolify uses these to connect to your servers.
  • Authorized Keys: These keys allow your servers to accept SSH connections from Coolify.

This guide will show you how to back up and transfer these items safely.

Coolify Migration Items Image


2. Back Up the Coolify Database

First, you need to back up your Coolify database. All of your instance's data is stored here.

There are three ways to do this:

Note

Use one of the other methods if you cannot access your Coolify dashboard.

Create a Backup Coolify Backup Page Image

  • Log in to your Coolify Dashboard.
  • Go to Settings and select the Backup tab.
  • Click Backup Now.

Save the Backup Location Coolify Backup Executions Image

  • Once the backup is done, the UI will show a download button and the backup's file path.
  • Copy this path and save it. You will need it later.

3. Run the Migration Script

To simplify the migration, we created a script that automates the process. It handles transferring files, installing Coolify on the new server, and restoring your data.

Follow these steps on your old server:

Create the script file

SSH into your old server and create a file named migration.sh:

touch migration.sh && chmod +x migration.sh

Paste the script

Open migration.sh in a text editor and paste the following code:

migration.sh
#!/bin/bash
 
### ========== MANUAL CONFIGURATION ==========
NEW_SERVER_IP="192.168.1.244"
NEW_SERVER_USER="root"
NEW_SERVER_PORT="22"
NEW_SERVER_AUTH_KEYS_FILE="/root/.ssh/authorized_keys"
 
SSH_PRIVATE_KEY_PATH="/root/.ssh/remote-server-ssh"
LOCAL_AUTH_KEYS_FILE="/root/.ssh/authorized_keys"
BACKUP_FILE="/data/coolify/backups/coolify/coolify-db-hostdockerinternal/pg-dump-coolify-1754489102.dmp"
### ========== MANUALCONFIGURATION ENDS HERE ==========
 
 
REMOTE_BACKUP_DIR="/root/coolify-backup"
ENV_FILE="/data/coolify/source/.env"
SSH_KEYS_DIR="/data/coolify/ssh/keys"
REMOTE_BACKUP_FILE="$REMOTE_BACKUP_DIR/$(basename "$BACKUP_FILE")"
 
LOG_PREFIX="[ Migration Agent ]"
CONTROL_SOCKET="/tmp/ssh_mux_socket"
 
LOG_DIR="$(pwd)/migration-logs"
mkdir -p "$LOG_DIR"
AGENT_LOG="$LOG_DIR/migration-agent.log"
DB_RESTORE_LOG="$LOG_DIR/db-restore.log"
INSTALL_LOG="$LOG_DIR/coolify-install.log"
FINAL_INSTALL_LOG="$LOG_DIR/coolify-final-install.log"
 
log() {
    echo "$LOG_PREFIX [ $1 ] $2" | tee -a "$AGENT_LOG"
}
 
check_success() {
    if [ $1 -eq 0 ]; then
        log "SUCCESS" "$2"
    else
        log "FAILED" "$2"
        cleanup_and_exit 1
    fi
}
 
cleanup_and_exit() {
    if [ $1 -eq 0 ]; then
        log "SUCCESS" "Migration completed successfully."
    else
        log "FAILED" "Migration failed."
    fi
 
    log "INFO" "Cleaning up SSH connection and background processes..."
    kill $HEALTH_CHECK_PID 2>/dev/null || true
    ssh -S "$CONTROL_SOCKET" -O exit "$NEW_SERVER_USER@$NEW_SERVER_IP" 2>/dev/null || true
    log "HEALTH CHECK" "SSH connection terminated."
    exit $1
}
 
 
trap cleanup_and_exit SIGINT
 
### ========== SSH SETUP ==========
log "INFO" "Starting ssh-agent..."
eval "$(ssh-agent -s)" >/dev/null
ssh-add "$SSH_PRIVATE_KEY_PATH" >/dev/null
check_success $? "SSH key added to agent."
 
log "INFO" "Establishing persistent SSH connection..."
ssh -fN -M -S "$CONTROL_SOCKET" -p "$NEW_SERVER_PORT" "$NEW_SERVER_USER@$NEW_SERVER_IP"
check_success $? "Persistent SSH connection established."
 
(while true; do
    if ssh -S "$CONTROL_SOCKET" -O check "$NEW_SERVER_USER@$NEW_SERVER_IP" 2>&1 | grep -q "Master running"; then
        log "HEALTH CHECK" "SSH connection is active."
    else
        log "HEALTH CHECK" "SSH connection lost."
        cleanup_and_exit 1
    fi
    sleep 20
done) &
HEALTH_CHECK_PID=$!
 
### ========== VALIDATION ==========
if [ ! -f "$BACKUP_FILE" ]; then
    log "FAILED" "Backup file not found at $BACKUP_FILE"
    cleanup_and_exit 1
fi
 
APP_KEY=$(grep "^APP_KEY=" "$ENV_FILE" | cut -d '=' -f2-)
if [ -z "$APP_KEY" ]; then
    log "FAILED" "APP_KEY not found in $ENV_FILE"
    cleanup_and_exit 1
fi
log "SUCCESS" "APP_KEY retrieved."
 
# more precise version extraction:
COOLIFY_IMAGE=$(docker ps --filter "name=coolify" --format '{{.Image}}' | grep coollabsio/coolify | head -n1)
COOLIFY_VERSION="${COOLIFY_IMAGE##*:}"
log "SUCCESS" "Detected Coolify version: $COOLIFY_VERSION"
 
### ========== INSTALL COOLIFY ==========
log "INFO" "Installing Coolify on new server..."
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -s $COOLIFY_VERSION" >"$INSTALL_LOG" 2>&1
grep -q "Your instance is ready to use" "$INSTALL_LOG"
check_success $? "Coolify install script completed."
 
### ========== TRANSFER FILES ==========
log "INFO" "Transferring backup and SSH keys..."
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "mkdir -p $REMOTE_BACKUP_DIR && rm -rf /data/coolify/ssh/keys/*"
scp -o ControlPath="$CONTROL_SOCKET" -P "$NEW_SERVER_PORT" "$BACKUP_FILE" "$NEW_SERVER_USER@$NEW_SERVER_IP:$REMOTE_BACKUP_FILE" >/dev/null
scp -o ControlPath="$CONTROL_SOCKET" -P "$NEW_SERVER_PORT" -r "$SSH_KEYS_DIR" "$NEW_SERVER_USER@$NEW_SERVER_IP:/data/coolify/ssh/" >/dev/null
check_success $? "Backup and SSH keys transferred."
 
# <— NEW STEP: append local authorized_keys to the remote authorized_keys file
log "INFO" "Appending local authorized_keys to remote $NEW_SERVER_AUTH_KEYS_FILE"
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "mkdir -p $(dirname $NEW_SERVER_AUTH_KEYS_FILE) && touch $NEW_SERVER_AUTH_KEYS_FILE && cat >> $NEW_SERVER_AUTH_KEYS_FILE" < "$LOCAL_AUTH_KEYS_FILE"
check_success $? "Authorized keys appended."
 
### ========== STOP CONTAINERS ==========
log "INFO" "Stopping all containers except coolify-db..."
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "docker ps --filter name=coolify --format '{{.Names}}' | grep -v 'coolify-db' | xargs -r docker stop" >/dev/null
check_success $? "Containers stopped."
 
### ========== RESTORE DATABASE ==========
log "INFO" "Restoring Coolify database..."
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "cat $REMOTE_BACKUP_FILE | docker exec -i coolify-db pg_restore --verbose --clean --no-acl --no-owner -U coolify -d coolify" >"$DB_RESTORE_LOG" 2>&1
check_success $? "Database restore complete."
 
### ========== UPDATE ENV FILE ==========
log "INFO" "Updating .env with previous APP_KEY..."
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "cd /data/coolify/source && sed -i '/^APP_PREVIOUS_KEYS=/d' .env && echo 'APP_PREVIOUS_KEYS=$APP_KEY' >> .env"
check_success $? ".env updated."
 
### ========== FINAL INSTALL OF RESTORE ==========
log "INFO" "Executing Coolify install script to apply restore changes..."
ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "bash -s" >"$FINAL_INSTALL_LOG" 2>&1 <<EOF
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash -s $COOLIFY_VERSION
EOF
 
log "INFO" "Waiting for install script finish (max 3 minutes)..."
for i in {1..18}; do
    sleep 10
    if grep -q "Your instance is ready to use" "$FINAL_INSTALL_LOG"; then
        log "SUCCESS" "Coolify install script completed successfully."
        break
    fi
done
 
if ! grep -q "Your instance is ready to use" "$FINAL_INSTALL_LOG"; then
    log "INFO" "Install script didn’t output expected success message. Checking Docker containers..."
    ssh -S "$CONTROL_SOCKET" "$NEW_SERVER_USER@$NEW_SERVER_IP" "
        docker ps --filter name=coolify --format '{{.Names}} {{.Status}}'
    " > "$LOG_DIR/docker-status.txt"
 
    if grep -q "coolify.*(healthy)" "$LOG_DIR/docker-status.txt"; then
        log "SUCCESS" "Coolify containers are running and healthy. Install likely succeeded."
    else
        log "FAILED" "Coolify install failed or containers are unhealthy. See logs in $FINAL_INSTALL_LOG and docker-status.txt"
        cleanup_and_exit 1
    fi
fi
 
### ========== CLEANUP ==========
cleanup_and_exit 0

Set up SSH access

The script needs to connect from your old server to your new server using SSH. Make sure you have an SSH key on the old server that can access the new server.

Configure the script variables

Before running the script, you must update the variables at the top to match your setup:

  • NEW_SERVER_IP: The IP address of your new server.
  • NEW_SERVER_USER: The user account for your new server (e.g., root).
  • NEW_SERVER_PORT: The SSH port of your new server (usually 22).
  • NEW_SERVER_AUTH_KEYS_FILE: The path to the authorized_keys file on your new server (e.g., /root/.ssh/authorized_keys).
  • SSH_PRIVATE_KEY_PATH: The path to the private SSH key on your old server that can access the new server.
  • LOCAL_AUTH_KEYS_FILE: The path to the authorized_keys file on your old server.
  • BACKUP_FILE: The full path to the Coolify backup file.

Run the migration

Execute the script:

./migration.sh

The migration will take a few minutes. Once it's done, you will see a Migration completed successfully message. You can then access your restored Coolify instance at http://<NEW_SERVER_IP>:8000.

Note

The migration script does not copy the contents of the /data/coolify/proxy directory. If you have custom proxy configurations, you will need to copy them manually.


4. Migrate Your Applications

This script only migrates the Coolify instance itself, not the applications you have deployed.

To migrate your applications, you need to move their data manually. Follow our separate guide for that: Migrate Applications.


Support

If you run into issues, join our Community Discord server and ask for help in the support channel.




On this page