Phase 1 of 6

Infrastructure Foundation

Set up AWS account, VPC networking, security groups, and container registry

2-3 days
Beginner Level
4 main steps
🎯 What You'll Accomplish
By the end of this phase, you'll have a secure AWS foundation with networking, security, and container storage ready for your application deployment.

Step 1: AWS Account Setup

1.1
Create Production AWS Account

If you don't have an AWS account yet, let's create one. This will be your production account.

  1. Go to https://aws.amazon.com/
  2. Click "Create an AWS Account"
  3. Enter your email address and choose a password
  4. Provide contact information and payment details
  5. Enable MFA on root account immediately!
⚠️ Security First!
Never use your root account for daily operations. We'll create an admin user in the next step.
1.2
Install and Configure AWS CLI

The AWS CLI lets you manage AWS services from your terminal. This is essential for deployment.

bash
# Check if AWS CLI is installed
aws --version

# If not installed, download from:
# https://aws.amazon.com/cli/

# Configure AWS CLI with your credentials
aws configure
# Enter your Access Key ID
# Enter your Secret Access Key
# Enter default region: us-east-1
# Enter default output format: json
💡 Beginner Tip:
Your Access Key ID and Secret Access Key are like a username and password for AWS CLI. Keep them secure and never share them!
1.3
Create IAM Admin User

Create a dedicated admin user for daily operations instead of using the root account.

  1. Go to IAM Console → Users → Add users
  2. Username: helium-admin
  3. Access type: ✅ Programmatic access + ✅ AWS Management Console access
  4. Attach policy: AdministratorAccess
  5. Save credentials securely (download CSV)
  6. Enable MFA on this user
1.4
Configure Cost Management

This is critical! Set up budget alerts to avoid unexpected charges.

🚨 Important for Beginners!
AWS charges can add up quickly. Setting up budget alerts NOW will save you from bill shock later.
  1. Go to AWS Cost Management → Budgets
  2. Click "Create budget"
  3. Budget type: Cost budget
  4. Budget name: helium-production-monthly
  5. Budget amount: $500 (adjust based on your needs)
  6. Configure alerts at: 50%, 80%, 100% of budget
  7. Add your email for notifications

Step 2: Network Architecture (VPC)

🌐 What is a VPC?
A Virtual Private Cloud (VPC) is your own isolated network in AWS. Think of it as your private data center in the cloud where you control all networking.
2.1
Create VPC

We'll create a VPC with public and private subnets across two availability zones for high availability.

VPC Configuration:

  • Name: helium-production-vpc
  • CIDR block: 10.0.0.0/16
  • DNS hostnames: ✅ Enabled
  • DNS resolution: ✅ Enabled
bash
# Create VPC using AWS CLI
aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=helium-production-vpc},{Key=Project,Value=helium},{Key=Environment,Value=production}]' \
  --region us-east-1

# Enable DNS hostnames
aws ec2 modify-vpc-attribute \
  --vpc-id vpc-xxxxxxxxx \
  --enable-dns-hostnames

# Enable DNS support
aws ec2 modify-vpc-attribute \
  --vpc-id vpc-xxxxxxxxx \
  --enable-dns-support
💡 Beginner Tip:
Replace vpc-xxxxxxxxx with the actual VPC ID you get from the create command. AWS will give you this ID in the response.
2.2
Create Subnets

We need three types of subnets: public (for load balancers), private (for applications), and isolated (for databases).

Subnet Layout:

Public Subnets (for ALB, NAT Gateways)
  • 10.0.1.0/24 (us-east-1a)
  • 10.0.2.0/24 (us-east-1b)
Private Subnets (for ECS tasks)
  • 10.0.10.0/24 (us-east-1a)
  • 10.0.11.0/24 (us-east-1b)
Isolated Subnets (for ElastiCache, databases)
  • 10.0.20.0/24 (us-east-1a)
  • 10.0.21.0/24 (us-east-1b)
bash
# Create Public Subnet 1
aws ec2 create-subnet \
  --vpc-id vpc-xxxxxxxxx \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=helium-public-1a}]'

