Using Chat-GPT to Automate Ghost CMS Deployments

Is Chat-GPT better than a developer with 20 years of experience? I put Chat-GPT to the test to write a script to deploy Ghost CMS websites.

Using Chat-GPT to Automate Ghost CMS Deployments
Photo by Emiliano Vittoriosi / Unsplash

TL;DR: full working solution at the bottom. Or you can view the final working solution on Github.

I recently chose Ghost CMS for my personal blog. A current project I'm working on aims to deploy thousands of blog-enabled websites.

Here's the two key aims I have for the project:

  1. Minimize costs (in order to make the project profitable)
  2. Allow a bulk-creation of sites
  3. Completely automatic (no messing about with SSL certificates)

Ghost CMS already uses acme.sh to automate SSL certificate issuances and installation, so I figured the script should use that too.

Attempt #1: Simple Prompt

I figured this was worth a shot, and could probably get me something close to workable just with a simple Chat-GPT prompt. Here was my original prompt:

Write a bash script to automatically set up a new Ghost CMS website using MySQL DB on ubuntu with acmesh [sic] to provision ssl certificate.
In this script, we will set up a new Ghost CMS website using MySQL as the database on Ubuntu, and we will use acme.sh to provision an SSL certificate. Before running the script, make sure you have the following prerequisites:

1. domain name pointing to your server's IP address
2. Ubuntu server with root access
3. Port 80 and 443 open in your firewall

Save the following script as setup_ghost.sh and update the required variables at the beginning of the script. Then, run it as root (sudo bash setup_ghost.sh):
#!/bin/bash

# Variables
DOMAIN="example.com"              # Your domain name
EMAIL="your-email@example.com"    # Your email address for Let's Encrypt registration
MYSQL_ROOT_PASSWORD="your_mysql_root_password" # MySQL root password
GHOST_DB_NAME="ghost_db"          # Ghost CMS database name
GHOST_DB_USER="ghost_user"        # Ghost CMS database user
GHOST_DB_PASSWORD="ghost_password" # Ghost CMS database user password

# Update the system
apt update
apt upgrade -y

# Install required packages
apt install -y curl wget nginx mysql-server nodejs npm

# Configure MySQL
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE DATABASE ${GHOST_DB_NAME};"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE USER '${GHOST_DB_USER}'@'localhost' IDENTIFIED BY '${GHOST_DB_PASSWORD}';"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "GRANT ALL PRIVILEGES ON ${GHOST_DB_NAME}.* TO '${GHOST_DB_USER}'@'localhost';"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "FLUSH PRIVILEGES;"

# Install Ghost CLI
npm install -g ghost-cli

# Create a directory for Ghost installation
mkdir -p /var/www/ghost
chown -R $USER:$USER /var/www/ghost
chmod 755 /var/www/ghost

# Install Ghost CMS
cd /var/www/ghost
ghost install --db mysql --dbhost localhost --dbuser ${GHOST_DB_USER} --dbpass ${GHOST_DB_PASSWORD} --dbname ${GHOST_DB_NAME} --url "http://${DOMAIN}" --no-prompt --no-setup-nginx --no-setup-ssl --no-setup-systemd

# Configure Nginx
wget -O /etc/nginx/sites-available/ghost https://raw.githubusercontent.com/TryGhost/Ghost-CLI/master/extensions/nginx/templates/ssl-params.conf

cat > /etc/nginx/sites-available/ghost <<EOL
server {
    listen 80;
    server_name ${DOMAIN};
    return 301 https://\$host\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ${DOMAIN};

    ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;

    include /etc/nginx/sites-available/ghost;

    location / {
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header Host \$http_host;
        proxy_pass http://127.0.0.1:2368;
    }
}
EOL

ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default
systemctl restart nginx

