How to Preserve AWS EC2 Instance IP Addresses During Stop/Start Operations


8 views

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:

  1. Launching in VPC instead
  2. 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