Installing Rails with Terraform
Installing Rails with Terraform

In the previous post, we discussed how to set up an EC2 instance resource through Terraform.

In this post, we're going to make that EC2 instance more useful by installing Rails, attaching a static IP address to it, and opening up SSH access on the server.

It may be helpful to check out the helper files associated with this series, while following along! If you're just starting with this chapter, it may also be helpful to check out the other Terraform tutorials.


If you're interested in topics like this, why not subscribe to the blog?

Project Files

To follow along, it may be useful to view the Github repository that includes all the project files for this chapter:

Using Terraform with AWS

Getting started

Let's start by navigating to our project directory and running:

$ cp -R 1-ec2-instance/ 2-installing-rails/
$ cd 2-installing-rails/

That should get us started!

Attaching a Static IP

In order to set up a proper domain name, a static IP address is often required. To make the rest of the steps easier - Let's start off by attaching a static IP address to our EC2 instance.

Let's create a file called eip.tf to store our Elastic IP resource configuration in. Filling it with the following contents:

All we need to to is create an Elastic IP resource and attach it to the instance we created earlier! The dynamic attributes available through the Terraform resource will allow us to always be sure this Instance ID is up to date.

You can run this via terraform apply and it'll create everything you'd expect. But, as things are now, you won't be able to actually read the IP address through the command line.

Let's figure out how to get the IP address without going through the AWS web interface.

Output Terraform Variables to CLI

We now have some EC2 resources that we've created. But, in order to view information about them, we currently need to use the web interface. That is inconvenient for this series and so we'll create a fix for it!

Let's create a file named outputs.tf with the following contents:

This file contains the configuration for an output in Terraform. Outputs can serve a number of purposes. In the top-level directory, like we have here, they serve the important purpose of being output to the console after a successful apply.

If you try to run terraform apply, you will get an output like this at the end:

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

server-ip = 35.164.121.188

That's our server's IP address! Let's get SSH working on this machine.

Security Groups

In order for an EC2 Instance to receive connections from the open internet, we need to attach a security group to the instance. Security groups control internet traffic to and from the machine.

Creating the Security Groups

Let's create a file named security_group.tf with the contents:

Here we're creating an aws_security_group resource with the identifier allow_ssh. This security group allows incoming (ingress) traffic to port 22 (the SSH port) from the CIDR Subnet Mask 0.0.0.0/0 (all IPs).

We are also creating a security group for outbound (egress) connections to any host any port, through allow_outbound. We're doing that so that our server can download RVM and Rails from the proper servers.

Attaching the Security Groups

Let's modify the main.tf file to contain:

This will attach the security groups we just created, to our EC2 instance. Allowing it to receive incoming connections on port 22 and allowing all outbound connections from the server.

SSH Access

In the spirit of this chapter, we're going to set up an SSH key pair through Terraform and the CLI. There is a web-based interface you can use to do this. But where's the fun in that?

The key pair will be used to SSH into the server we've set up, without a password. Instead it'll use a PEM file that we've set up. A private key that only our machine has access to.


Note: Public key encryption is an extremely interesting and useful thing to know. If you're not familiar with it, I definitely recommend taking a look!


Generate the Public and Private Keys

Open up another terminal window, and execute the following:

$ cd ~/.ssh/
$ ssh-keygen -t rsa -b 2048 -v

For the filename, let's just enter my_test_key, so that the full location of the private key is ~/.ssh/my_test_key and the public key is located at ~/.ssh/my_test_key.pub. Let's leave the passwords blank.

Apply the Key Pair through Terraform

Back in the project directory (2-install-rails), execute the following command:

$ cat ~/.ssh/my_test_key.pub > my_test_key.pub

Alright! The last step is to tell AWS about this key pair through Terraform a small configuration.

Create a file named key_pair.tf with the contents:

That will set the Key Pair up within Amazon. Now we just have to use it!

Using a Key Pair for SSH

In order to use the key pair we've created, we have to add the key name to the configuration of the EC2 instance.

Open up the main.tf file and make the addition of a key_name attribute:

This will attach the key pair we just generated to the instance and allow it to be used for SSH autentication.

Connect via SSH

If you now run terraform apply, and pull the IP address out of the final output, you should be able to successfuly SSH into the machine using:

$ ssh 52.24.133.0 -l ubuntu -i ~/.ssh/my_test_key

We now have a fully working, fully SSH-able, Ubuntu server configuration!

Let's get Rails on it!

Install Rails

After setting up the security groups and SSH keys, it's time to install Rails. We'll do this through a configuration called a provisioner.

Adding the provisioner

Modify main.tf to look like this:

The provisioner we're using here is a remote-exec. When the server is created, this provisioner will connect to it with the details given in the connection block.

The provisioner will then execute the bash commands placed in the in the inline attribute. In this case, the server will download and install RVM along with the latest version of Rails.

Recreating the server

For whatever reason, Terraform does not seem to force an update when the provisioner on an ec2_instance is modified. That being the case, we'll force the update ourselves!

This time, let's destroy only the server. Execute the following command to exclusively destroy the server and the things that depend on it (the Elastic IP, in this case):

$ terraform destroy -target="aws_instance.my-test-instance"

Now, you can execute terraform apply one more time to bring everything back online and install Rails!

Checking the installation

If all went well, you should receive output containing the following:

Outputs:

server-ip = 52.43.141.214

You can use that to SSH into the server and check if Rails is installed properly:

$ ssh 52.43.141.214 -l ubuntu -i ~/.ssh/my_test_key

ubuntu@ip-172-31-29-13:~$ rails -v

and get an output like:

Rails 5.1.4

Congratulations! You've done a ton of stuff in AWS and Terraform and are well on your way to having a fully-deployed application.

In the next chapter, we'll talk about how to massively improve your Terraform abilities through modules. Then we'll use those new-found powers to deploy a production-ready Rails application.