Have you ever launched an EC2 instance, convinced you picked the right type, only to find a 40% higher bill a month later? Or exposed a server with SSH open to the entire internet, ending up with a crypto miner instead of your application? It happens more often than you'd think. At Meteora Web, after years of managing AWS infrastructures, we've seen dozens of cases where a better understanding of these four elements — instance type, AMI, security group, and key pair — would have prevented wasted costs, security holes, and hours of debugging. This guide walks you through each one, with real-world examples and commands you can run right now.
Choosing the Right Instance Type
EC2 offers dozens of instance families. The problem is many people start with the default (t2.micro free tier) and later realize a production workload needs something else. The wrong choice hits your budget directly: a memory-optimized instance for a lightweight web server is like buying a truck to carry groceries.
Instance families at a glance
- General purpose (A/T/M) – balanced CPU, RAM, network. Ideal for web servers, dev environments, small databases.
- Compute optimized (C) – high CPU, moderate RAM. For batch processing, rendering, ML training.
- Memory optimized (R/X) – lots of RAM, enough CPU. In-memory databases (Redis, Memcached), SAP, large data analytics.
- Storage optimized (I/D) – high-speed NVMe SSDs. Transactional databases, data warehousing.
- GPU (P/G) – 3D rendering, deep learning, video transcoding.
Reading instance names
Take c6g.2xlarge:
c= compute optimized family6= generation (6a = AMD, 6g = ARM Graviton)g= ARM processor (Graviton). Missing = Intel;a= AMD2xlarge= size (micro, small, medium, large, xlarge, 2xlarge...)
Using AWS CLI to explore instance types
Before launching, list available types in your region:
aws ec2 describe-instance-types --filters "Name=instance-type,Values=m5.*" --query "InstanceTypes[].[InstanceType, VCpuInfo.DefaultVCpus, MemoryInfo.SizeInMiB]" --output table
Check pricing in real-time (example for eu-west-1):
aws pricing get-products --service-code AmazonEC2 --filters "Type=TERM_MATCH,Field=instanceType,Value=t3.medium" "Type=TERM_MATCH,Field=regionCode,Value=eu-west-1" | jq '.PriceList[]'
Watch out for burstable instances (t2/t3/t4g)
They earn CPU credits when idle and burn them under load. Perfect for dev or low-traffic sites. If your workload is steady at 40% for hours, credits run out and the instance gets throttled. In that case, switch to a general purpose type (m5/m6i).
AMI – your tailored operating system
An Amazon Machine Image is a snapshot of a configured system. Choosing the right AMI saves hours of setup and ensures a secure environment from boot.
Types of AMIs
- Public – provided by AWS (Amazon Linux, Windows Server) or the community (Ubuntu, Debian, CentOS).
- Marketplace – with pre-installed software (e.g., WordPress, LAMP, SAP).
- Custom – created by you from an existing instance. This is the best choice for production: you have exactly the packages and configurations you need.
Creating a custom AMI from CLI
Say you configured a server with nginx, PHP, and a Laravel app. Immortalize it:
aws ec2 create-image --instance-id i-0abcdef1234567890 --name "laravel-prod-2026-03-01" --no-reboot
The --no-reboot flag avoids a forced restart, but for filesystem consistency it's better to stop the instance first. Then launch new instances from this AMI in seconds.
Practical tips
- Amazon Linux 2023 is optimized for AWS (tuned kernel, Systems Manager integration).
- Ubuntu 24.04 LTS has fresher packages for modern applications.
- Keep AMIs updated: rebuild the image monthly with the latest security patches.
- Tag AMIs with version and date to track the latest.
Security Group – your instance firewall
Security groups are stateful firewalls at the instance level. Every inbound rule must be justified. We always see the same mistake: SSH open to 0.0.0.0/0 (the whole world) – “I’ll change it later”. You'll change it after the first brute-force attempt, if you're lucky.
Stateful rules explained
If you allow inbound on port 80, the outbound response is automatically allowed. No symmetric rules needed. However, default outbound is open to everything. For sensitive environments, restrict outbound only to what's required (e.g., only to internet for updates, only to RDS for database).
Example security group for a web server
Create a security group called web-sg with AWS CLI:
aws ec2 create-security-group --group-name web-sg --description "Security group for web servers" --vpc-id vpc-12345
# SSH only from corporate IP
aws ec2 authorize-security-group-ingress --group-id sg-abc123 --protocol tcp --port 22 --cidr 203.0.113.0/24
# HTTP and HTTPS from anywhere
aws ec2 authorize-security-group-ingress --group-id sg-abc123 --protocol tcp --port 80 --cidr 0.0.0.0/0
aws ec2 authorize-security-group-ingress --group-id sg-abc123 --protocol tcp --port 443 --cidr 0.0.0.0/0
# (Optional) Outbound only for updates
aws ec2 authorize-security-group-egress --group-id sg-abc123 --protocol tcp --port 443 --cidr 0.0.0.0/0
Common mistakes to avoid
- Port 22 (SSH) open to 0.0.0.0/0. Use a fixed IP or a bastion host.
- Applying the same security group to all instances without differentiating roles (web, database, admin).
- Forgetting to remove old rules after changing VPN or IP address.
- Using the default VPC security group which is usually too permissive.
Key Pair – your only access key
Key pairs (RSA or ED25519) are the standard method for SSH access to Linux instances. Lose the private key? You lose access to the instance. No recovery via console, unless you set up an alternative mechanism (e.g., Session Manager).
Creating a key pair
From AWS Console:
- Go to EC2 → Key Pairs → Create key pair
- Choose format (PEM for OpenSSH, PPK for PuTTY)
- Download the private key immediately. Amazon does not keep it.
Or via CLI:
aws ec2 create-key-pair --key-name mio-key --key-type rsa --output text > mio-key.pem
chmod 400 mio-key.pem
You can also import an existing public key:
aws ec2 import-key-pair --key-name mio-key-import --public-key-material fileb://~/.ssh/id_rsa.pub
Best practices for key management
- Permissions 400 on the private key (owner read only).
- Never share the private key via email or chat. Use a password manager or vault.
- Use different keys per environment (dev, staging, prod).
- Add Session Manager (SSM) as a backdoor: if you lose the key, you can still access via IAM.
- Rotate keys periodically (at least once a year).
In summary – what to do now
- Analyze your workload before choosing an instance type. Use CloudWatch or a simple benchmark to see if you need more CPU, RAM, or I/O.
- Build a custom AMI for your production environment. Automate with Packer or just use create-image after each update.
- Lock down SSH to a specific IP in your security group. For teams, use a bastion host or VPN.
- Apply least-privilege even to outbound ports: don't allow all outbound traffic unless necessary.
- Protect your private keys with 400 permissions and an encrypted backup. Have a recovery plan (SSM) so you never get locked out.
To dive deeper into managing AWS permissions, check our guide on IAM AWS: Least Privilege and Policy Management. And remember: an EC2 instance is not just a virtual server – it's your digital asset. Treat it accordingly.
Sponsored Protocol