mirror of
https://github.com/d0zingcat/ghost-docker.git
synced 2026-05-13 15:09:34 +00:00
658 lines
23 KiB
Bash
658 lines
23 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
# Constants
|
|
readonly GHOST_UID=1000
|
|
readonly GHOST_GID=1000
|
|
readonly MYSQL_TIMEOUT=120
|
|
readonly DISK_SPACE_SAFETY_FACTOR=1.5
|
|
readonly TEMP_SQL_FILE="${PWD}/data/ghost_import.sql"
|
|
readonly RECOVERY_SCRIPT="${PWD}/recovery_instructions.sh"
|
|
|
|
# Global variables
|
|
current_location=""
|
|
mysql_user=""
|
|
mysql_password=""
|
|
ghost_service_name=""
|
|
|
|
# Function to convert bytes to human readable format
|
|
human_readable() {
|
|
local bytes=$1
|
|
local units=("B" "KB" "MB" "GB" "TB")
|
|
local unit=0
|
|
local size=$bytes
|
|
|
|
while (( $(echo "$size > 1024" | bc -l) )) && (( unit < 4 )); do
|
|
size=$(echo "scale=2; $size / 1024" | bc -l)
|
|
((unit++))
|
|
done
|
|
|
|
echo "${size} ${units[$unit]}"
|
|
}
|
|
|
|
# Function to get size in bytes
|
|
get_size_bytes() {
|
|
local path=$1
|
|
if [[ -d "$path" ]]; then
|
|
du -sb "$path" 2>/dev/null | cut -f1
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Cleanup function
|
|
cleanup() {
|
|
local exit_code=$?
|
|
|
|
if [[ -f "$TEMP_SQL_FILE" ]]; then
|
|
echo "Cleaning up temporary files..."
|
|
rm "$TEMP_SQL_FILE"
|
|
fi
|
|
|
|
if [[ $exit_code -ne 0 && -f "$RECOVERY_SCRIPT" ]]; then
|
|
echo ""
|
|
echo "════════════════════════════════════════════════════════════"
|
|
echo "❌ MIGRATION FAILED!"
|
|
echo "════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "Don't worry - your data is safe!"
|
|
echo ""
|
|
echo "To restore your original Ghost installation, run:"
|
|
echo " bash $RECOVERY_SCRIPT"
|
|
echo ""
|
|
echo "Need help? Check the migration logs above for error details."
|
|
echo "════════════════════════════════════════════════════════════"
|
|
fi
|
|
|
|
exit $exit_code
|
|
}
|
|
|
|
# Set trap for cleanup
|
|
trap cleanup EXIT INT TERM
|
|
|
|
# Create recovery script
|
|
create_recovery_script() {
|
|
local service_name="$1"
|
|
cat > "$RECOVERY_SCRIPT" << EOF
|
|
#!/usr/bin/env bash
|
|
# Recovery script generated by Ghost migration on $(date)
|
|
# This script will restore your original Ghost installation
|
|
|
|
set -euo pipefail
|
|
|
|
echo "Restoring original Ghost installation..."
|
|
|
|
# Stop any Docker containers that might have been started
|
|
docker compose down 2>/dev/null || true
|
|
|
|
# Re-enable and start the original Ghost service
|
|
if [[ -n "${service_name}" ]]; then
|
|
systemctl enable "${service_name}" 2>/dev/null || true
|
|
systemctl start "${service_name}" 2>/dev/null || true
|
|
echo "Original Ghost installation has been restored."
|
|
echo "You can check the status with: systemctl status ${service_name}"
|
|
else
|
|
echo "Note: Ghost service was not yet stopped, so no restoration needed."
|
|
echo "Your original installation should still be running."
|
|
fi
|
|
EOF
|
|
|
|
chmod +x "$RECOVERY_SCRIPT"
|
|
echo "✓ Recovery script created at: $RECOVERY_SCRIPT"
|
|
}
|
|
|
|
# Validate MySQL connection
|
|
validate_mysql_connection() {
|
|
local host=$1
|
|
local database=$2
|
|
local port=$3
|
|
local user=$4
|
|
local password=$5
|
|
|
|
echo "Testing MySQL connection..."
|
|
|
|
if mysql -h"$host" -u"$user" -p"$password" -P"$port" -e "SELECT 1 FROM information_schema.tables WHERE table_schema='$database' LIMIT 1;" &>/dev/null; then
|
|
echo "✓ MySQL connection successful"
|
|
return 0
|
|
else
|
|
echo "✗ MySQL connection failed"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Check prerequisites
|
|
check_prerequisites() {
|
|
# Check we're running as root
|
|
if [[ "$EUID" -ne 0 ]]; then
|
|
echo "Sorry, this script must be run as root!"
|
|
exit 1
|
|
fi
|
|
|
|
# Check required commands
|
|
local required_commands=("jq" "docker" "bc" "mysql" "mysqldump" "rsync")
|
|
local missing_commands=()
|
|
|
|
for cmd in "${required_commands[@]}"; do
|
|
if ! command -v "$cmd" &>/dev/null; then
|
|
missing_commands+=("$cmd")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#missing_commands[@]} -gt 0 ]]; then
|
|
echo "The following required commands are not installed:"
|
|
printf ' - %s\n' "${missing_commands[@]}"
|
|
echo "Please install them first."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Show migration summary
|
|
show_migration_summary() {
|
|
echo "
|
|
═══════════════════════════════════════════════════════════════════
|
|
GHOST MIGRATION SUMMARY
|
|
═══════════════════════════════════════════════════════════════════
|
|
|
|
This script will migrate your Ghost CLI installation to Docker.
|
|
|
|
WHAT WILL HAPPEN:
|
|
✓ Validate MySQL credentials
|
|
✓ Stop your current Ghost installation
|
|
✓ Copy content directory to Docker mount
|
|
✓ Export and import your database to a Docker based MySQL instance
|
|
✓ Start Ghost in Docker container
|
|
✓ Optionally configure Caddy Webserver for HTTPS
|
|
|
|
WHAT WONT HAPPEN:
|
|
✓ No data will be deleted
|
|
✓ Recovery script will be created
|
|
✓ Original installation remains intact
|
|
|
|
REQUIREMENTS:
|
|
✓ .env file configured for Docker
|
|
✓ MySQL credentials with dump permissions
|
|
✓ Sufficient disk space for migration
|
|
|
|
═══════════════════════════════════════════════════════════════════
|
|
"
|
|
}
|
|
|
|
# Migrate content directory
|
|
migrate_content() {
|
|
local source="${current_location}/content/"
|
|
local dest="${PWD}/data/ghost/"
|
|
|
|
echo "Starting content migration..."
|
|
echo "Source: $source"
|
|
echo "Destination: $dest"
|
|
echo ""
|
|
|
|
# Create destination directory
|
|
mkdir -p "$dest"
|
|
|
|
# Copy with progress
|
|
echo "Copying files..."
|
|
rsync --info=progress2 -aH "$source" "$dest"
|
|
|
|
echo ""
|
|
echo "Setting permissions for Ghost container (UID: $GHOST_UID, GID: $GHOST_GID)..."
|
|
chown -R ${GHOST_UID}:${GHOST_GID} "$dest"
|
|
|
|
echo "✓ Content migration completed"
|
|
}
|
|
|
|
# Test if we can dump database with given credentials
|
|
test_mysql_dump() {
|
|
local host=$1
|
|
local database=$2
|
|
local port=$3
|
|
local user=$4
|
|
local password=$5
|
|
|
|
# Try a minimal dump to test permissions
|
|
if MYSQL_PWD="$password" mysqldump --no-tablespaces --no-data -P"$port" -h"$host" -u"$user" "$database" >/dev/null 2>&1; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Export and import database
|
|
migrate_database() {
|
|
local mysql_host
|
|
local mysql_database
|
|
local mysql_port
|
|
mysql_host=$(jq -r < "${current_location}/config.production.json" '.database.connection.host')
|
|
mysql_database=$(jq -r < "${current_location}/config.production.json" '.database.connection.database')
|
|
mysql_port=$(jq -r < "${current_location}/config.production.json" '.database.connection.port')
|
|
# Default to 3306 if port is missing or null
|
|
if [[ -z "$mysql_port" || "$mysql_port" == "null" ]]; then
|
|
mysql_port=3306
|
|
fi
|
|
|
|
echo "Exporting database from $mysql_host..."
|
|
|
|
# Export database with proper error handling
|
|
local dump_output
|
|
local dump_status
|
|
dump_output=$(MYSQL_PWD="$mysql_password" mysqldump --no-tablespaces -h"$mysql_host" -u"$mysql_user" -P"$mysql_port" "$mysql_database" 2>&1 > "$TEMP_SQL_FILE")
|
|
dump_status=$?
|
|
|
|
# Check for errors in output (mysqldump may return 0 even with some errors)
|
|
if [[ $dump_status -ne 0 ]] || [[ "$dump_output" =~ "Error:" ]]; then
|
|
echo ""
|
|
echo "ERROR: Failed to export database"
|
|
if [[ "$dump_output" =~ "PROCESS privilege" ]]; then
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "The MySQL user '$mysql_user' needs the PROCESS privilege."
|
|
echo ""
|
|
echo "To fix this, connect to MySQL as a privileged user and run:"
|
|
echo " GRANT PROCESS ON *.* TO '$mysql_user'@'%';"
|
|
echo " FLUSH PRIVILEGES;"
|
|
echo ""
|
|
echo "Or retry with a user that has sufficient privileges (e.g., root)."
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
elif [[ -n "$dump_output" ]]; then
|
|
echo "Error details: $dump_output"
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Verify the dump file exists and has content
|
|
if [[ ! -f "$TEMP_SQL_FILE" ]] || [[ ! -s "$TEMP_SQL_FILE" ]]; then
|
|
echo ""
|
|
echo "ERROR: Database dump file is empty or missing"
|
|
echo "This might indicate insufficient disk space or permissions issues."
|
|
exit 1
|
|
fi
|
|
|
|
local dump_size
|
|
dump_size=$(human_readable "$(stat -c%s "$TEMP_SQL_FILE")")
|
|
echo "✓ Database exported successfully ($dump_size)"
|
|
|
|
# Wait for MySQL to be ready
|
|
echo -n "Waiting for MySQL container to be ready"
|
|
local counter=0
|
|
until [ "$(docker compose ps db --format json | jq -r '.Health')" = "healthy" ] || [ $counter -eq $MYSQL_TIMEOUT ]; do
|
|
echo -n "."
|
|
sleep 1
|
|
((counter++)) || true
|
|
done
|
|
|
|
if [[ $counter -eq $MYSQL_TIMEOUT ]]; then
|
|
echo ""
|
|
echo "ERROR: Timed out waiting for MySQL container"
|
|
exit 1
|
|
fi
|
|
|
|
echo " ✓"
|
|
|
|
# Import database
|
|
echo "Importing database into Docker MySQL..."
|
|
local MYSQL_ROOT_PASSWORD
|
|
MYSQL_ROOT_PASSWORD=$(grep DATABASE_ROOT_PASSWORD "$PWD/.env" | cut -d '=' -f 2-)
|
|
if ! docker compose exec -e MYSQL_PWD="$MYSQL_ROOT_PASSWORD" -T db sh -c 'exec mysql -uroot $MYSQL_DATABASE' < "$TEMP_SQL_FILE"; then
|
|
echo "ERROR: Failed to import database"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ Database migration completed"
|
|
|
|
# Clean up SQL file
|
|
rm -f "$TEMP_SQL_FILE"
|
|
}
|
|
|
|
# Find Ghost installations in /var/www/
|
|
find_ghost_installations() {
|
|
local installations=()
|
|
|
|
# Search one level deep in /var/www/
|
|
if [[ -d "/var/www" ]]; then
|
|
for dir in /var/www/*/; do
|
|
# Skip if not a directory
|
|
[[ ! -d "$dir" ]] && continue
|
|
|
|
# Remove trailing slash
|
|
dir="${dir%/}"
|
|
|
|
# Check if it's a valid Ghost installation
|
|
if [[ -f "${dir}/.ghost-cli" ]] && [[ -d "${dir}/content" ]]; then
|
|
# Additional validation - check if config file exists
|
|
if [[ -f "${dir}/config.production.json" ]]; then
|
|
installations+=("$dir")
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
|
|
printf '%s\n' "${installations[@]}"
|
|
}
|
|
|
|
# Main script starts here
|
|
main() {
|
|
check_prerequisites
|
|
|
|
echo "WARNING: This script is currently in beta, please ensure you have a backup!"
|
|
|
|
show_migration_summary
|
|
|
|
read -rp 'Ready to proceed with migration? (y/n): ' confirm
|
|
if [[ "${confirm,,}" != "y" ]]; then
|
|
echo "Migration cancelled."
|
|
exit 0
|
|
fi
|
|
|
|
# Search for Ghost installations
|
|
echo ""
|
|
echo "Searching for Ghost installations in /var/www/..."
|
|
|
|
local ghost_installations=()
|
|
while IFS= read -r line; do
|
|
[[ -n "$line" ]] && ghost_installations+=("$line")
|
|
done < <(find_ghost_installations)
|
|
|
|
# Get installation location
|
|
if [[ ${#ghost_installations[@]} -gt 0 ]]; then
|
|
echo ""
|
|
echo "Found ${#ghost_installations[@]} Ghost installation(s) in /var/www/:"
|
|
echo ""
|
|
|
|
# Display found installations with numbers
|
|
local i=1
|
|
for installation in "${ghost_installations[@]}"; do
|
|
local site_name
|
|
site_name=$(basename "$installation")
|
|
echo " $i) $site_name (${installation})"
|
|
((i++))
|
|
done
|
|
echo " $i) Enter a different path"
|
|
echo ""
|
|
|
|
read -rp "Select an installation (1-$i): " selection
|
|
|
|
# Validate selection
|
|
if [[ "$selection" =~ ^[0-9]+$ ]] && [[ $selection -ge 1 ]] && [[ $selection -le $i ]]; then
|
|
if [[ $selection -eq $i ]]; then
|
|
# User wants to enter a different path
|
|
read -rp 'Enter your current Ghost installation path: ' current_location
|
|
else
|
|
# User selected a found installation
|
|
current_location="${ghost_installations[$((selection-1))]}"
|
|
echo "Selected: $current_location"
|
|
fi
|
|
else
|
|
echo "Invalid selection"
|
|
exit 1
|
|
fi
|
|
else
|
|
# No installations found, ask for path directly
|
|
echo ""
|
|
echo "No Ghost installations found in /var/www/"
|
|
read -rp 'Enter your current Ghost installation path: ' current_location
|
|
fi
|
|
|
|
if [[ -z "$current_location" ]]; then
|
|
echo "ERROR: Installation path is required"
|
|
exit 1
|
|
fi
|
|
|
|
# Validate Ghost installation
|
|
if [[ ! -f "${current_location}/.ghost-cli" ]]; then
|
|
echo "ERROR: No Ghost-CLI installation found at ${current_location}"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -d "${current_location}/content" ]]; then
|
|
echo "ERROR: No content directory found at ${current_location}/content"
|
|
exit 1
|
|
fi
|
|
|
|
# Check for .env file
|
|
if [[ ! -f "${PWD}/.env" ]]; then
|
|
echo "ERROR: Please create a .env file for the Docker installation first"
|
|
exit 1
|
|
fi
|
|
|
|
# Get Ghost service name
|
|
ghost_service_name="ghost_$(jq -r < "${current_location}/.ghost-cli" '.name')"
|
|
|
|
# Get database configuration
|
|
local mysql_host
|
|
local mysql_database
|
|
local mysql_port
|
|
local ghost_mysql_user
|
|
local ghost_mysql_password
|
|
mysql_host=$(jq -r < "${current_location}/config.production.json" '.database.connection.host')
|
|
mysql_database=$(jq -r < "${current_location}/config.production.json" '.database.connection.database')
|
|
mysql_port=$(jq -r < "${current_location}/config.production.json" '.database.connection.port')
|
|
# Default to 3306 if port is missing or null
|
|
if [[ -z "$mysql_port" || "$mysql_port" == "null" ]]; then
|
|
mysql_port=3306
|
|
fi
|
|
ghost_mysql_user=$(jq -r < "${current_location}/config.production.json" '.database.connection.user')
|
|
ghost_mysql_password=$(jq -r < "${current_location}/config.production.json" '.database.connection.password')
|
|
|
|
# Check disk space
|
|
echo ""
|
|
echo "Checking disk space requirements..."
|
|
|
|
local content_size
|
|
local content_size_human
|
|
local required_space
|
|
local required_space_human
|
|
local available_space
|
|
local available_space_human
|
|
|
|
content_size=$(get_size_bytes "${current_location}/content")
|
|
content_size_human=$(human_readable "$content_size")
|
|
required_space=$(echo "$content_size * $DISK_SPACE_SAFETY_FACTOR" | bc | cut -d'.' -f1)
|
|
required_space_human=$(human_readable "$required_space")
|
|
available_space=$(df -B1 "${PWD}" | tail -1 | awk '{print $4}')
|
|
available_space_human=$(human_readable "$available_space")
|
|
|
|
echo " Content size: ${content_size_human}"
|
|
echo " Required space: ${required_space_human}"
|
|
echo " Available space: ${available_space_human}"
|
|
|
|
if (( available_space < required_space )); then
|
|
echo ""
|
|
echo "ERROR: Insufficient disk space!"
|
|
echo "Need ${required_space_human} but only ${available_space_human} available."
|
|
exit 1
|
|
fi
|
|
|
|
echo "✓ Disk space check passed"
|
|
echo ""
|
|
|
|
# Try Ghost's own credentials first
|
|
echo "Testing database export with Ghost's credentials..."
|
|
if test_mysql_dump "$mysql_host" "$mysql_database" "$mysql_port" "$ghost_mysql_user" "$ghost_mysql_password"; then
|
|
echo "✓ Ghost's credentials have sufficient privileges"
|
|
mysql_user="$ghost_mysql_user"
|
|
mysql_password="$ghost_mysql_password"
|
|
else
|
|
echo "Ghost's database user doesn't have sufficient privileges for export."
|
|
echo "Please provide credentials for a MySQL user with dump privileges."
|
|
echo ""
|
|
|
|
# Get MySQL credentials and validate
|
|
read -rp "MySQL user for database export (default: root): " mysql_user
|
|
mysql_user=${mysql_user:-root}
|
|
|
|
# Get password securely
|
|
echo -n "MySQL password for ${mysql_user}: "
|
|
read -rs mysql_password
|
|
echo ""
|
|
|
|
# Validate connection
|
|
if ! validate_mysql_connection "$mysql_host" "$mysql_database" "$mysql_port" "$mysql_user" "$mysql_password"; then
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "Could not connect to MySQL database."
|
|
echo ""
|
|
echo "Please verify:"
|
|
echo " • MySQL service is running"
|
|
echo " • Credentials are correct"
|
|
echo " • User has access from this host"
|
|
echo " • Database name is correct"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
exit 1
|
|
fi
|
|
|
|
# Test dump permissions
|
|
if ! test_mysql_dump "$mysql_host" "$mysql_database" "$mysql_port" "$mysql_user" "$mysql_password"; then
|
|
echo ""
|
|
echo "ERROR: The provided user doesn't have sufficient privileges for database export."
|
|
echo "Please ensure the user has the necessary privileges or try a different user."
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Create recovery script (with empty service name since we haven't stopped anything yet)
|
|
create_recovery_script ""
|
|
|
|
# Final confirmation before stopping Ghost
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "⚠️ YOUR SITE WILL BE UNAVAILABLE DURING MIGRATION"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "The next steps will:"
|
|
echo " 1. Stop your Ghost service"
|
|
echo " 2. Migrate your content and database"
|
|
echo " a. Your new content directory will be at ${PWD}/data/ghost/"
|
|
echo " b. Your new MySQL database will be at ${PWD}/data/mysql/"
|
|
echo " 3. Start Ghost in Docker"
|
|
echo ""
|
|
echo "If anything goes wrong, run: bash $RECOVERY_SCRIPT"
|
|
echo ""
|
|
read -rp 'Continue with migration? This will make your site unavailable. (y/n): ' confirm
|
|
|
|
if [[ "${confirm,,}" != "y" ]]; then
|
|
echo "Migration cancelled."
|
|
rm -f "$RECOVERY_SCRIPT"
|
|
exit 0
|
|
fi
|
|
|
|
# Stop Ghost service
|
|
echo ""
|
|
echo "Stopping Ghost service..."
|
|
|
|
# Update recovery script with actual service name before stopping
|
|
create_recovery_script "$ghost_service_name"
|
|
|
|
if ! systemctl stop "$ghost_service_name"; then
|
|
echo "ERROR: Failed to stop Ghost service"
|
|
echo "Please check: systemctl status $ghost_service_name"
|
|
exit 1
|
|
fi
|
|
|
|
systemctl disable "$ghost_service_name" 2>/dev/null || true
|
|
echo "✓ Ghost service stopped"
|
|
|
|
# Start MySQL container
|
|
echo "Starting MySQL container for migration..."
|
|
docker compose up db -d
|
|
|
|
# Migrate content
|
|
echo ""
|
|
migrate_content
|
|
|
|
# Migrate database
|
|
echo ""
|
|
migrate_database
|
|
|
|
# Import configuration
|
|
echo ""
|
|
echo "Importing configuration from existing installation..."
|
|
echo ""
|
|
node "${PWD}/scripts/config-to-env.js" "${current_location}/config.production.json"
|
|
echo ""
|
|
|
|
echo -e "\n# Configuration imported from existing Ghost install at ${current_location}" >> "${PWD}/.env"
|
|
node "${PWD}/scripts/config-to-env.js" "${current_location}/config.production.json" >> "${PWD}/.env"
|
|
echo "✓ Configuration imported"
|
|
|
|
# Start Ghost
|
|
echo ""
|
|
echo "Starting Ghost container..."
|
|
docker compose up ghost -d
|
|
echo "✓ Ghost is running in Docker"
|
|
|
|
# Caddy setup
|
|
echo ""
|
|
read -rp 'Start Caddy Webserver for automatic HTTPS? This will stop Nginx. (y/n): ' confirm
|
|
if [[ "${confirm,,}" == "y" ]]; then
|
|
echo "Stopping Nginx..."
|
|
systemctl stop nginx -q || true
|
|
systemctl disable nginx -q || true
|
|
|
|
echo "Starting Caddy..."
|
|
docker compose up caddy -d
|
|
|
|
local domain
|
|
domain=$(grep 'DOMAIN' "${PWD}/.env" | cut -d '=' -f 2-)
|
|
echo ""
|
|
echo "✓ Caddy Webserver is running!"
|
|
echo "✓ Your site is available at: https://${domain}"
|
|
else
|
|
local ghost_port
|
|
ghost_port=$(grep 'GHOST_PORT' "${PWD}/.env" | cut -d '=' -f 2-)
|
|
echo ""
|
|
echo "✓ Ghost is now running"
|
|
echo " To finish migration, configure your webserver to forward traffic to 127.0.0.1:${ghost_port}"
|
|
fi
|
|
|
|
# Success! Remove recovery script
|
|
rm -f "$RECOVERY_SCRIPT"
|
|
|
|
echo ""
|
|
echo "════════════════════════════════════════════════════════════"
|
|
echo "✓ MIGRATION COMPLETED SUCCESSFULLY!"
|
|
echo "════════════════════════════════════════════════════════════"
|
|
echo ""
|
|
echo "Your Ghost site is now running in Docker!"
|
|
echo ""
|
|
echo "IMPORTANT INFORMATION:"
|
|
echo " • Original files: $current_location"
|
|
echo " • Original database: $mysql_database on $mysql_host"
|
|
echo " • New content location: ${PWD}/data/ghost/"
|
|
echo " • Configuration: ${PWD}/.env"
|
|
echo ""
|
|
echo "QUICK START COMMANDS:"
|
|
echo " View logs: docker compose logs -f ghost"
|
|
echo " Check status: docker compose ps"
|
|
echo " Stop Ghost: docker compose down"
|
|
echo " Start Ghost: docker compose up -d"
|
|
echo ""
|
|
echo "TROUBLESHOOTING:"
|
|
echo " • If site is unreachable, check: docker compose logs caddy"
|
|
echo " • For 502 errors, Ghost may still be starting (check logs)"
|
|
echo " • Database issues: docker compose logs db"
|
|
echo ""
|
|
echo "UPGRADES:"
|
|
echo " 1. git pull"
|
|
echo " 2. docker compose pull"
|
|
echo " 3. docker compose up -d"
|
|
echo " Always backup before major upgrades!"
|
|
echo ""
|
|
echo "HELP GUIDE:"
|
|
echo " For a comprehensive list of commands and troubleshooting tips:"
|
|
echo " ./help"
|
|
echo ""
|
|
echo "CLEANUP:"
|
|
echo "Once you're checked over the migration you can remove the old installation files and database by running:"
|
|
echo ""
|
|
echo " rm -r $current_location/"
|
|
echo " mysql -h$mysql_host -u$mysql_user -p -P$mysql_port -e 'DROP DATABASE IF EXISTS ${mysql_database}'"
|
|
echo ""
|
|
echo "This will remove the old Ghost CLI and Ghost 5.x installation"
|
|
echo ""
|
|
echo "════════════════════════════════════════════════════════════"
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|