Provisioning infrastructure and deploying applications manually is a recipe for inconsistency. Today, I took on the challenge of automating a server setup using Terraform to host a Spring Boot Java application. It wasn't a straight path. I ran into regional payment blocks, architecture mismatches and SSH "ghosts" but here is exactly how I solved them.
The Pivot From DigitalOcean to AWS:
I was following a course where the instructor used DigitalOcean to deploy the Java app. I tried to follow along, but I hit a brick wall, DigitalOcean kept rejecting my cards because I am in Nigeria.
I felt bad for a few days, but then I remembered my #30ofAWSTerraform challenge. AWS is known for its complexity, but it’s also the industry leader. I decided to stop feeling bad and start building. If the course used a DigitalOcean "Firewall," I knew I could translate that into an AWS Security Group. I decided to test my knowledge and gain real experience.
1. Provisioning Infrastructure with Terraform:
My goal was to use Infrastructure as Code (IaC) to create an EC2 instance. I used the aws_instance and aws_key_pair resources to define my server.
The Challenge: SSH Key Management
Initially, passing the public key as a raw string variable led to formatting errors.
The Solution:
I used the Terraform file() function to read my public key directly from my local disk. This ensured that the exact bytes on my Windows machine matched what AWS received.
resource "aws_key_pair" "my_ssh_key" {
key_name = "zacks-key"
public_key = file("C:/Users/Public/id_aws.pub")
}
2. The Battle of AMI IDs and Usernames:
Even after the server was "running," I couldn't get in. I kept seeing InvalidAMIID.NotFound or Permission denied (publickey).
The Lessons Learned:
-
Region Specificity: AMI IDs are not universal. An Ubuntu ID in London won't work in North Virginia (
us-east-1). -
Architecture Matters: I discovered that a
t2.microinstance requires an x86 image. Trying to use an ARM-based AMI will result in a "Not Found" error. -
The Default User: Every OS has a different "front door." For Amazon Linux, it’s
ec2-user. For Ubuntu, it’subuntu.
3. Deploying the Application (The JAR File):
Once the server was accessible, I needed to move my Java artifact from my local build/libs folder to the cloud.
The Tool: SCP (Secure Copy)
I used the following command to securely upload the JAR:
scp -i C:\Users\Public\id_aws "C:\Users\...\java-app-1.0-SNAPSHOT.jar" ubuntu@<IP>:/home/ubuntu/
Translating Firewall to Security Group:
When my instructor added a firewall on DigitalOcean, I knew exactly what to do in AWS. I updated my Security Group in Terraform to open Port 8080, allowing traffic to reach my Spring Boot application.
4. Linux User Management & Security
For security best practices, I created a personal user: zacks.
The Steps taken:
-
Creation:
sudo adduser zacks. -
Permissions: I gave the user administrative power using
sudo usermod -aG sudo zacks. -
The Final SSH Boss: I mistakenly named my key file
Authentication_keys. Linux ignores this, It must be namedauthorized_keys. Furthermore, I had to usechownto ensure the userzacksactually owned the file andchmod 600to make it private.
sudo mv /home/zacks/.ssh/Authentication_keys /home/zacks/.ssh/authorized_keys
sudo chown -R zacks:zacks /home/zacks/.ssh
sudo chmod 600 /home/zacks/.ssh/authorized_keys
Conclusion
Today was a masterclass in troubleshooting. I learned that DevOps isn't just about writing code; it's about being adaptable. When one cloud door closed, I used Terraform to open a better one on AWS.
Infrastructure is live, the JAR is running, and the "Whitelabel Error Page" never looked so beautiful!





Top comments (0)