cheat-sheets

Amazon Web Services

AWS from a self-hoster’s point of view: the few services worth using for a VPS, off-site backups, DNS and cost control, and the pitfalls that generate surprise bills. For generic CLI usage see AWS CLI; to compare providers see Cloud-Provider Comparison.

Documentation: AWS CLI Command Reference · AWS Free Tier · Terraform AWS provider (see Terraform)

Verification: flag names were checked against the AWS CLI reference pages and prices against the AWS pricing pages (November 2026). No command was run against an account. Prices and free-tier terms change often, so check the pricing pages before relying on a figure. Items marked (unverified) were not confirmed.

Services a Self-Hoster Uses #

NEEDSERVICENOTES
Virtual machineEC2Billed per second while running
Simple fixed-price VPSLightsailCheaper and simpler than EC2 for one box
Object storageS3Off-site backups, static files
Cold backupsS3 Glacier classesCheap to store, restore delay and fees
DNSRoute 53Hosted zones are billed monthly per zone
FirewallSecurity groupsStateful, per instance or network interface
Disk snapshotsEBS snapshots, Data Lifecycle ManagerScheduled and retained automatically
Access controlIAMOne user or role per purpose, MFA on root
Cost controlBudgets, Cost ExplorerSet a budget on day one

Free Tier #

  • New accounts get a Free plan: $100 of credits, with up to $100 more for exploring services. It ends after 6 months or when the credits run out. The Paid plan gets up to $200 of credits. Source: AWS Free Tier.
  • Older accounts may still be on the previous 12-month model. Check the Billing console for which applies.
  • Always set a budget (below) even on the Free plan.

EC2 #

COMMANDDESCRIPTION
aws ec2 run-instances --image-id <AMI_ID> --instance-type <TYPE> --key-name <KEY_NAME> --security-group-ids <SG_ID> --subnet-id <SUBNET_ID>Launch an instance
--image-id resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64Use the latest Amazon Linux 2023 AMI (a value for --image-id)
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=<NAME>}]'Tag the instance at launch
aws ec2 describe-instancesList instances (see AWS CLI for queries)
aws ec2 stop-instances --instance-ids <ID>Stop (compute billing stops, see pitfalls)
aws ec2 terminate-instances --instance-ids <ID>Delete the instance (destroys its data unless volumes are kept)

Security Groups #

COMMANDDESCRIPTION
aws ec2 create-security-group --group-name <NAME> --description <TEXT> --vpc-id <VPC_ID>Create a group
aws ec2 authorize-security-group-ingress --group-id <SG_ID> --protocol tcp --port 22 --cidr 203.0.113.10/32Allow SSH from one address only
aws ec2 describe-security-groups --group-ids <SG_ID>Show the rules

Never open SSH or admin ports to 0.0.0.0/0. Use a VPN such as WireGuard or Tailscale instead.

Snapshots and Backups #

COMMANDDESCRIPTION
aws ec2 create-snapshot --volume-id <VOLUME_ID> --description <TEXT>One-off EBS snapshot
aws dlm create-lifecycle-policy --execution-role-arn <ROLE_ARN> --description <TEXT> --state ENABLED --policy-details file://policy.jsonScheduled snapshots with retention (Data Lifecycle Manager)
aws dlm get-lifecycle-policiesList policies

S3 #

COMMANDDESCRIPTION
aws s3 mb s3://<BUCKET>Create a bucket
aws s3 sync <DIR> s3://<BUCKET>/<PREFIX>Upload changes (add --delete only if you want removals mirrored)
aws s3api put-public-access-block --bucket <BUCKET> --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=trueBlock all public access
aws s3api put-bucket-lifecycle-configuration --bucket <BUCKET> --lifecycle-configuration file://lifecycle.jsonApply lifecycle rules (transition or expire)
STORAGE CLASSUSEMINIMUM STORAGE
STANDARDFrequent accessnone
STANDARD_IAInfrequent access, millisecond reads, retrieval fee30 days, 128 KB objects
GLACIER_IRRarely read (about quarterly), millisecond reads90 days
GLACIER (Flexible Retrieval)Archive, restore takes minutes to hours90 days
DEEP_ARCHIVELong-term archive, restore takes hours180 days

Lifecycle rule moving backups to Glacier Instant Retrieval after 30 days and deleting after a year (lifecycle.json):

json
{
  "Rules": [
    {
      "ID": "age-out-backups",
      "Status": "Enabled",
      "Filter": { "Prefix": "backups/" },
      "Transitions": [{ "Days": 30, "StorageClass": "GLACIER_IR" }],
      "Expiration": { "Days": 365 }
    }
  ]
}

Use S3 as a backup target with restic or rclone.

IAM for a Backup User #

Create one user per purpose with only the access it needs. A policy limited to one bucket (BUCKET is a placeholder), adapted from the AWS S3 example policies:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::BUCKET"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::BUCKET/*"
    }
  ]
}
COMMANDDESCRIPTION
aws iam create-user --user-name <NAME>Create the user
aws iam put-user-policy --user-name <NAME> --policy-name <POLICY> --policy-document file://policy.jsonAttach an inline policy
aws iam create-access-key --user-name <NAME>Create keys (the secret is shown once, store it in a password manager)
aws sts get-caller-identityCheck who the current credentials are

To stop a backup tool deleting its own history, omit s3:DeleteObject and rely on lifecycle rules.

DNS (Route 53) #

COMMANDDESCRIPTION
aws route53 list-hosted-zonesList zones
aws route53 change-resource-record-sets --hosted-zone-id <ZONE_ID> --change-batch file://change.jsonCreate, update or delete records (the JSON holds Changes with an Action of UPSERT, CREATE or DELETE)

Cost Control #

COMMANDDESCRIPTION
aws budgets create-budget --account-id <ACCOUNT_ID> --budget file://budget.json --notifications-with-subscribers file://notifications.jsonCreate a budget with e-mail alerts
aws ce get-cost-and-usage --time-period Start=2026-11-01,End=2026-12-01 --granularity MONTHLY --metrics UnblendedCost --group-by Type=DIMENSION,Key=SERVICECost by service for a period

Pitfalls #

PITFALLDETAIL
Public IPv4 addresses are billed$0.005 per hour per address, in use or idle (VPC pricing)
NAT gateway$0.045 per hour plus $0.045 per GB processed in the example region (us-east-2); other regions (unverified). Use a public subnet or a NAT instance for a homelab
Data transfer outFirst 100 GB per month to the internet is free, then charged per GB (EC2 pricing)
Stopped instancesCompute billing stops; EBS volume and Elastic IP charges continue (EBS while stopped unverified on the pricing page; allocated Elastic IPs are charged in use or idle)
Orphaned snapshots and volumesRemain billed after the instance is terminated
Access keysLong-lived keys leak; prefer roles or SSO and never commit ~/.aws/credentials
Root accountEnable MFA and do not use it day to day

See Also #

Search all sheets

Tip: / or Ctrl/Cmd+K to open, Esc to close.