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?
To follow along, it may be useful to view the Github repository that includes all the project files for this chapter:
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
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 = 188.8.131.52
That's our server's IP address! Let's get SSH working on this machine.
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.
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
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 184.108.40.206 -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!
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
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 = 220.127.116.11
You can use that to SSH into the server and check if Rails is installed properly:
$ ssh 18.104.22.168 -l ubuntu -i ~/.ssh/my_test_key ubuntu@ip-172-31-29-13:~$ rails -v
and get an output like:
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.