How to Connect to an EC2 Instance in a Private Network Using a Bastion Host
Using the AWS Management console

Search for a command to run...
Using the AWS Management console

No comments yet. Be the first to comment.
Terraform is a powerful tool for defining infrastructure as code (IaC). When managing multiple environments like dev, staging, and prod, organizing your Terraform code effectively is key. In this article, I’ll share how I manage multiple environments...
Deploying a FastAPI Application with CI/CD Pipeline

Number Classification API

Task - NGINX configuration

On this page
In cloud environments like AWS, it's a best practice to place your application servers in private subnets to prevent direct access from the internet. But then, how do you connect to those private instances for troubleshooting or configuration?
This is where a Bastion Host comes in, a secure jump server that provides SSH access to private instances.
Configure your VPC, security groups and route tables
Set up a bastion host
SSH into a private EC2 instance via the bastion host
Before we start, ensure the following:
You have an AWS account
You’re familiar with basic VPC, EC2, and SSH concepts (optional, but helpful)
You’ll create a simple VPC setup like this:

Create a VPC
Enter a CIDR block (e.g., 10.0.0.0/16 the range of IP addresses your VPC will have)
Give your VPC a name (always ensure you tag your resources)
Create 2 Subnets:
Public Subnet (e.g., 10.0.1.0/24)
Private Subnet (e.g., 10.0.2.0/24)
Create an Internet Gateway (IGW):
This will give internet access to the public subnets within the VPC and then in the action’s menu.
Once the Internet Gateway is created, click on the “Actions” button on the top-right, and attach to VPC. Ensure you select your created VPC, your tags should make this easier to find.
Update route table
Create a route to destination (0.0.0.0./0) and the target should be the Internet Gateway you Attached to the VPC.
Create the Private Route table
What makes a route table private is the absence of a route to outside traffic through an Internet Gateway. This is what’d needed for the private subnet.
Create a route table association for the Private Subnet.
NOTE: By default, both subnets are implicitly associated to the VPC’s main route table, and this would give them internet access, but only one requires it, so another route table will be made for the private subnet.
By the time you’re done with the above steps, you have the following in your VPC resource map.

Launch an EC2 instance (Amazon Linux/Ubuntu) in the public subnet.
Assign it a public IP
Associate it with a security group that:
Use a key pair for SSH access, it will automatically download. Ensure you take note of its location.
Launch an EC2 instance in the private subnet
Do not assign a public IP
Configure your security group to:
Select a key-pair, just as in the previous instance.
Now let’s connect:
SSH into the Bastion Host.
Go the Instances dashboard and select the instance your created
Go to the Connect option on the top-right and click on SSH client. Now copy the command and paste it in your terminal as such.
ssh -i "test.pem" ec2-user@54.165.42.99
NOTE: test.pem was what I saved my key-pair as.
If you’re on a Linux distro such as ubuntu you have to manage the permissions of your key-pair using the following command.
chmod 400 "test.pem"
Once you’ve SHH’d into the into the instance, you should get something like below

Security concerns: The key-pair and instances used were strictly created for this project and have since been deleted.
SSH into the Private EC2 Instance.
NOTE: The key-pair for your private instance was download unto your local PC, so your instance does not have it. In order to SSH into your private subnet, we’d need to copy the content of the key pair to your Bastion Host.
Open your key-pair file for your private instance saved to your local PC and copy all of its contents using CTRL + a and CTRL + c
Now go to your Bastion Host, presumably still SHH’d into and perform the following:
vim test.pem

Press i on your keyboard to edit, and then paste your key-pair copied in previous steps.
Now to save the file press ESC on your keyboard and type :wq! to save and exit the vim editor.
To confirm if your keypair saved, use the following to view its contents
cat test.pem
Now modify the permissions for the key pair
chmod 400 "test.pem"
Now, just like your bastion host, go to the EC2 dashboard, and click on “connect” on the top-right corner, click ln the “SSH Client” and then copy the command. Paste it into your Bastion Hosts terminal.
ssh -i "test.pem" ec2-user@10.0.0.11

This should display the above, indicating you’ve SSH’d into your private subnet
You have successfully and securely accessed your private instance using a bastion host, now you can configure your instance how you want
NOTE: This method does not give your private instance internet access to download resources.
NOTE: Using Session Manager (SSM) is better for enhanced, will be discussed in a future post
Timeout When SSHing to Private EC2
Cause: Private security group doesn't allow SSH from Bastion hosts security group
Fix: Allow port 22 from Bastion's Security group in Private EC2's security group
Permission Denied (publickey)
Cause: Wrong key or wrong permissions
Fix: Use correct .pem file and/or run chmod 400 my-key.pem
Can’t Reach Bastion Host
Cause: No public IP, IGW, or incorrect route table
Fix: Ensure the bastion host has a public IP, IGW attached to the VPC, and route to 0.0.0.0/0 on the route table.
Use key rotation and minimal SSH access
Set up CloudWatch for monitoring the bastion
Consider using Session Manager (SSM) for enhanced security (no SSH needed)
Restrict bastion access with security groups and NACLs
Using a bastion host is a secure and controlled way to access EC2 instances in a private network. This setup is essential for production-grade cloud environments.
Stay tuned for a future post where we’ll automate this entire setup using Terraform or CloudFormation!