# Install acme.sh and issue SSL certificate
curl https://get.acme.sh | sh
source ~/.bashrc
acme.sh --issue -d ${DOMAIN} --webroot /var/www/ghost/system/nginx-root/ --email ${EMAIL} --reloadcmd "system

Hm, not too bad! But this won't work out of the box.

Attempt #2: Install Directory

This is the offending bit:

# Create a directory for Ghost installation
mkdir -p /var/www/ghost
chown -R $USER:$USER /var/www/ghost
chmod 755 /var/www/ghost

We need to create multiple sites with this script. Installing them all in the same folder, named ghost obviously won't work. Let's ask Chat-GPT to rework this:

Add a variable to that script to change the installation directory.
You can easily add a variable to change the installation directory in the script. Add a new variable called GHOST_INSTALL_DIR at the beginning of the script and update the script accordingly:
#!/bin/bash

# Variables
DOMAIN="example.com"              # Your domain name
EMAIL="your-email@example.com"    # Your email address for Let's Encrypt registration
MYSQL_ROOT_PASSWORD="your_mysql_root_password" # MySQL root password
GHOST_DB_NAME="ghost_db"          # Ghost CMS database name
GHOST_DB_USER="ghost_user"        # Ghost CMS database user
GHOST_DB_PASSWORD="ghost_password" # Ghost CMS database user password
GHOST_INSTALL_DIR="/var/www/ghost" # Ghost CMS installation directory

# Update the system
apt update
apt upgrade -y

# Install required packages
apt install -y curl wget nginx mysql-server nodejs npm

# Configure MySQL
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE DATABASE ${GHOST_DB_NAME};"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE USER '${GHOST_DB_USER}'@'localhost' IDENTIFIED BY '${GHOST_DB_PASSWORD}';"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "GRANT ALL PRIVILEGES ON ${GHOST_DB_NAME}.* TO '${GHOST_DB_USER}'@'localhost';"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "FLUSH PRIVILEGES;"

# Install Ghost CLI
npm install -g ghost-cli

# Create a directory for Ghost installation
mkdir -p ${GHOST_INSTALL_DIR}
chown -R $USER:$USER ${GHOST_INSTALL_DIR}
chmod 755 ${GHOST_INSTALL_DIR}

# Install Ghost CMS
cd ${GHOST_INSTALL_DIR}
ghost install --db mysql --dbhost localhost --dbuser ${GHOST_DB_USER} --dbpass ${GHOST_DB_PASSWORD} --dbname ${GHOST_DB_NAME} --url "http://${DOMAIN}" --no-prompt --no-setup-nginx --no-setup-ssl --no-setup-systemd

# Configure Nginx
wget -O /etc/nginx/sites-available/ghost https://raw.githubusercontent.com/TryGhost/Ghost-CLI/master/extensions/nginx/templates/ssl-params.conf

cat > /etc/nginx/sites-available/ghost <<EOL
server {
    listen 80;
    server_name ${DOMAIN};
    return 301 https://\$host\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ${DOMAIN};

    ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;

    include /etc/nginx/sites-available/ghost;

    location / {
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header Host \$http_host;
        proxy_pass http://127.0.0.1:2368;
    }
}
EOL

ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default
systemctl restart nginx

# Install acme.sh and issue SSL certificate
curl https://get.acme.sh | sh
source ~/.bashrc
acme.sh --issue -d ${DOMAIN} --webroot ${GHOST_INSTALL_DIR}/system/nginx-root/ --email ${EMAIL} --reloadcmd "systemctl restart nginx"

# Install SSL certificate
acme.sh --install-cert -d ${DOMAIN} --cert-file /etc/letsencrypt/live/${DOMAIN}/cert.pem --key-file /etc/letsencrypt/live/${DOMAIN}/privkey.pem --fullchain-file /etc/letsencrypt/live/${DOMAIN}/

Derp, that wasn't actually all that helpful!

The nginx configuration still relies on the name ghost:

