This repo is a small Terraform on AWS playground:
a hands-on set of five labs to practice real Terraform workflows on AWS.
You’ll go from a simple VPC with one EC2 instance, to Nginx and Docker on EC2,
then to a two-tier setup with frontend, API and Postgres, connected through VPC, subnets, NAT and security groups.
Everything is managed as code, with remote state in S3 + DynamoDB and GitHub Actions CI/CD keeping the labs in sync.
bootstrap/- creates S3 bucket + DynamoDB table for Terraform statelabs/lab01…lab05/- individual Terraform labs, growing in complexity.github/workflows/- CI/CD for Terraform and for the workflows themselves.gitignore- standard Terraform ignores
- Labs: labs/ - all labs tab
- Terraform CI/CD: .github/workflows - used CI/CD pipelines
- Pull Requests: PR tab - open and closed change requests and Terraform plan results in comments
- CI/CD runs: Actions tab -
CI_for_TerraformandCD_for_Terraform_to_AWSruns - Docker Hub: trashpanda31 - used images
- Focus: minimal setup.
- Network (Terraform): VPC
10.10.1.0/24, public subnet with public IPs, IGW + route table0.0.0.0/0. - EC2:
aws_instance.vm(Amazon Linux 2023), SGssh(22/tcp), optional SSH key. - State: S3 bucket
devops-state-504508177008, DynamoDB tableDevOps-lock.
- Focus: web server and SSH keys.
- Network: VPC
10.20.0.0/16, public subnet10.20.0.0/24, IGW, route0.0.0.0/0 > IGW. - EC2 and access:
aws_instance.web(Amazon Linux 2023) +aws_eip.web, SGweb(HTTP 80, HTTPS 443, SSH 22 withssh_cidr). - Keys and Nginx:
tls_private_key>aws_key_pair>local_filewith the private key,user_data.shinstalls and enables Nginx. - State: S3 key
labs/lab2-vpc-ec2/terraform.tfstate+DevOps-lock.
- Focus: running a Docker app on EC2 via
user_data. - Network and EC2: VPC
10.40.0.0/16, public subnet10.40.0.0/24, IGW, route0.0.0.0/0, EC2aws_instance.webwith EIP and SGweb(HTTP 80). - Docker:
user_data.sh.tmplinstalls Docker, pullsvar.docker_image(defaulttrashpanda31/lab03:latest), mapshost_port>container_portand performs an HTTP check. - State: S3 key
labs/lab3-min-ec2-docker/terraform.tfstate+DevOps-lock.
- Focus: two-tier app with backend hidden behind NAT.
- Network: VPC
10.42.0.0/16, public subnet10.42.1.0/24(public IP), private subnet10.42.2.0/24, IGW, NAT Gateway, separate public/private route tables. - EC2 and security: backend
aws_instance.backendin private subnet (no public IP), frontendaws_instance.frontendin public subnet with EIP; SGfrontend(HTTP/SSH from the internet), SGbackend(inbound only from frontend). - Docker images: backend via
usedata-backend.sh(var.back_image, defaulttrashpanda31/lab04-src-server:latest), frontend viausedata-frontend.sh(var.front_image, defaulttrashpanda31/lab04-src-client:latest,API_ORIGINpointing to backend private IP). - State/outputs: S3 key
lab04/terraform.tfstate+DevOps-lock; outputs withfrontend_public_ip,backend_private_ip,frontend_url.
- Focus: modular "mini-prod" stack.
- Modules:
vpc- VPC, public/private subnets, IGW, NAT, routes.security- SG frontend (HTTPfrontend_port) and backend (only traffic from frontend).iam_ssm- EC2 role + instance profile withAmazonSSMManagedInstanceCore.ec2- EC2 instances with EIP anduser_data_replace_on_change.
- Instances: backend in private subnet with no public IP; frontend in public subnet with EIP; both with SSM roles.
- Docker stack: on backend,
user_data_backendcreates networklab05, runspostgres:15-alpineandlab05-backend; on frontend,user_data_frontendrunslab05-frontendbehind Nginx, proxying/apito the private backend. - State/outputs: shared S3/DynamoDB backend; outputs with VPC/subnet IDs, instance IDs, IPs and final frontend URL.
You need an AWS account and an IAM user with programmatic access and permissions for S3, DynamoDB, EC2, VPC, IAM, etc.
Configure the AWS CLI profile that Terraform will use:
aws configure --profile DevOps
# AWS Access Key ID: <your key>
# AWS Secret Access Key: <your secret>
# Default region name: eu-north-1
# Default output format: jsoncd bootstrap
terraform init
terraform apply -var="aws_profile=DevOps" -var="prefix=DevOps"cd labs/lab03 # or lab01..lab05
terraform init
terraform plan
terraform applyterraform destroy- Gradual Terraform deep dive: I go through five labs - from a single EC2 in a small VPC to a modular "mini-prod" with frontend, API, and Postgres.
- Real AWS networking: I configure VPCs, public and private subnets, IGW and NAT, route tables, security groups, and Elastic IPs - the core building blocks of production-grade AWS infrastructure.
- Application delivery with Docker: using EC2
user_dataI install Docker, pull images from Docker Hub, wire up ports, and connect frontend, backend, and database into a working application. - Safe remote state & automation: in every lab I use S3 + DynamoDB for Terraform state storage and locking, and GitHub Actions makes plans and applies predictable and repeatable.
- Ops skills, not just theory: SSH, SSM, health checks, Terraform outputs, and per-lab state keys give me hands-on practice in operating and debugging infrastructure changes.
- Reusable patterns: in Lab 05 I've structured modules (VPC, security, IAM/SSM, EC2) as building blocks that I can reuse in future projects and evolve into more advanced IaC setups.



