← All projects
132026 / Deployed / Infrastructure-as-code portfolio project

Terraform — EC2 Deployment with Cloud-Init

Provisioned an AWS EC2 instance through Terraform with an external cloud-init YAML file passed via user_data, automatically installing and enabling NGINX on first boot so the server reaches a working public endpoint with no manual SSH steps.

TerraformAWS EC2Security GroupsCloud-InitUser DataAmazon Linux 2023NGINXDynamic AMI Data SourceInput VariablesOutput AttributesIaC

Business value

For teams that repeatedly launch web servers, this replaces manual OS setup and SSH package installation with a single repeatable Terraform run. Every instance boots into an identical, predictable state, cutting environment spin-up time from hours of manual work to minutes and removing the configuration drift that slows incident response and release velocity.

0 manual stepsServer configured on boot
MinutesFrom apply to live endpoint
RepeatableIdentical instance every run

The problem

Traditional server deployment means launching an instance, logging in over SSH, running package updates, installing the web server, starting the service and verifying it — a sequence that is slow, inconsistent and easy to get wrong. The task was to automate that entire flow: use Terraform to launch a t3.micro EC2 instance, pass a cloud-init script through user_data, and have NGINX running and reachable on a public IP as soon as the instance boots.

What I built

  1. 01

    Structured the project with clear separation of concerns — main.tf for resources, variables.tf for inputs, outputs.tf for returned metadata and cloud-init.yaml for OS-level configuration.

  2. 02

    Used an AWS data source to dynamically fetch the latest Amazon Linux 2023 AMI, avoiding brittle hardcoded AMI IDs that break as images age out.

  3. 03

    Created a cloud-init YAML file that updates system packages, installs NGINX, enables the service on boot and writes a custom deployment verification message to the web root.

  4. 04

    Passed the cloud-init script into the EC2 resource via Terraform's file() function through the user_data argument, keeping the bootstrap logic external and version-controllable.

  5. 05

    Declared explicit outputs for the instance public IP, instance ID, availability zone and instance type so the endpoint is printed automatically after every apply.

  6. 06

    Configured a dedicated security group allowing inbound HTTP (port 80) for the web server and SSH (port 22) for management, with all other traffic denied by default.

  7. 07

    Ran terraform apply to provision the infrastructure, then verified the deployment by checking the running NGINX service over SSH and loading the default welcome page over the public IP.

Project stages

01 / 05
Stage 01 — terraform apply completing the EC2 provisioning cycle, with outputs.tf exposing the instance public IP, ID, availability zone and type.

Stage 01 — terraform apply completing the EC2 provisioning cycle, with outputs.tf exposing the instance public IP, ID, availability zone and type.