# Create Public Subnet 2
aws ec2 create-subnet \
  --vpc-id vpc-xxxxxxxxx \
  --cidr-block 10.0.2.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=helium-public-1b}]'

# Create Private Subnet 1
aws ec2 create-subnet \
  --vpc-id vpc-xxxxxxxxx \
  --cidr-block 10.0.10.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=helium-private-1a}]'

# Create Private Subnet 2
aws ec2 create-subnet \
  --vpc-id vpc-xxxxxxxxx \
  --cidr-block 10.0.11.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=helium-private-1b}]'

# Create Isolated Subnet 1
aws ec2 create-subnet \
  --vpc-id vpc-xxxxxxxxx \
  --cidr-block 10.0.20.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=helium-isolated-1a}]'

# Create Isolated Subnet 2
aws ec2 create-subnet \
  --vpc-id vpc-xxxxxxxxx \
  --cidr-block 10.0.21.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=helium-isolated-1b}]'

# Enable auto-assign public IP for public subnets
aws ec2 modify-subnet-attribute \
  --subnet-id subnet-xxxxxxxxx \
  --map-public-ip-on-launch
2.3
Create Internet Gateway & NAT Gateways

Internet Gateway allows public subnets to access the internet. NAT Gateways allow private subnets to access the internet (for updates, API calls) without being directly accessible from the internet.

bash
# Create Internet Gateway
aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=helium-production-igw}]'

# Attach to VPC
aws ec2 attach-internet-gateway \
  --internet-gateway-id igw-xxxxxxxxx \
  --vpc-id vpc-xxxxxxxxx

# Allocate Elastic IPs for NAT Gateways
aws ec2 allocate-address --domain vpc
aws ec2 allocate-address --domain vpc

# Create NAT Gateway 1 (in public subnet 1)
aws ec2 create-nat-gateway \
  --subnet-id subnet-public-1a \
  --allocation-id eipalloc-xxxxxxxxx \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=helium-nat-1a}]'

# Create NAT Gateway 2 (in public subnet 2)
aws ec2 create-nat-gateway \
  --subnet-id subnet-public-1b \
  --allocation-id eipalloc-yyyyyyyyy \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=helium-nat-1b}]'
💰 Cost Alert:
NAT Gateways cost ~$32/month each plus data transfer. For production, you need 2 (one per AZ) for high availability. Total: ~$65/month.
2.4
Configure Route Tables

Route tables control where network traffic goes. We need different routes for public, private, and isolated subnets.

bash
# Create Public Route Table
aws ec2 create-route-table \
  --vpc-id vpc-xxxxxxxxx \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=helium-public-rt}]'

# Add route to Internet Gateway
aws ec2 create-route \
  --route-table-id rtb-xxxxxxxxx \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id igw-xxxxxxxxx

# Associate with public subnets
aws ec2 associate-route-table \
  --route-table-id rtb-xxxxxxxxx \
  --subnet-id subnet-public-1a

aws ec2 associate-route-table \
  --route-table-id rtb-xxxxxxxxx \
  --subnet-id subnet-public-1b

# Create Private Route Table 1
aws ec2 create-route-table \
  --vpc-id vpc-xxxxxxxxx \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=helium-private-rt-1a}]'

# Add route to NAT Gateway 1
aws ec2 create-route \
  --route-table-id rtb-private-1a \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id nat-xxxxxxxxx

# Associate with private subnet 1a
aws ec2 associate-route-table \
  --route-table-id rtb-private-1a \
  --subnet-id subnet-private-1a

# Repeat for private subnet 1b with NAT Gateway 2

Step 3: Security Groups

🔒 What are Security Groups?
Security groups are virtual firewalls that control inbound and outbound traffic to your AWS resources. They're essential for security!
3.1
Create ALB Security Group

This security group controls traffic to your Application Load Balancer.

bash
# Create ALB Security Group
aws ec2 create-security-group \
  --group-name helium-alb-sg \
  --description "Security group for Application Load Balancer" \
  --vpc-id vpc-xxxxxxxxx

# Allow HTTPS from anywhere
aws ec2 authorize-security-group-ingress \
  --group-id sg-alb-xxxxxxxxx \
  --protocol tcp \
  --port 443 \
  --cidr 0.0.0.0/0

