Skip to content

Instantly share code, notes, and snippets.

@camdenfullmer
Last active March 3, 2019 22:59
Show Gist options
  • Save camdenfullmer/6448454d6f9d6610056cd2f7fabbee30 to your computer and use it in GitHub Desktop.
Save camdenfullmer/6448454d6f9d6610056cd2f7fabbee30 to your computer and use it in GitHub Desktop.
A script that creates a Ghost publication on DigitalOcean.
#!/bin/bash
set -e
set -o pipefail
DROPLET_NAME=my-ghost-publication
DOMAIN=""
SUBDOMAIN=""
IMAGES_DIR=""
THEMES_DIR=""
KEYS_DIR="~/.create-ghost-publication/keys"
usage() { echo -e "OVERVIEW: Script to create a Ghost publication on DigitalOcean.\n\nUSAGE: $0 [options] domain-name (e.g. mypublication.com)\n\nOPTIONS:\n -s\tSubdomain to use for the publication.\n -i\tImages directory to import.\n -t\tThemes directory to import.\n -k\tKeys directory to use." 1>&2; exit 1; }
while getopts "s:i:t:k:" OPTION; do
case "${OPTION}" in
s)
SUBDOMAIN="$OPTARG"
;;
i)
IMAGES_DIR="$OPTARG"
;;
t)
THEMES_DIR="$OPTARG"
;;
k)
KEYS_DIR="$OPTARG"
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
DOMAIN=$1
# Check that domain was specified.
if [ -z "$DOMAIN" ]; then
usage
fi
# Check that we are running on a Mac.
if [ "$(uname)" != "Darwin" ]; then
echo "Your system is not supported. Only macOS is supported at this time."
exit 1
fi
# Check that brew is installed. If not attempt to install it.
if [ ! -x "$(command -v brew)" ]; then
echo "Installing brew…"
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
echo "Installed brew."
fi
# Check that doctl is installed. If not attempt to install it using brew.
if [ ! -x "$(command -v doctl)" ]; then
echo "Installing doctl…"
brew install doctl
echo "Installed doctl."
fi
# Check that doctl is authenticated. If not start authentication.
set +e # Need to capture an error.
AUTHED="$(! doctl account get 2>&1 > /dev/null)"
set -e
if [ ! -z "$AUTHED" ]; then
echo -e "\n\nPlease enter your access token for DigitalOcean.\n\nFor more information please visit https://www.digitalocean.com/docs/api/create-personal-access-token/ to learn how to create an access token for DigitalOcean.\n"
doctl auth init
echo "Authenticated with DigitalOcean."
fi
# Create a root ssh key.
mkdir -p "$KEYS_DIR"
if [ ! -f "$KEYS_DIR"/root_key ]; then
echo "Creating root SSH key…"
ssh-keygen -t rsa -N '' -f "$KEYS_DIR"/root_key
echo "Created root SSH key."
fi
# Get the root key fingerprint.
SSH_KEY_FINGERPRINT=$(doctl compute ssh-key list --no-header --format FingerPrint,Name | grep "Ghost Publication" | cut -b 1-47 || true)
if [ -z "$SSH_KEY_FINGERPRINT" ]; then
echo "Uploading SSH key to DigitalOcean…"
SSH_KEY_FINGERPRINT=$(doctl compute ssh-key create "Ghost Publication" --no-header --format FingerPrint --public-key "$(cat "$KEYS_DIR"/root_key.pub)")
echo "Uploaded key."
fi
# Create droplet.
DROPLET_ID=$(doctl compute droplet list --no-header --format ID,Name | grep $DROPLET_NAME | cut -c 1-9 || true)
if [ -z $DROPLET_ID ]; then
echo "Creating droplet…"
DROPLET_ID=$(doctl compute droplet create $DROPLET_NAME --enable-backups --enable-monitoring --region nyc1 --image ubuntu-18-04-x64 --size s-1vcpu-1gb --ssh-keys $SSH_KEY_FINGERPRINT --format ID --no-header --wait)
echo "Created droplet."
echo "Waiting for droplet to accept connections…"
sleep 30 # Need to wait a little extra time for droplet to boot up.
fi
DROPLET_IP=$(doctl compute droplet get $DROPLET_ID --no-header --format PublicIPv4)
# Create domain.
DOMAIN_EXISTS="$(doctl compute domain list --no-header --format Domain | grep -e $DOMAIN || true)"
if [ -z "$DOMAIN_EXISTS" ]; then
echo "Creating domain…"
doctl compute domain create $DOMAIN --ip-address $DROPLET_IP
echo "Created domain."
fi
# Create subdomain entry.
if [ ! -z "$SUBDOMAIN" ]; then
SUBDOMAIN_RECORD_EXISTS="$(doctl compute domain records list --no-header --format Type,Name $DOMAIN | grep $SUBDOMAIN || true)"
if [ -z "$SUBDOMAIN_RECORD_EXISTS" ]; then
echo "Creating subdomain record…"
doctl compute domain records create $DOMAIN --record-type A --record-name $SUBDOMAIN --record-data $DROPLET_IP
echo "Created subdomain record."
fi
fi
# Update apt.
echo "Updating system…"
COMMAND=$(cat <<EOF
apt-get -qy update
EOF
)
doctl compute ssh --ssh-user root --ssh-key-path "$KEYS_DIR"/root_key --ssh-command "$COMMAND" $DROPLET_ID
echo "Updated system."
# Set up ubuntu user.
USERNAME=ubuntu
COMMAND=$(cat <<EOF
if getent passwd "$USERNAME" >/dev/null; then
echo "User ubuntu already exists."
else
echo "Creating ubuntu user…"
adduser --disabled-password --gecos 'Ubuntu user' $USERNAME &&
usermod -aG sudo $USERNAME &&
echo '$USERNAME ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers.d/90-cloud-init-users
echo "Created user ubuntu."
fi
EOF
)
doctl compute ssh --ssh-user root --ssh-key-path "$KEYS_DIR"/root_key --ssh-command "$COMMAND" $DROPLET_ID
# Create ubuntu ssh key.
if [ ! -f "$KEYS_DIR"/ubuntu_key ]; then
echo "Creating ubuntu SSH key…"
ssh-keygen -t rsa -N '' -f "$KEYS_DIR"/ubuntu_key
echo "Created ubuntu SSH key."
fi
# Set up ssh.
COMMAND=$(cat <<EOF
runuser -l $USERNAME -c "rm -rf ~/.ssh &&
mkdir -p ~/.ssh &&
touch ~/.ssh/authorized_keys &&
chmod -R go= ~/.ssh &&
cat >> ~/.ssh/authorized_keys"
EOF
)
echo "Setting up SSH access…"
cat "$KEYS_DIR"/ubuntu_key.pub | ssh -i "$KEYS_DIR"/root_key root@$DROPLET_IP "$COMMAND"
echo "Set up SSH access."
# Set up firewall.
COMMAND=$(cat <<EOF
sudo ufw allow OpenSSH &&
sudo ufw allow 80 &&
sudo ufw allow 443 &&
sudo ufw --force enable
EOF
)
echo "Setting up firewall…"
doctl compute ssh --ssh-user $USERNAME --ssh-key-path "$KEYS_DIR"/ubuntu_key --ssh-command "$COMMAND" $DROPLET_ID
echo "Set up firewall."
# Set up docker.
COMMAND=$(cat <<EOF
sudo apt-get -qy install apt-transport-https ca-certificates curl software-properties-common &&
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - &&
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" &&
sudo apt-get update &&
sudo apt-get -qy install docker-ce docker-compose
EOF
)
echo "Setting up firewall…"
doctl compute ssh --ssh-user $USERNAME --ssh-key-path "$KEYS_DIR"/ubuntu_key --ssh-command "$COMMAND" $DROPLET_ID
echo "Set up Docker."
# Copy images.
if [ ! -z "$IMAGES_DIR" ]; then
if [ ! -d "$IMAGES_DIR" ]; then
echo "The images directory ($IMAGES_DIR) does not exist or is not a directory."
exit 1
fi
echo "Copying images…"
doctl compute ssh --ssh-user $USERNAME --ssh-key-path "$KEYS_DIR"/ubuntu_key --ssh-command "rm -rf ~/ghost/content/images && mkdir -p ~/ghost/content/images" $DROPLET_ID
scp -r -i "$KEYS_DIR"/ubuntu_key "$IMAGES_DIR"/* $USERNAME@$DROPLET_IP:~/ghost/content/images
echo "Copied images."
fi
# Copy themes.
if [ ! -z "$THEMES_DIR" ]; then
if [ ! -d "$THEMES_DIR" ]; then
echo "The themes directory ($THEMES_DIR) does not exist or is not a directory."
exit 1
fi
echo "Copying themes…"
doctl compute ssh --ssh-user $USERNAME --ssh-key-path "$KEYS_DIR"/ubuntu_key --ssh-command "rm -rf ~/ghost/content/themes && mkdir -p ~/ghost/content/themes" $DROPLET_ID
scp -r -i "$KEYS_DIR"/ubuntu_key "$THEMES_DIR"/* $USERNAME@$DROPLET_IP:~/ghost/content/themes
echo "Copied themes."
fi
HOST=$DOMAIN
if [ ! -z "$SUBDOMAIN" ]; then
HOST="$SUBDOMAIN.$DOMAIN"
fi
COMMAND=$(cat <<EOF
(sudo docker run --detach \
--name nginx-proxy \
--publish 80:80 \
--restart always \
--publish 443:443 \
--volume /etc/nginx/certs:/etc/nginx/certs \
--volume /etc/nginx/vhost.d:/etc/nginx/vhost.d \
--volume /usr/share/nginx/html:/usr/share/nginx/html \
--volume /var/run/docker.sock:/tmp/docker.sock:ro \
jwilder/nginx-proxy && sleep 60) || true &&
sudo docker run --detach \
--name nginx-proxy-letsencrypt \
--restart always \
--volumes-from nginx-proxy \
--volume /var/run/docker.sock:/var/run/docker.sock:ro \
jrcs/letsencrypt-nginx-proxy-companion || true &&
sudo docker pull ghost &&
sudo docker kill ghost || true &&
sudo docker rm ghost || true &&
sudo docker run --detach \
--name ghost \
--restart always \
--env "VIRTUAL_HOST=$HOST" \
--env "VIRTUAL_PORT=2368" \
--env "LETSENCRYPT_HOST=$HOST" \
--env "url=https://${HOST}" \
--expose 2368 \
--volume /home/$USERNAME/ghost/content:/var/lib/ghost/content \
ghost
EOF
)
echo "Starting Ghost…"
doctl compute ssh --ssh-user $USERNAME --ssh-key-path "$KEYS_DIR"/ubuntu_key --ssh-command "$COMMAND" $DROPLET_ID
echo "Ghost is running"
echo -e "\nYour Ghost publication is now available at https://$HOST. To finish setting up your publication please vist https://$HOST/ghost/."
# Create a root ssh key.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment