Terraform: upgraded CentOS/LAMP/WordPress guide

New things are happening in my life, which is pushing me to try new technology/software/everything (which is a very positive thing). I will get into more detail about what is changing later. In this blog article I will explain how you can do the same installation as described in my WordPress on a CentOS LAMP stack guide blog article, but now in an upgraded way, using Terraform.

Terraform is an infrastructure as code tool. So you basically write your infrastructure in configuration files (as code). You can provision servers in environments like AWS, DigitalOcean and Kubernetes. And you can perform other tasks such as add the server to Chef or execute commands. It's easy to create multiple servers (you can simply add a 'count' option), so you can create clusters such as a load balancer with 3 web servers in just a few configuration files.

In this article I will give you an example of how you can start 1 server using the DigitalOcean Terraform provider, with the remote-exec provisioner. So nothing really fancy, but it will give you an idea of the possibilities and opens doors for bigger projects 😉

What you'll need

This is not going to be a complete SSH key and Linux guide. Here is a list of things you'll need:

  • DigitalOcean account (use my referral link to get free credit).
  • Linux workstation, or access to a Linux shell (or macOS or FreeBSD). Actually, there are also Terraform binaries for Windows.
  • SSH key (~/.ssh/id_rsa and ~/.ssh/id_rsa.pub) which is also added to your DigitalOcean account (make sure this is the same key, always check key fingerprints!).
  • DigitalOcean API key (you can create one in your account).

Preparations: Terraform installation

Downloading and installing Terraform is easy. They provide binaries and you can simply unzip them:

  1. Log in to your workstation or Linux system
  2. Create a Terraform directory: mkdir terraform ; cd terraform
  3. Download the Terraform binary for your system from https://www.terraform.io/downloads.html
  4. Unzip the package: unzip terraform*.zip

Preparations: Project directory and DigitalOcean credentials

This is just a basic example. You can of course also create a GIT repository for your project. Just make sure it's not a public repository and make sure your DigitalOcean credentials are not included, because otherwise anyone can create DigitalOcean servers in your account.

  1. Make your project directory: mkdir wordpress1 ; cd wordpress1
  2. Get your SSH key fingerprint: ssh-keygen -E md5 -lf ~/.ssh/id_rsa
  3. For your configuration file, remove the 'MD5:' prefix, so it's just the plain hash
  4. Create a 'terraform.tfvars' file and 'provider.tf' file (see examples below)

Example file: terraform.tfvars

Replace the do_token string with your DigitalOcean API token and the ssh_fingerprint string with your SSH key fingerprint (remember to remove the 'MD5:' prefix):

do_token="xxxxxxxxxxxxxx"
ssh_fingerprint="xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"
pub_key="~/.ssh/id_rsa.pub"
pvt_key="~/.ssh/id_rsa"

Example file: provider.tf

For the project in this blog article you can simple use the file below without any changes:

variable "do_token" {}
variable "pub_key" {}
variable "pvt_key" {}
variable "ssh_fingerprint" {}
provider "digitalocean" { token = "${var.do_token}" }

Create your project

Below you'll find a big file that defines the server we will be creating. The installation is largely based on my other blog article, but (almost) everything is installed automatically. It also generates passwords for the MySQL root user and WordPress database user.

I'm not going to explain everything in the config file, because if you have some Linux knowledge it's pretty much self-explanatory. But here are a few things I'd like to point out:

  • Image, region and size arguments in the resource definition are from the DigitalOcean API. It's safe to change them, but use the right names!
  • Your public SSH key will be added to your VM by DigitalOcean and Terraform will use your key for the remote-exec provisioner to execute all the commands.
  • The whole process can take pretty long (even 5 minutes or more), depending on how many updates need to be installed. Terraform will update you every 10 seconds with some output, but it's possible that there is no other output for a few minutes. So have some patience.
  • After installation you'll be presented with the MySQL passwords. This is a bit ugly, but for this example it's fine. It's not really the best way if you're going to install clusters of course.
  • The last step is a reboot of the server, to get all updates active (for example kernel updates).
  • Let's Encrypt is not included.
  • SELinux will be changed to the permissive state instead of enforcing, because otherwise it's not possible to write files in /var/www/html. It's better to change the SELinux config and keep it in an enforcing state of course.

