Infrastructure-as-Code for the Duly note-taking app. Manages all AWS resources including EC2, networking, container registry, and DNS.
This repository contains Terraform configurations for deploying Duly on a single EC2 instance running Kubernetes. Resources are tagged with project, environment, owner, and managed-by tags for organization and cost tracking.
- Terraform >= 1.6
- AWS CLI configured with appropriate credentials
- AWS account with permissions for EC2, VPC, IAM, ECR, and Route 53
This project uses a remote S3 backend with DynamoDB-based locking for state management:
- State bucket: S3 (encrypted, versioned, public access blocked)
- Locks: DynamoDB (prevents concurrent applies, prevents destroy)
- Benefits: Reproducible infrastructure, team-safe state, audit trail
The S3 bucket and DynamoDB table are managed by Terraform but create a bootstrap dependency (chicken-and-egg problem). Follow this workflow:
- Comment out the
backend "s3"block inmain.tf - Run
terraform init(uses local state temporarily) - Run
terraform apply(creates S3 bucket and DynamoDB table) - Uncomment the
backend "s3"block inmain.tf - Run
terraform init -backend-config=backend.hcl -migrate-state(migrates state to S3)
Create terraform.tfvars (not committed to git):
my_ip = "YOUR_IP/32" # Your home/office IP for SSH accessCreate/update backend.hcl (not committed to git):
bucket = "terraform-state-duly-YOUR_ACCOUNT_ID"
key = "terraform.tfstate"
region = "eu-north-1"
dynamodb_table = "terraform-state-lock"
encrypt = true# Initialize with backend config
terraform init -backend-config=backend.hcl
# Preview changes
terraform plan
# Apply changes
terraform apply
# Destroy EC2 to save money (keep state infrastructure)
terraform destroy -target=aws_instance.main
# Later: recreate EC2 from state
terraform applymain.tf— Terraform and provider configuration, backend blockstate.tf— S3 bucket and DynamoDB table (remote backend)vpc.tf— VPC, subnets, and networkingsecurity_group.tf— Security groups with rulesec2.tf— EC2 instance configurationvariables.tf— Input variables and shared localsoutputs.tf— Exported values for other systemsbackend.hcl— Backend configuration (not in git, see.gitignore)
Strategy: Destroy the EC2 instance when not actively developing:
terraform destroy -target=aws_instance.mainRecreate it anytime with:
terraform applyThe S3 state persists, so the recreated instance will have the same configuration.
Note: Destroying the EC2 instance also destroys the associated EIP. This means a new EIP will be associated with the EC2 instance when you create it again.
However, note that the next time you spin it up your instance will be assigned a new public IP.
All resources are tagged with:
Project— project name (duly)Environment— deployment environment (production)Owner— resource ownerManagedBy— "terraform" (indicates IaC management)CostCenter— "portfolio"
GitHub Actions automatically validates Terraform on pull requests:
terraform fmt -check— formattingterraform validate— syntaxtflint— best practices and style