# Allow HTTP (for redirect to HTTPS)
aws ec2 authorize-security-group-ingress \
  --group-id sg-alb-xxxxxxxxx \
  --protocol tcp \
  --port 80 \
  --cidr 0.0.0.0/0
3.2
Create ECS Task Security Group
bash
# Create ECS Task Security Group
aws ec2 create-security-group \
  --group-name helium-ecs-task-sg \
  --description "Security group for ECS tasks" \
  --vpc-id vpc-xxxxxxxxx

# Allow traffic from ALB only
aws ec2 authorize-security-group-ingress \
  --group-id sg-ecs-xxxxxxxxx \
  --protocol tcp \
  --port 8000 \
  --source-group sg-alb-xxxxxxxxx

# Allow all outbound traffic (for API calls, updates)
aws ec2 authorize-security-group-egress \
  --group-id sg-ecs-xxxxxxxxx \
  --protocol -1 \
  --cidr 0.0.0.0/0
3.3
Create ElastiCache Security Group
bash
# Create ElastiCache Security Group
aws ec2 create-security-group \
  --group-name helium-elasticache-sg \
  --description "Security group for ElastiCache Redis" \
  --vpc-id vpc-xxxxxxxxx

# Allow Redis traffic from ECS tasks only
aws ec2 authorize-security-group-ingress \
  --group-id sg-redis-xxxxxxxxx \
  --protocol tcp \
  --port 6379 \
  --source-group sg-ecs-xxxxxxxxx

Step 4: Container Registry (ECR)

📦 What is ECR?
Elastic Container Registry (ECR) is where you store your Docker images. Think of it as a private Docker Hub for your AWS account.
4.1
Create ECR Repositories
bash
# Create backend repository
aws ecr create-repository \
  --repository-name helium-backend \
  --image-scanning-configuration scanOnPush=true \
  --encryption-configuration encryptionType=AES256 \
  --region us-east-1

# Create frontend repository (if needed)
aws ecr create-repository \
  --repository-name helium-frontend \
  --image-scanning-configuration scanOnPush=true \
  --encryption-configuration encryptionType=AES256 \
  --region us-east-1
✅ 2025 Update:
Image scanning is now enabled by default to detect vulnerabilities. Encryption ensures your images are secure at rest.
4.2
Configure Lifecycle Policies

Lifecycle policies automatically clean up old images to save storage costs.

json
{
  "rules": [
    {
      "rulePriority": 1,
      "description": "Keep last 10 images",
      "selection": {
        "tagStatus": "any",
        "countType": "imageCountMoreThan",
        "countNumber": 10
      },
      "action": {
        "type": "expire"
      }
    }
  ]
}
bash
# Save the JSON above as lifecycle-policy.json, then:
aws ecr put-lifecycle-policy \
  --repository-name helium-backend \
  --lifecycle-policy-text file://lifecycle-policy.json \
  --region us-east-1
4.3
Test ECR Push

Let's test that you can push images to ECR successfully.

bash
# Get your AWS account ID
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# Login to ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  $ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com

# Build a test image (from your backend directory)
cd backend
docker build -t helium-backend:test .

# Tag the image
docker tag helium-backend:test \
  $ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/helium-backend:test

# Push to ECR
docker push $ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com/helium-backend:test

# Verify the image
aws ecr describe-images \
  --repository-name helium-backend \
  --region us-east-1
✅ Success!
If you see your image listed, ECR is working correctly. You're ready to move forward!

Phase 1 Verification Checklist

Before proceeding to Phase 2, make sure all these items are complete:

Common Issues & Solutions

Issue: Cannot push to ECR

Solution:

# Re-authenticate Docker with ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin \
  $ACCOUNT_ID.dkr.ecr.us-east-1.amazonaws.com
Issue: NAT Gateway not working

Check:

  • Verify route table has route to NAT Gateway
  • Check NAT Gateway is in public subnet
  • Verify Elastic IP is attached
  • Check security groups allow traffic
Issue: AWS CLI commands not working

Solution:

# Verify AWS CLI is configured
aws configure list

# Check your credentials
aws sts get-caller-identity

# If issues persist, reconfigure
aws configure