Last active
March 3, 2019 22:59
-
-
Save camdenfullmer/6448454d6f9d6610056cd2f7fabbee30 to your computer and use it in GitHub Desktop.
A script that creates a Ghost publication on DigitalOcean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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