cat > /etc/nginx/sites-available/ghost <<EOL
server {
    listen 80;
    server_name ${DOMAIN};
    return 301 https://\$host\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ${DOMAIN};

    ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;

    include /etc/nginx/sites-available/ghost;

    location / {
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header Host \$http_host;
        proxy_pass http://127.0.0.1:2368;
    }
}
EOL

ln -s /etc/nginx/sites-available/ghost /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default

Attempt #3: Simplify

Reworking the Chat-GPT Output

At this point it was easier for me to just edit the script than to try to engineer a precise prompt to get it correct.

Here's what I came up with:

#!/bin/bash

# Public inputs
GHOST_SITE_NAME="example2"
GHOST_BASE_DOMAIN="yourdomain.com"
SSL_EMAIL="youremail@yourcompany.com"

# Secret script inputs
MYSQL_ROOT_PASSWORD="changeme"

# Generated inputs
GHOST_DOMAIN="${GHOST_SITE_NAME}.${GHOST_BASE_DOMAIN}"
GHOST_DB_NAME="${GHOST_SITE_NAME}_ghost_db"
GHOST_DB_USER_RANDOM=$((1 + $RANDOM % 10))
GHOST_DB_USER="${GHOST_SITE_NAME}_ghost_user_${GHOST_DB_USER_RANDOM}"
GHOST_INSTALL_DIR="/var/www/${GHOST_SITE_NAME}"

# Configure MySQL
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE DATABASE ${GHOST_DB_NAME};"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "CREATE USER '${GHOST_DB_USER}'@'localhost' IDENTIFIED BY '${GHOST_DB_PASSWORD}';"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "GRANT ALL PRIVILEGES ON ${GHOST_DB_NAME}.* TO '${GHOST_DB_USER}'@'localhost';"
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e "FLUSH PRIVILEGES;"

# Create a directory for Ghost installation
mkdir -p ${GHOST_INSTALL_DIR}
chown -R $USER:$USER ${GHOST_INSTALL_DIR}
chmod 755 ${GHOST_INSTALL_DIR}

# Install Ghost CMS
cd ${GHOST_INSTALL_DIR}
ghost install --db mysql --dbhost localhost --dbuser ${GHOST_DB_USER} --dbpass ${GHOST_DB_PASSWORD} --dbname ${GHOST_DB_NAME} --url "http://${DOMAIN}" --no-prompt --no-setup-nginx --no-setup-ssl --no-setup-systemd

# Manually configure nginx ...

But wait, why are we passing:

--noset-up-nginx --no-setup-ssl --no-setup-systemd

If Ghost can do those for us automatically, shouldn't we let it?

This is where I realized my mistake in my original prompt:

Write a bash script to automatically set up a new Ghost CMS website using MySQL DB on ubuntu with acme.sh to provision ssl certificate.

Derp! I've told Chat-GPT to make this more complicated than they need to be. We can just remove those --no flags and let Ghost do the magic itself!

So far so good! This is exciting...

Final Step: DNS Records

My DNS is hosted on GoDaddy, and fortunately they have a very straightforward REST API for this type of thing (documented nicely using Open API / Swagger):

From GoDaddy's V1 REST API

This is so straightforward I didn't even bother using Chat-GPT.

In my use-case, I have a main domain and for each site I create a subdomain using a CNAME record. Here's the bash script I wrote to do this:

#!/bin/bash

# Public inputs
GHOST_SITE_NAME="example2"
GHOST_BASE_DOMAIN="somedomain.com"

# Secret inputs
GODADDY_API_KEY="changeme"
GODADDY_API_SECRET="changeme"

# GoDaddy API
GODADDY_API_URL="https://api.godaddy.com/v1/domains/$GHOST_BASE_DOMAIN/records/CNAME/$GHOST_SITE_NAME"
GODADDY_REQUEST_BODY="[{\"data\":\"@\",\"name\":\"$GHOST_SITE_NAME\",\"ttl\":3600,\"type\":\"CNAME\"}]"

