Available for Elixir Consulting.

Terraform on Linode Notes

Posted on

Over vacation I worked through a small project to use Terraform on Linode to provision a new webserver for my personal website. The following is a collection of notes and resources from the experience.

Project Goals / Areas of Improvement:

  • Since the addition of the guildflow.com static website, anyone who was attempting to load a HTTPS version of mikezornek.com would be met with a security warning as the browser was attempting to load the SSL cert for guildflow.com when serving up mikezornek.com.
  • The lack of SSL to mikezornek.com has historically been intentional.
  • The Linode serving my static sites uses Ubuntu 16.04 LTS, which is going to be EOL on April 30, 2021 and so it’d be good to get one a new LTS version.
  • This is a good excuse to experiment with Terraform, which is something I’ve been learning in support of some possible Guildflow infrastructure updates.

Quick Review of the MikeZornek.com Infrastructure and Deployment

  • MikeZornek is a static site. I like static sites as they are cheaper to serve and easier to keep secure. I have used WordPress in the distant pass but I was lazy at keeping it updated and eventually it was hacked.
  • Hugo is used to help build the static site.
  • The git repo is public and hosted on GitHub.
  • I’ve setup CircleCI to detect changes on the repo’s master branch and deploy any changes.
  • The deploy is pretty basic but there are a few HTML/link checks.
  • Once generated, the static files are copied to my Linode using rsync.
  • The historic Linode was hand crafted and used Apache as it’s web server.

Learning Terraform Resources

My Terraform Script

provider "linode" {
  # API Token
  token = "abc123"
}

resource "linode_sshkey" "mikezornek_linode_ssh_key" {
  label = "mikezornek_linode_ssh_key"
  ssh_key = chomp(file("~/.ssh/id_rsa_linode_mikezornek.pub"))
}

resource "linode_stackscript" "setup_mikezornek_prod" {
  label = "setup_mikezornek_prod"
  description = "setups nginx and certbot for mikezornek"
  script = file("files/setup.sh")
  images = ["linode/ubuntu20.04"]
  is_public = false
}

resource "linode_instance" "mikezornek_prod" {
  image = "linode/ubuntu20.04"
  label = "mikezornek_prod"
  group = "mikezornek"
  region = "us-east"
  type = "g6-nanode-1"
  authorized_keys = [linode_sshkey.mikezornek_linode_ssh_key.ssh_key]
  # Leave the root password unset if want to keep it random
  root_pass = "abc123"
  backups_enabled = true
  stackscript_id = linode_stackscript.setup_mikezornek_prod.id
}

output "server_ip" {
  value = linode_instance.mikezornek_prod.ip_address
}

The output is useful if you want to ssh into your new linode instance right away with:

$ ssh root@(terraform output server_ip)

My setup bash script

#!/bin/bash

# strict mode
set -xeo pipefail

exec > >(tee -i /var/log/stackscript.log)

FQDN=mikezornek.com

echo Setting hostname to ${FQDN}
hostnamectl set-hostname ${FQDN}

echo Running apt-get update and upgrade
apt update && apt upgrade -y

echo Installing nginx
apt install -y nginx

echo Prep snap
snap install core; snap refresh core

echo Install certbot
snap install --classic certbot

# echo Setup certbot for nginx for the domain ${FQDN}
# we will do this manually after setup since the 
# domain should be pointing at this machine at the time of setup
# certbot --nginx --agree-tos -m zorn@zornlabs.com --verbose -d mikezornek.com

echo Starting nginx
sudo service nginx start

echo ALL DONE!

Observe the log file on your new server with:

$ tail -f /var/log/stackscript.log