When working with AWS EC2 instances, many developers encounter this scenario: You stop a running instance (perhaps for maintenance like expanding the boot volume), then start it again - only to discover the public IP address has changed. This isn't a bug but rather AWS's default behavior for instances not configured with Elastic IPs.
AWS uses dynamic public IP addressing by default. When you:
1. Launch a new instance
2. Stop and start an existing instance
The public IP gets released back to the AWS pool and a new one is assigned. Only Elastic IPs remain persistent.
Here's how to verify the IP change using AWS CLI:
# Before stopping instance aws ec2 describe-instances --instance-ids i-1234567890abcdef0 --query 'Reservations[0].Instances[0].PublicIpAddress' --output text # After stop/start aws ec2 describe-instances --instance-ids i-1234567890abcdef0 --query 'Reservations[0].Instances[0].PublicIpAddress' --output text
The two commands will return different IP addresses if you haven't used an Elastic IP.
Option 1: Assign an Elastic IP
Elastic IPs remain associated with your account until you explicitly release them.
# Allocate new Elastic IP aws ec2 allocate-address --domain vpc # Associate with instance aws ec2 associate-address --instance-id i-1234567890abcdef0 --public-ip 203.0.113.10
Option 2: Use DNS with Route 53
Create a CNAME record pointing to your instance's public DNS name which remains consistent despite IP changes.
IP changes can disrupt:
- SSH/RDP connections relying on IP whitelisting
- Application configurations hardcoding IP addresses
- DNS records with low TTL values
Always design systems to handle IP changes or use the solutions above.
For dynamic environments, consider this Lambda function triggered by EC2 state changes:
import boto3 def lambda_handler(event, context): ec2 = boto3.client('ec2') if event['detail']['state'] == 'running': instance_id = event['detail']['instance-id'] # Your logic to update DNS or notify teams print(f"Instance {instance_id} started with new IP")
html
Understanding EC2 IP Address Behavior
When working with AWS EC2 instances, it's crucial to understand that stopping and starting an instance (as opposed to rebooting) will typically result in a new public IP address assignment. This is default AWS behavior unless you've taken specific measures to prevent it.
The key distinctions:
- Reboot: Maintains the same instance ID and IP addresses
- Stop-Start: Essentially creates a new instance launch from your existing configuration
The IP reassignment occurs because:
- AWS releases the public IP back into the pool when the instance stops
- The elastic IP association (if present) is maintained, but regular public IP isn't
- The underlying virtualization may place your instance on different physical hardware
Here's how you can programmatically verify this behavior using AWS CLI:
# Get current public IP before stopping INSTANCE_ID="i-0123456789abcdef0" PREVIOUS_IP=$(aws ec2 describe-instances \ --instance-ids $INSTANCE_ID \ --query 'Reservations[0].Instances[0].PublicIpAddress' \ --output text) echo "Current public IP: $PREVIOUS_IP" # Stop the instance aws ec2 stop-instances --instance-ids $INSTANCE_ID # Wait for instance to stop aws ec2 wait instance-stopped --instance-ids $INSTANCE_ID # Start the instance aws ec2 start-instances --instance-ids $INSTANCE_ID # Wait for instance to be running again aws ec2 wait instance-running --instance-ids $INSTANCE_ID # Get new public IP NEW_IP=$(aws ec2 describe-instances \ --instance-ids $INSTANCE_ID \ --query 'Reservations[0].Instances[0].PublicIpAddress' \ --output text) echo "New public IP after start: $NEW_IP"
To maintain a consistent public IP across stop-start cycles:
Solution 1: Use Elastic IP
# Allocate new Elastic IP ALLOC_ID=$(aws ec2 allocate-address \ --domain vpc \ --query 'AllocationId' \ --output text) # Associate with your instance aws ec2 associate-address \ --instance-id $INSTANCE_ID \ --allocation-id $ALLOC_ID
Solution 2: Configure ENI with Static IP
# Create network interface with specific private IP ENI_ID=$(aws ec2 create-network-interface \ --subnet-id subnet-0123456789abcdef0 \ --private-ip-address 10.0.0.100 \ --query 'NetworkInterface.NetworkInterfaceId' \ --output text) # Attach to instance aws ec2 attach-network-interface \ --network-interface-id $ENI_ID \ --instance-id $INSTANCE_ID \ --device-index 1
If you're using the public IP directly in applications, consider switching to DNS names:
# Get public DNS name instead of IP PUBLIC_DNS=$(aws ec2 describe-instances \ --instance-ids $INSTANCE_ID \ --query 'Reservations[0].Instances[0].PublicDnsName' \ --output text) echo "Public DNS name: $PUBLIC_DNS"
This behavior affects several common workflows:
- CI/CD pipelines that reference instance IPs directly
- Firewall rules whitelisting specific IPs
- Database connection strings
- SSL certificates tied to specific IP addresses
Always design your infrastructure to handle IP changes gracefully, either through DNS, Elastic IPs, or connection pooling configurations.