# Make the request
curl -X PUT $GODADDY_API_URL \
	-H "Authorization: sso-key $GODADDY_API_KEY:$GODADDY_API_SECRET" \
	-H "Accept: application/json" \
	-H "Content-Type: application/json" \
	-d $GODADDY_REQUEST_BODY
result=$?

# See the result
echo "Result was: $result"

And this works like a charm! The final step was just wiring this all up together and connecting it to my DevOps infrastructure.

Giving Chat-GPT a Shot

Let's see how Chat-GPT would do with this.

Create a bash script to use GoDaddy's REST API to add a CNAME record to a domain.
To create a bash script that uses GoDaddy's REST API to add a CNAME record to a domain, you will need the following:

1. An API key and secret from GoDaddy (you can generate them here: https://developer.godaddy.com/keys)
2. The domain you want to modify
3. The subdomain you want to create as a CNAME record
4. The target domain for the CNAME record

Save the following script as add_cname_godaddy.sh and update the required variables at the beginning of the script. Then, run the script (bash add_cname_godaddy.sh):
#!/bin/bash

# Variables
API_KEY="your_api_key"
API_SECRET="your_api_secret"
DOMAIN="example.com"             # Your domain name
SUBDOMAIN="subdomain"            # The subdomain you want to create as a CNAME record
TARGET_DOMAIN="target.example.com." # The target domain for the CNAME record (include the trailing dot)

# Function to get the current CNAME record
get_cname_record() {
  curl -s -X GET "https://api.godaddy.com/v1/domains/${DOMAIN}/records/CNAME/${SUBDOMAIN}" \
       -H "Authorization: sso-key ${API_KEY}:${API_SECRET}" \
       -H "Content-Type: application/json"
}

# Function to add/update the CNAME record
add_cname_record() {
  curl -s -X PUT "https://api.godaddy.com/v1/domains/${DOMAIN}/records/CNAME/${SUBDOMAIN}" \
       -H "Authorization: sso-key ${API_KEY}:${API_SECRET}" \
       -H "Content-Type: application/json" \
       -d "[{\"data\": \"${TARGET_DOMAIN}\", \"ttl\": 3600}]"
}

# Get the current CNAME record
CURRENT_CNAME_RECORD=$(get_cname_record)

if [ -z "${CURRENT_CNAME_RECORD}" ] || [ "${CURRENT_CNAME_RECORD}" == "[]" ]; then
  echo "Adding CNAME record for ${SUBDOMAIN}.${DOMAIN} pointing to ${TARGET_DOMAIN}"
  add_cname_record
  echo "CNAME record added successfully."
else
  echo "Updating CNAME record for ${SUBDOMAIN}.${DOMAIN} to point to ${TARGET_DOMAIN}"
  add_cname_record
  echo "CNAME record updated successfully."
fi

Well, shucks. That's even better than what I wrote.

Putting it All Together

After various tweaking, here's the final script. I used additional Chat-GPT prompts to make the script a bit more robust, allowing passing arguments, validating required args, etc.

Here's some of my prompts along the way:

Handling CLI Arguments

Write a bash script that accepts the following named variables as inputs: domain, subdomain, ssl-email, godaddy-api-key, godaddy-api-secret, mysql-root-password
#!/bin/bash

# Default values
DOMAIN=""
SUBDOMAIN=""
SSL_EMAIL=""
GODADDY_API_KEY=""
GODADDY_API_SECRET=""
MYSQL_ROOT_PASSWORD=""

# Function to print the usage
print_usage() {
  echo "Usage: $0 [OPTIONS]"
  echo "  -d, --domain               Domain name"
  echo "  -s, --subdomain            Subdomain"
  echo "  -e, --ssl-email            SSL email"
  echo "  -k, --godaddy-api-key      GoDaddy API key"
  echo "  -r, --godaddy-api-secret   GoDaddy API secret"
  echo "  -p, --mysql-root-password  MySQL root password"
  echo ""
  echo "Example:"
  echo "  $0 -d example.com -s subdomain -e email@example.com -k api_key -r api_secret -p mysql_root_password"
}

# Parse input arguments
while [ "$#" -gt 0 ]; do
  case "$1" in
    -d|--domain)
      DOMAIN="$2"
      shift 2
      ;;
    -s|--subdomain)
      SUBDOMAIN="$2"
      shift 2
      ;;
    -e|--ssl-email)
      SSL_EMAIL="$2"
      shift 2
      ;;
    -k|--godaddy-api-key)
      GODADDY_API_KEY="$2"
      shift 2
      ;;
    -r|--godaddy-api-secret)
      GODADDY_API_SECRET="$2"
      shift 2
      ;;
    -p|--mysql-root-password)
      MYSQL_ROOT_PASSWORD="$2"
      shift 2
      ;;
    *)
      print_usage
      exit 1
      ;;
  esac
done

# Check if all required variables are provided
if [ -z "$DOMAIN" ] || [ -z "$SUBDOMAIN" ] || [ -z "$SSL_EMAIL" ] || [ -z "$GODADDY_API_KEY" ] || [ -z "$GODADDY_API_SECRET" ] || [ -z "$MYSQL_ROOT_PASSWORD" ]; then
  echo "Error: Missing required arguments."
  print_usage
  exit 1
fi

# Print the provided variables
echo "Domain: $DOMAIN"
echo "Subdomain: $SUBDOMAIN"
echo "SSL Email: $SSL_EMAIL"
echo "GoDaddy API Key: $GODADDY_API_KEY"
echo "GoDaddy API Secret: $GODADDY_API_SECRET"
echo "MySQL Root Password: $MYSQL_ROOT_PASSWORD"

Confirmation Dialog

Write a bash script to prompt to confirm and exit if not yes.
#!/bin/bash

# Function to prompt user confirmation
confirm_action() {
  read -p "Do you want to proceed? (yes/no): " response
  case "$response" in
    [yY][eE][sS]|[yY])
      echo "Proceeding with the action..."
      ;;
    *)
      echo "Exiting the script..."
      exit 1
      ;;
  esac
}

# Main script
echo "This script will perform an action that requires your confirmation."
confirm_action
echo "Perform your action here."

# Rest of the script
echo "Script execution completed."

Adding a No-Prompt Option

Write a bash script that sets a variable to true if a flag is present, regardless of if a value is provided.
#!/bin/bash

# Default value for the variable
my_var=false

# Function to print the usage
print_usage() {
  echo "Usage: $0 [OPTIONS]"
  echo "  -f   Set the 'my_var' variable to true"
  echo ""
  echo "Example:"
  echo "  $0 -f"
}

# Parse input arguments
while getopts ":f" opt; do
  case "${opt}" in
    f)
      my_var=true
      ;;
    \?)
      print_usage
      exit 1
      ;;
  esac
done

# Print the value of 'my_var'
echo "my_var: ${my_var}"

Check for Failed Steps

Write a bash script to check that the previous command exited with a zero status code.
#!/bin/bash

# Function to run a command and check if it exited with a zero status code
run_command_and_check() {
  # Replace 'command_to_run' with the command you want to run
  command_to_run
  local exit_status=$?

  if [ $exit_status -eq 0 ]; then
    echo "The previous command exited with a zero status code (successful)."
  else
    echo "The previous command exited with a non-zero status code (unsuccessful). Exit code: $exit_status"
  fi
}

# Main script
run_command_and_check

Check if DB Already Exists

Write a bash script to check if a database exists.
#!/bin/bash

# Set your MySQL credentials
MYSQL_USER="root"
MYSQL_PASSWORD="your_mysql_root_password"

