When working with AWS Free Tier, many developers overlook that some services have hard limits while others operate on cumulative monthly usage. EC2 instances under Free Tier include:
- 750 hours of t2.micro or t3.micro instances per month
- 30GB of EBS storage (gp2)
- 15GB of data transfer out
The most effective way to monitor your usage is through AWS Budgets. Here's how to set it up:
aws budgets create-budget \
--account-id YOUR_ACCOUNT_ID \
--budget file://budget.json \
--notifications-with-subscribers file://notifications.json
Example budget.json:
{
"Budget": {
"BudgetName": "Free-Tier-Monitoring",
"BudgetLimit": {
"Amount": "0.01",
"Unit": "USD"
},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}
}
Use AWS Instance Scheduler to automatically stop instances during non-working hours:
Resources:
EC2Scheduler:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/solutions-reference/aws-instance-scheduler/latest/instance-scheduler.template
Parameters:
ScheduledServices: "EC2"
ScheduleRdsClusters: "false"
DefaultTimezone: "UTC"
Create a custom CloudWatch dashboard with these essential metrics:
- CPUUtilization (keep below 40% for t* instances)
- NetworkOut (watch for spikes)
- EBSReadOps/EBSWriteOps
aws cloudwatch put-dashboard \
--dashboard-name "FreeTierMonitoring" \
--dashboard-body file://dashboard.json
Programmatically check your usage with the AWS Cost Explorer API:
import boto3
from datetime import datetime, timedelta
client = boto3.client('ce')
response = client.get_cost_and_usage(
TimePeriod={
'Start': str(datetime.now().date().replace(day=1)),
'End': str(datetime.now().date())
},
Granularity='MONTHLY',
Metrics=['UnblendedCost'],
Filter={
'Dimensions': {
'Key': 'USAGE_TYPE_GROUP',
'Values': ['EC2: Running Hours']
}
}
)
The AWS Free Tier offers 750 hours of EC2 t2.micro instance usage per month for 12 months. That's equivalent to running one instance continuously for the entire month. However, many developers accidentally exceed this limit by:
- Launching multiple instances simultaneously
- Using larger instance types (even temporarily)
- Forgetting to terminate test instances
Create a billing alarm to monitor your Free Tier usage:
aws cloudwatch put-metric-alarm \
--alarm-name "FreeTierUsageAlert" \
--metric-name "EstimatedCharges" \
--namespace "AWS/Billing" \
--statistic "Maximum" \
--dimensions Name=Currency,Value=USD \
--period 21600 \
--evaluation-periods 1 \
--threshold 0.01 \
--comparison-operator "GreaterThanThreshold" \
--alarm-actions "arn:aws:sns:us-east-1:123456789012:FreeTierAlerts"
Use AWS Instance Scheduler to automatically stop instances during non-working hours:
# CloudFormation template snippet
Resources:
InstanceScheduler:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: https://s3.amazonaws.com/solutions-reference/aws-instance-scheduler/latest/instance-scheduler.template
Parameters:
StartedTags: "Environment=Dev,Owner=Team"
StoppedTags: "Environment=Dev,Owner=Team"
DefaultTimezone: "UTC"
ScheduleLambdaAccount: "123456789012"
SchedulerFrequency: "5"
Query your usage programmatically using the AWS Cost Explorer API:
import boto3
from datetime import datetime, timedelta
def check_free_tier_usage():
ce = boto3.client('ce')
end = datetime.utcnow()
start = end - timedelta(days=30)
response = ce.get_cost_and_usage(
TimePeriod={
'Start': start.strftime('%Y-%m-%d'),
'End': end.strftime('%Y-%m-%d')
},
Granularity='MONTHLY',
Metrics=['UnblendedCost'],
Filter={
'Dimensions': {
'Key': 'USAGE_TYPE_GROUP',
'Values': ['EC2: Running Hours']
}
}
)
return response['ResultsByTime'][0]['Total']['UnblendedCost']['Amount']
print(f"Current EC2 usage: ${check_free_tier_usage()}")
Implement mandatory tagging to track Free Tier resources:
aws ec2 create-tags \
--resources i-1234567890abcdef0 \
--tags Key=Environment,Value=Dev Key=Project,Value=FreeTier Key=Owner,Value=YourName
Create a zero-dollar budget for Free Tier services:
aws budgets create-budget \
--account-id 123456789012 \
--budget file://budget.json \
--notifications-with-subscribers file://notifications.json
budget.json:
{
"BudgetName": "FreeTierBudget",
"BudgetLimit": {
"Amount": "0",
"Unit": "USD"
},
"CostFilters": {
"Service": ["Amazon Elastic Compute Cloud - Compute"]
},
"TimeUnit": "MONTHLY",
"BudgetType": "COST"
}
When using Terraform for Free Tier deployments:
resource "aws_instance" "free_tier" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
tags = {
Name = "FreeTierInstance"
Environment = "Development"
AutoStop = "true"
}
lifecycle {
prevent_destroy = false
}
}
resource "aws_cloudwatch_metric_alarm" "instance_runtime" {
alarm_name = "free-tier-runtime"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "1"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "86400"
statistic = "Maximum"
threshold = "1"
alarm_description = "Monitor free tier instance runtime"
alarm_actions = [aws_sns_topic.free_tier_alerts.arn]
}