Example file: wordpress1.tf

This is the whole project file. Feel free to make changes, just don't break it 😉 It might look like a lot, but just take some time to read it and you'll see it's actually really simple.

resource "digitalocean_droplet" "wordpress1" {
  image = "centos-7-x64"
  name = "wordpress1"
  region = "ams3"
  size = "s-1vcpu-1gb"
  private_networking = false
  ssh_keys = [
    "${var.ssh_fingerprint}"
  ]
  connection {
    user = "root"
    type = "ssh"
    private_key = "${file(var.pvt_key)}"
    timeout = "2m"
  }
  provisioner "remote-exec" {
    inline = [
      "yum -q -y update",
      "yum -q -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm",
      "yum -q -y install wget pwgen firewalld mariadb-server",
      "systemctl enable firewalld ; systemctl start firewalld",
      "systemctl enable mariadb ; systemctl start mariadb",
      "pwgen -s 24 1 >> /root/mariadb.password ; chmod 600 /root/mariadb.password",
      "pwgen -s 24 1 >> /root/wordpress.password ; chmod 600 /root/wordpress.password",
      "mysql -e 'create database wordpress1;'",
      "mysql -e \"grant all on wordpress1.* to wordpress1@localhost identified by \\\"`cat /root/wordpress.password`\\\";\"",
      "mysqladmin password `cat /root/mariadb.password`",
      "yum -q -y install httpd",
      "systemctl enable httpd",
      "rm -f /etc/httpd/conf.d/welcome.conf ; touch /etc/httpd/conf.d/welcome.conf",
      "firewall-cmd --permanent --zone=public --add-port=80/tcp",
      "firewall-cmd --reload",
      "yum -q -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm",
      "yum -q -y --enablerepo=remi-php73 install php php-mysql php-opcache php-gd php-xml",
      "wget -q https://wordpress.org/latest.tar.gz",
      "tar xzf latest.tar.gz --strip-components=1 -C /var/www/html",
      "rm -f latest.tar.gz",
      "chown -R apache:apache /var/www/html",
      "systemctl start httpd",
      "sed -i 's/SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config",
      "echo -----",
      "echo The following passwords are created. Please store them in a safe place",
      "echo MySQL root password: `cat /root/mariadb.password`",
      "echo MySQL wordpress1 password: `cat /root/wordpress.password`",
      "echo -----",
      "rm -f /root/mariadb.password /root/wordpress.password"
    ]
  }
  #Rebooting to get all updates active such as a new kernel
  provisioner "remote-exec" {
    inline = [
      "reboot"
    ]
    on_failure = "continue"
  }
}

Deploy!

To deploy your project, use the following commands:

  • Initialize your project (usually only needed once, Terraform will download plugins such as the DigitalOcean provider): ../terraform init
  • Use the plan command to see what Terraform is going to do: ../terraform plan
  • Apply your configuration (this will actually deploy your project): ../terraform apply

After deployment

After deployment, wait till the server is back online (there is a reboot command at the end), visit your server using your web browser and install WordPress. Use the following credentials for your database:

  • Database Name: wordpress1
  • Username: wordpress1
  • Password: the password in the Terraform output

And destroy

Did you do something wrong? Don't want to play with your WordPress VM anymore? Or are you ready for a new project? Terraform makes it really easy to delete everything. Just use the destroy command: ../terraform destroy

Your next project

Here are a few other things to try, if you need a new project:

  • Manage your configuration with Chef as provisioner
  • Use another provider, such as Kubernetes
  • Create multiple servers, for example build a cluster of web servers

That's all folks!

Questions? Let me know in the comment section below!

Leave a Reply