Create a Bastion Host on AWS

Disclaimer: This is a personal blog, any views or opinions expressed in this blog are personal and belong solely to the blog author and do not represent those of people, institutions, or organizations that the author may or may not be associated with in a professional or personal capacity, unless explicitly stated. Any views or opinions are not intended to malign any religion, ethnic group, club, organization, company, or individual.

This post is part of our series on how to Create a Multi-Tier Auto-Scaling WordPress Site on Amazon Web Services. If you haven’t checked out our previous posts, be sure to click the link above.

As a reminder, we’ll follow the AWS Reference architecture as close as possible; however, we will try to use Free Tier resources whenever available. For this tutorial, we are going to create a Bastion Host to manage our WordPress architecture.

Scalability does come with some drawbacks with regard to keeping themes/plugins up to date; however, it all depends on your goal and what you need for your site. The way you’ve traditionally managed WordPress will be different with this architecture and that needs to be taken into account long-term.

Please note that we are going to put the whole WordPress installation on EFS which does have some latency and performance concerns. We will try to overcome this with caching and CDN; however, if that’s not performant enough for your use case, you may want to only put the “uploads” directory on EFS and then have a process to update the base AMI going forward.

Prerequisite: AWS Reference Architecture and Previous Posts

As mentioned above, please ensure that you check out the AWS Reference architecture as well as our previous posts.

What is a Bastion Host?

A bastion host is a server that provides access to a private network from a public network. It is designed to be a hardened front door and limit access to resources behind it. For our use case, it will be used for SSH access to our web/app servers, and also to check connections to our database on RDS and cache on ElastiCache.

Create your Bastion Host EC2 Instance

Our first step is going to be to create a new EC2 Instance to act as your Bastion Host and have it reside on one of our public subnets.

Login to your AWS Management Console and then go to the “EC2” service.

Then click on “Instances” to get to the Instances Dashboard.

Click on “Launch instance” in the top right.

Select a Free Tier AMI

Once there, select a Free Tier eligible AMI. I’m familiar with Ubuntu, so I’ll select that image.

Select an Instance Type

I’m going to start with a t2.nano instance and if I come across any issues, I can always change the instance type later on.

Click on “Next: Configure instance details”.

Configure your instance to use your VPC and Public Subnet

Make sure to select the VPC you created, as well as one of your public subnets where you want the host to reside.

Click on “Next: Add Storage”.

Configure Storage

I’ll leave the size as 8GB since we won’t be doing much with this host.

Add Tags to your Instance

Then you can add “Tags” in the next step if you’d like, and then continue to “Next: Configure Security Group”

Select our Bastion Hosts Security Group

Select the the Security Group we created earlier in our series for Bastion Hosts. Note that we allow SSH access from ANY address; however, we can lock this down just to our own IP address for additional security (this is what we recommend in a Production scenario).

Launch your Instance and select SSH Keys

Now click on “Review and Launch”! You may see warnings on Free Tier eligibility as well as your Security Group being open to the world. Keep in mind that we recommend locking things down to your IP address, but we will move forward for the purpose of this tutorial.

If you have an SSH Key Pair already created and have access to the key, go ahead and use that or create a new one. Ensure you download the key at this point in time as you won’t see it again!

Go ahead and “Launch Instances”.

Name your Instance for easy identification

I like to name my instances for easy identification. I’ll call this instance “3T – Bastion Host”.

Test SSH Access to your Bastion Host

If you click on the Instance ID, you’ll get additional details about your instance. Additionally, you can find the Public IP address in the Instance dashboard as well as the details. Note this IP address down and test SSH access with your SSH Client of choice.

I am a fan of “Termius” so that’s what I’ll use to test out the connection.

Optional: Add a Banner when users Login

Personally, I like to know when I’m logging into a Bastion Host. Thus, I create the following file “/etc/motd” and add in the text that I want to display. Here is an example of what I see what I login.

Update Your Server

Ensure your server is updated with the following two commands. Agree to prompts as needed or add the “-y” flag.

$ sudo apt-get update
$ sudo apt-get dist-upgrade

Go ahead and reboot the server for good measure as well!

Note: If you reboot from the AWS Management Console instead of the command line, your IP address may change. Feel free to configure an Elastic IP if you’d like a consistent IP.

Test Connection to RDS

We want to test the connection to our RDS MySQL Database from our Bastion Host, so we’ll install the mysql-client with the following command.

sudo apt-get install mysql-client

Next, we’ll run the following command, after you hit Enter, you’ll be prompted for your password.


If you get the mysql prompt, everything worked as expected! You can run the following command to ensure that you see the database that you created in our last post to use for our WordPress install.


Type in the following, and then hit Enter to exit out of the mysql client prompts.


You can also double-check our connection by going to the RDS Dashboard and looking at the database metrics. Below you’ll see our DB Connection Count go up to 1 when we were connected and drop back down to 0 when we exited.

Optional: Test Connection to ElastiCache

You should have your ElastiCache details from an earlier post. We’ll simply run a telnet command to ensure that our host can communicate with the Redis Cache on ElastiCache.

$ telnet <ElastiCache EndPoint> <PORT>

If you see the following, you’re all set! we’ll do the same thing with your instance in our private subnet later on.

Test Connection to Instance in Private Subnet

Let’s make sure our VPC/subnet and Security Group configurations are good to go. Quickly create an EC2 instance in your private subnets with Web/App Server Security Group.

I’m just going to show the final step with the details since you now know how to create an EC2 instance. Use the same key that you created/used earlier.

You’ll see that this new instance doesn’t have a Public IP since it is in our Private Subnet.

Configure ssh-agent

I’m using a Mac so ssh-agent is luckily already installed as part of MacOS. We just need to add our key to our keychain by running the following command. Ensure your *.pem file has the proper permissions (600).

ssh-add -K myPrivateKey.pem

SSH to Bastion Host

Next, we’ll SSH to our Bastion Host with the following command. The -A flag means that we are using the ssh agent and forwarding.

ssh –A user@<bastion-IP-address or DNS-entry>

SSH to Instance in Private Subnet from Bastion Host

Now get the Private IP of your server in your Private Subnet and run the following command from your Bastion Host.

ssh user@<Instance in Private Subnet>

If you see a successful connection, everything worked as expected!

Install MySQL Client and Test Connection to RDS

Similar to what we did on the Bastion Host itself, let’s install the mysql-client and then test the connection to the RDS MySQL Database. Use the same commands from earlier in this post.

We successfully connected to RDS; therefore, when we set up our WordPress instance, we know we’ll be able to connect to the database.

Optional: Test Connection to ElastiCache

You should have your ElastiCache endpoint noted from earlier. We’ll simply run a telnet command to ensure that our host can communicate with the Redis Cache on ElastiCache.

If you see the following, you’re all set!

Optional: Test Outbound Internet Connection on Instance in Private Subnet

Currently, we don’t have a NAT Gateway configured on our server in the Private Subnet. Thus, if you try to connect to anything outbound on the Internet, it will fail (which is expected). You can run a simple ping command to test it out.

$ ping

Since I have a NAT Gateway instance created, as well as the correct Security Groups, all I need to do is add the correct Security Group to my instance in the Private Subnet, and I can run the ping again and get responses.

Note: You will need an outbound internet connection for OS updates/upgrades, as well as basic WordPress functionality. Either use the NAT Gateway service, or use this link to create your own NAT Gateway EC2 Instance.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.