# Function to check if a MySQL database exists
check_mysql_database_exists() {
  local database_name="$1"
  local db_exists=$(mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -se "SELECT EXISTS(SELECT 1 FROM information_schema.schemata WHERE schema_name = '$database_name');")

  if [ "$db_exists" -eq 1 ]; then
    echo "The MySQL database '$database_name' exists."
  else
    echo "The MySQL database '$database_name' does not exist."
  fi
}

# Main script
mysql_database_name="example_database"
check_mysql_database_exists "$mysql_database_name"

Final Working Solution

Chat-GPT was far more effective than re-leaning the nuances of BASH. Here's the final working version I'm using (also available on Github):

#!/bin/bash

# Default values
SITE_NAME=""
DOMAIN=""
SSL_EMAIL=""
GODADDY_API_KEY=""
GODADDY_API_SECRET=""
MYSQL_ROOT_PASSWORD=""
NO_PROMPT=false

# Function to print the usage
print_usage() {
  echo "Usage: $0 [OPTIONS]"
  echo "  -s, --site-name            Site name (subdomain)"
  echo "  -d, --domain               Domain name"
  echo "  -e, --ssl-email            SSL email"
  echo "  -k, --godaddy-api-key      GoDaddy API key"
  echo "  -r, --godaddy-api-secret   GoDaddy API secret"
  echo "  -p, --mysql-root-password  MySQL root password"
  echo "  -n, --no-prompt            Run in non-interactive mode"
  echo ""
  echo "Example:"
  echo "  $0 -d example.com -s subdomain -e email@example.com -k api_key -r api_secret -p mysql_root_password --no-prompt"
}

make_url_safe() {
  local input_string="$1"
  local url_safe_string=$(echo "$input_string" | sed 's/[^a-zA-Z0-9-]/-/g')
  echo "$url_safe_string"
}

make_db_safe() {
  local input_string="$1"
  local url_safe_string=$(echo "$input_string" | sed 's/[^a-zA-Z0-9_]/_/g')
  echo "$url_safe_string"
}

confirm_to_proceed() {
  # only prompt in interactive mode
  if [ "$NO_PROMPT" = false ]; then
    read -p "Do you want to proceed? (Yes/[No]): " response
    case "$response" in
      [yY][eE][sS]|[yY])
        echo "Proceeding with the action..."
        ;;
      *)
        echo "Cancelled."
        exit 1
        ;;
    esac
  fi
}

assert_required_arguments() {
  # Check if all required variables are provided
  if [ -z "$SITE_NAME" ] || [ -z "$DOMAIN" ] || [ -z "$SSL_EMAIL" ] || [ -z "$GODADDY_API_KEY" ] || [ -z "$GODADDY_API_SECRET" ] || [ -z "$MYSQL_ROOT_PASSWORD" ]; then
    echo "Error: Missing required arguments."
    print_usage
    exit 2
  fi
}

get_cname_record() {
  curl -s -X GET "https://api.godaddy.com/v1/domains/${DOMAIN}/records/CNAME/${SITE_NAME}" \
    -H "Authorization: sso-key ${GODADDY_API_KEY}:${GODADDY_API_SECRET}" \
    -H "Content-Type: application/json"
  local exit_status=$?
  if [ $exit_status -ne 0 ]; then
    echo "Error: Failed to get current DNS."
    exit 3
  fi
}

update_cname_record() {
  curl -s -X PUT "https://api.godaddy.com/v1/domains/${DOMAIN}/records/CNAME/${SITE_NAME}" \
    -H "Authorization: sso-key ${GODADDY_API_KEY}:${GODADDY_API_SECRET}" \
    -H "Content-Type: application/json" \
    -d "[{\"data\": \"@\", \"ttl\": 3600}]"
  local exit_status=$?
  if [ $exit_status -ne 0 ]; then
    echo "Error: Failed to configure DNS."
    exit 4
  fi
}

