The fundamental difference between EC2-Classic and VPC environments affects IP retention:
// Pseudo-code showing IP assignment behavior
if (environment == EC2-Classic) {
releaseAllIPsOnStop();
assignNewIPsOnStart();
} else if (environment == EC2-VPC) {
retainPrivateIPs();
releasePublicIPv4();
assignNewPublicIPv4OnStart();
}
For VPC instances where you need consistent public IPs:
# AWS CLI example to associate Elastic IP
aws ec2 allocate-address --domain vpc
aws ec2 associate-address --instance-id i-1234567890abcdef0 --allocation-id eipalloc-12345678
Here's a CloudFormation template snippet for Elastic IP association:
Resources:
MyEIP:
Type: AWS::EC2::EIP
Properties:
Domain: vpc
EC2Instance:
Type: AWS::EC2::Instance
Properties:
# Instance properties...
EIPAssociation:
Type: AWS::EC2::EIPAssociation
Properties:
InstanceId: !Ref EC2Instance
AllocationId: !Ref MyEIP
Lambda function to monitor and reattach EIPs:
import boto3
def lambda_handler(event, context):
ec2 = boto3.client('ec2')
instance_id = event['detail']['instance-id']
# Check if instance has EIP association
response = ec2.describe_addresses(
Filters=[{'Name': 'instance-id', 'Values': [instance_id]}]
)
if not response['Addresses']:
# Reattach previously stored EIP from DynamoDB
# Implementation omitted for brevity
pass
For advanced scenarios with multiple interfaces:
# Create ENI with specific private IP
aws ec2 create-network-interface \
--subnet-id subnet-123456 \
--private-ip-address 10.0.0.100 \
--groups sg-123456
When managing EC2 instances, IP address changes during stop/start cycles can disrupt configurations requiring stable endpoints. AWS handles this differently between EC2-Classic and VPC environments:
// AWS Default Behavior
EC2-Classic:
- Releases both public/private IPv4 on stop
- Assigns new addresses on start
EC2-VPC:
- Retains private IPv4 and any IPv6
- Releases public IPv4 (gets new one on start)
For VPC instances, associate an Elastic IP (EIP) before stopping:
# AWS CLI example
aws ec2 allocate-address --domain vpc
aws ec2 associate-address --instance-id i-1234567890abcdef0 --allocation-id eipalloc-12345678
# Terraform example
resource "aws_eip" "example" {
vpc = true
}
resource "aws_eip_association" "example" {
instance_id = aws_instance.example.id
allocation_id = aws_eip.example.id
}
For EC2-Classic (being deprecated), consider:
- Launching in VPC instead
- Using Elastic Network Interfaces (ENIs) with fixed IPs:
# Create ENI with specific IP
aws ec2 create-network-interface \
--subnet-id subnet-123456 \
--private-ip-address 10.0.0.100
# Attach to instance
aws ec2 attach-network-interface \
--network-interface-id eni-123456 \
--instance-id i-1234567890abcdef0 \
--device-index 1
When IP persistence isn't possible, implement dynamic DNS updates:
#!/bin/bash
# Route 53 update script
INSTANCE_IP=$(curl http://169.254.169.254/latest/meta-data/public-ipv4)
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890 \
--change-batch '{
"Changes": [{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"TTL": 300,
"ResourceRecords": [{"Value": "'$INSTANCE_IP'"}]
}
}]
}'
For production systems requiring high availability:
- Use Application Load Balancers instead of instance IPs
- Implement Auto Scaling groups with health checks
- Consider CloudFront distributions for static content