AWS Free Tier gives you enough compute, storage, and serverless capacity to run a production-quality side project for 12 months without spending a rupee. This guide is tailored for Indian developers — we use the ap-south-1 (Mumbai) region for lowest latency to Indian users, and every command is tested and ready to run.
Setting Up Your AWS Account
Create your AWS account at aws.amazon.com. You will need a credit or debit card (Visa/Mastercard — RuPay is not supported). AWS will place a temporary hold of $1 (approximately 84 INR) for verification. Install and configure the AWS CLI:
# Install AWS CLI v2
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
# Configure with your credentials
aws configure
# AWS Access Key ID: YOUR_ACCESS_KEY
# AWS Secret Access Key: YOUR_SECRET_KEY
# Default region name: ap-south-1
# Default output format: json
# Verify configuration
aws sts get-caller-identity
Security first: Never use your root account for daily operations. Create an IAM user with programmatic access and attach the appropriate policies.
# Create an IAM user for CLI access
aws iam create-user --user-name deploy-user
# Attach necessary policies
aws iam attach-user-policy \
--user-name deploy-user \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
aws iam attach-user-policy \
--user-name deploy-user \
--policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
aws iam attach-user-policy \
--user-name deploy-user \
--policy-arn arn:aws:iam::aws:policy/AWSLambda_FullAccess
# Create access keys
aws iam create-access-key --user-name deploy-user
EC2: Your Virtual Server
The Free Tier gives you 750 hours per month of a t2.micro instance (1 vCPU, 1 GB RAM). That is enough to run a small Node.js, Python, or Java application 24/7. Let us launch one:
# Create a key pair for SSH access
aws ec2 create-key-pair \
--key-name my-app-key \
--query 'KeyMaterial' \
--output text \
--region ap-south-1 > my-app-key.pem
chmod 400 my-app-key.pem
# Create a security group
aws ec2 create-security-group \
--group-name my-app-sg \
--description "Security group for my application" \
--region ap-south-1
# Allow SSH (port 22) and HTTP (port 80)
SG_ID=$(aws ec2 describe-security-groups \
--group-names my-app-sg \
--query 'SecurityGroups[0].GroupId' \
--output text \
--region ap-south-1)
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--protocol tcp --port 22 --cidr 0.0.0.0/0 \
--region ap-south-1
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--protocol tcp --port 80 --cidr 0.0.0.0/0 \
--region ap-south-1
# Launch the instance (Amazon Linux 2023 AMI)
aws ec2 run-instances \
--image-id ami-0e35ddab05955cf57 \
--instance-type t2.micro \
--key-name my-app-key \
--security-group-ids $SG_ID \
--region ap-south-1 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-app-server}]'
# Get the public IP
INSTANCE_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=my-app-server" \
--query 'Reservations[0].Instances[0].InstanceId' \
--output text --region ap-south-1)
aws ec2 describe-instances \
--instance-ids $INSTANCE_ID \
--query 'Reservations[0].Instances[0].PublicIpAddress' \
--output text --region ap-south-1
SSH in and deploy a simple Node.js app:
# SSH into the instance
ssh -i my-app-key.pem ec2-user@YOUR_PUBLIC_IP
# Install Node.js
sudo dnf install -y nodejs
# Create a simple Express app
mkdir ~/myapp && cd ~/myapp
npm init -y
npm install express
cat > index.js <<'EOF'
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.json({
message: 'Hello from AWS Mumbai!',
region: 'ap-south-1',
timestamp: new Date().toISOString(),
});
});
app.get('/health', (req, res) => {
res.json({ status: 'healthy', uptime: process.uptime() });
});
app.listen(80, () => console.log('Server running on port 80'));
EOF
# Run with sudo (port 80 requires root)
sudo node index.js
S3: Static File Hosting
S3 Free Tier gives you 5 GB storage, 20,000 GET requests, and 2,000 PUT requests per month. Perfect for hosting a static website or storing assets:
# Create a bucket (names must be globally unique)
aws s3 mb s3://my-app-static-2026 --region ap-south-1
# Enable static website hosting
aws s3 website s3://my-app-static-2026 \
--index-document index.html \
--error-document error.html
# Create and upload a simple website
cat > index.html <<'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My App</title>
<style>
body { font-family: system-ui; max-width: 600px; margin: 80px auto; padding: 0 20px; }
h1 { color: #1a1a2e; }
</style>
</head>
<body>
<h1>Deployed on S3 Mumbai</h1>
<p>This static site is hosted on AWS S3 in ap-south-1.</p>
</body>
</html>
EOF
# Upload with public-read ACL
aws s3 cp index.html s3://my-app-static-2026/ \
--content-type "text/html" \
--region ap-south-1
# Set bucket policy for public access
cat > bucket-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-app-static-2026/*"
}
]
}
EOF
aws s3api put-bucket-policy \
--bucket my-app-static-2026 \
--policy file://bucket-policy.json \
--region ap-south-1
# Your site is now live at:
# http://my-app-static-2026.s3-website.ap-south-1.amazonaws.com
Lambda: Serverless Functions
Lambda Free Tier gives you 1 million requests and 400,000 GB-seconds of compute per month — permanently, not just for 12 months. Here is how to deploy an API endpoint:
# Create the Lambda function code
cat > lambda_function.py <<'EOF'
import json
from datetime import datetime
def handler(event, context):
path = event.get('rawPath', '/')
method = event.get('requestContext', {}).get('http', {}).get('method', 'GET')
if path == '/api/greet':
name = event.get('queryStringParameters', {}).get('name', 'World')
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'body': json.dumps({
'message': f'Namaste, {name}!',
'region': 'ap-south-1',
'timestamp': datetime.utcnow().isoformat(),
}),
}
return {
'statusCode': 404,
'body': json.dumps({'error': 'Not found'}),
}
EOF
# Package the function
zip function.zip lambda_function.py
# Create an IAM role for Lambda
cat > trust-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "lambda.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
EOF
aws iam create-role \
--role-name lambda-basic-role \
--assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy \
--role-name lambda-basic-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
# Wait for role propagation, then create the function
ROLE_ARN=$(aws iam get-role --role-name lambda-basic-role \
--query 'Role.Arn' --output text)
aws lambda create-function \
--function-name my-api \
--runtime python3.12 \
--handler lambda_function.handler \
--zip-file fileb://function.zip \
--role $ROLE_ARN \
--region ap-south-1 \
--memory-size 128 \
--timeout 10
# Create a Function URL (free alternative to API Gateway)
aws lambda create-function-url-config \
--function-name my-api \
--auth-type NONE \
--region ap-south-1
# Allow public access
aws lambda add-permission \
--function-name my-api \
--statement-id FunctionURLAllowPublicAccess \
--action lambda:InvokeFunctionUrl \
--principal "*" \
--function-url-auth-type NONE \
--region ap-south-1
# Get the function URL
aws lambda get-function-url-config \
--function-name my-api \
--region ap-south-1 \
--query 'FunctionUrl' --output text
Cost Monitoring: Avoid Surprise Bills
The biggest fear for Indian developers using AWS is an unexpected bill. Set up billing alerts immediately:
# Enable billing alerts in us-east-1 (billing metrics are only in us-east-1)
aws cloudwatch put-metric-alarm \
--alarm-name "billing-alarm-500inr" \
--alarm-description "Alert when estimated charges exceed $6 (approx 500 INR)" \
--metric-name EstimatedCharges \
--namespace AWS/Billing \
--statistic Maximum \
--period 21600 \
--threshold 6 \
--comparison-operator GreaterThanThreshold \
--evaluation-periods 1 \
--alarm-actions arn:aws:sns:us-east-1:YOUR_ACCOUNT_ID:billing-alerts \
--dimensions Name=Currency,Value=USD \
--region us-east-1
Also enable AWS Free Tier usage alerts in Billing → Billing preferences → Free Tier usage alerts. AWS will email you when you approach 85% of any Free Tier limit.
Conclusion
With EC2 for server workloads, S3 for static hosting, and Lambda for serverless APIs — all in the ap-south-1 Mumbai region — you have a complete deployment stack that costs nothing within Free Tier limits. The key is to always set billing alerts, use t2.micro (not t3.micro which has different Free Tier rules), and shut down resources you are not using. AWS is the most widely used cloud platform in India’s job market, and hands-on experience with real deployments will set you apart.