configure_dns() {
  local current_cname_record=$(get_cname_record)
  if [ -z "${current_cname_record}" ] || [ "${current_cname_record}" == "[]" ]; then
    echo "Adding CNAME record for ${SITE_NAME}.${DOMAIN} pointing to ${DOMAIN}"
    update_cname_record
    echo "CNAME record added successfully."
  else
    echo "Updating CNAME record for ${SITE_NAME}.${DOMAIN} to point to ${DOMAIN}"
    update_cname_record
    echo "CNAME record updated successfully."
  fi
}

create_mysql_db() {
  local database_name="$1"
  local db_exists=$(mysql -u root -p"$MYSQL_ROOT_PASSWORD" -se "SELECT EXISTS(SELECT 1 FROM information_schema.schemata WHERE schema_name = '$database_name');")

  if [ "$db_exists" -eq 1 ]; then
    echo "The MySQL database '$database_name' already exists."
  else
    echo "The MySQL database '$database_name' does not exist. Creating it..."
    mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -e "CREATE DATABASE ${GHOST_DB_NAME};"
    local exit_status=$?
    if [ $exit_status -ne 0 ]; then
      echo "Error: Failed to create MySQL DB"
      exit 5
    fi
  fi
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    -d|--domain)
      DOMAIN="$2"
      shift 2
      ;;
    -s|--subdomain)
      RAW_SITE_NAME="$2"
      shift 2
      ;;
    -e|--ssl-email)
      SSL_EMAIL="$2"
      shift 2
      ;;
    -k|--godaddy-api-key)
      GODADDY_API_KEY="$2"
      shift 2
      ;;
    -r|--godaddy-api-secret)
      GODADDY_API_SECRET="$2"
      shift 2
      ;;
    -p|--mysql-root-password)
      MYSQL_ROOT_PASSWORD="$2"
      shift 2
      ;;
    -n|--no-prompt)
      NO_PROMPT=true
      shift
      ;;
    *)
      print_usage
      exit 1
      ;;
  esac
done

SITE_NAME=$(make_url_safe "$RAW_SITE_NAME")
TARGET_DOMAIN="$SITE_NAME.$DOMAIN"
GHOST_DB_NAME_PREFIX=$(make_db_safe "$RAW_SITE_NAME")
GHOST_DB_NAME="${GHOST_DB_NAME_PREFIX}_ghost_db"
GHOST_DOMAIN="${GHOST_SITE_NAME}.${GHOST_BASE_DOMAIN}"
GHOST_INSTALL_DIR="/var/www/${SITE_NAME}"

assert_required_arguments

echo ""
echo "-- Deploy New Ghost Site ---- "
echo -e "Site Name:\t\t$SITE_NAME"
echo -e "Target Domain:\t\t$TARGET_DOMAIN"
echo -e "SSL Email:\t\t$SSL_EMAIL"
echo -e "MySQL DB:\t\t$GHOST_DB_NAME"
echo -e "Install Dir:\t\t$GHOST_INSTALL_DIR"
echo ""

confirm_to_proceed

echo ""
echo " > Configuring DNS"
get_cname_record
configure_dns
echo ""

echo ""
echo " > Setting up MySQL"
create_mysql_db $GHOST_DB_NAME
echo ""

echo ""
echo " > Installing Ghost"
mkdir -p ${GHOST_INSTALL_DIR}
chown -R $USER:$USER ${GHOST_INSTALL_DIR}
chmod 755 ${GHOST_INSTALL_DIR}
cd ${GHOST_INSTALL_DIR}
ghost install \
	--db mysql \
	--dbhost localhost \
	--dbuser root \
	--dbpass ${MYSQL_ROOT_PASSWORD} \
	--dbname ${GHOST_DB_NAME} \
	--url "http://${TARGET_DOMAIN}" \
	--sslemail "${SSL_EMAIL}" \
	--no-prompt
echo ""