DEV Community

Cover image for Overcoming Four Hours of Terraform Troubleshooting: Automating Nginx Deployment on AWS
BAKRE JAMIU
BAKRE JAMIU

Posted on

Overcoming Four Hours of Terraform Troubleshooting: Automating Nginx Deployment on AWS

Introduction

As a Cloud Engineer, automation is key to managing infrastructure efficiently. Recently, I spent four intense hours troubleshooting an issue with automating an Nginx deployment on AWS using Terraform. What seemed like a simple task turned into a deep dive into cloud-init, Terraform behavior, and AWS infrastructure debugging. This post walks you through my problem, the troubleshooting process, and the eventual solution.

The Goal: Deploying Nginx with Terraform

The objective was straightforward:

  • Use Terraform to launch an EC2 instance
  • Configure user_data to install and start Nginx automatically
  • Display a simple webpage: Welcome to my Terraform

Here’s the Terraform user_data script I initially wrote:

#!/bin/bash
sudo apt update -y
sudo apt install -y nginx
echo "Welcome to my Terraform" | sudo tee /var/www/html/index.html
sudo systemctl start nginx
sudo systemctl enable nginx
echo "Installation and Deployment Complete"
Enter fullscreen mode Exit fullscreen mode

It looked perfect! But when I deployed it, Nginx was not running, and the index page wasn’t updated. Time to troubleshoot.

The Problem: Terraform Applied, But No Nginx

After launching the EC2 instance, I tried accessing the public IP, but the Nginx welcome page did not load. I logged into the instance and checked:

systemctl status nginx
Enter fullscreen mode Exit fullscreen mode

It showed that Nginx was not installed! Clearly, the user-data script did not execute as expected.

The Troubleshooting Process

  1. Checking cloud-init Logs I ran:
   sudo cat /var/log/cloud-init-output.log
Enter fullscreen mode Exit fullscreen mode

It showed no errors, but also no indication that Nginx was installed. Strange!

  1. Checking if user-data was Loaded I checked:
   sudo cat /var/lib/cloud/instance/user-data.txt
Enter fullscreen mode Exit fullscreen mode

The script was there, meaning Terraform passed it correctly. So why didn't it execute?

  1. Checking Cloud-Init Processing Running:
   sudo cat /var/log/cloud-init.log | grep -i user-data
Enter fullscreen mode Exit fullscreen mode

Showed multiple Skipping user-data validation. No user-data found. messages. This indicated that cloud-init thought there was no new user-data, so it didn’t rerun the script!

  1. Realizing Terraform Doesn’t Automatically Reapply User-Data Terraform does not rerun user_data unless the instance is replaced. Since I was applying changes to the same instance, cloud-init did not reprocess the script.

The Solution: Force Terraform to Reapply User-Data

To make Terraform recognize the user_data change, I did the following:

  1. Explicitly forced instance replacement using:
   terraform taint aws_instance.web
   terraform apply
Enter fullscreen mode Exit fullscreen mode

This forced Terraform to destroy and recreate the instance, triggering the user-data script again.

  1. Used a Proper User-Data Block in Terraform:
   user_data = <<-EOF
   #!/bin/bash
   sudo apt update -y
   sudo apt install -y nginx
   echo "Welcome to my Terraform" | sudo tee /var/www/html/index.html
   sudo systemctl start nginx
   sudo systemctl enable nginx
   echo "Installation and Deployment Complete"
   EOF
Enter fullscreen mode Exit fullscreen mode

Using <<-EOF ensures correct multi-line interpretation.

  1. Verified Everything
    • Checked systemctl status nginx → ✅ Nginx was running
  • Opened http://<public-ip> in a browser → ✅ "Welcome to my Terraform" was displayed!

This my output below:

Image description

Lessons Learned

After four hours of debugging, I walked away with these key lessons:

Terraform Does Not Reapply user_data on Existing Instances – It only runs once on first boot unless the instance is replaced.

Cloud-Init Logs are Critical for Debugging – Always check /var/log/cloud-init-output.log and /var/log/cloud-init.log.

Using <<-EOF for Multi-Line User-Data Blocks is Best Practice – Prevents formatting issues.

Forcing Instance Recreation is Sometimes Necessary – Use terraform taint or terraform destroy if user-data changes.

Conclusion

This experience reinforced my problem-solving skills in AWS and Terraform. Automation is powerful, but understanding how cloud-init and Terraform interact is crucial. Now, my Terraform script reliably provisions EC2 instances with fully automated Nginx deployment.

🔹 Have you faced similar Terraform issues? Let’s discuss in the comments! 🚀

Postmark Image

20% off for developers shipping features, not fixing email

Build your product without worrying about email infrastructure. Our reliable delivery, detailed analytics, and developer-friendly API let you focus on shipping features that matter.

Start free

Top comments (0)

ACI image

ACI.dev: Fully Open-source AI Agent Tool-Use Infra (Composio Alternative)

100% open-source tool-use platform (backend, dev portal, integration library, SDK/MCP) that connects your AI agents to 600+ tools with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server.

Check out our GitHub!

AWS Security LIVE!

Join AWS Security LIVE! streaming from AWS Partner Summit Hamburg

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️