Amazon EC2 supports Elastic IP Addresses to implement the effect of having a static IP address for public servers running on EC2. You can point the Elastic IP at any of your EC2 instances, changing the active instance at any time, without changing the IP address seen by the public outside of EC2.
This is a valuable feature for things like web and email servers, especially if you need to replace a failing server or upgrade or downgrade the hardware capabilities of the server, but read on for an insiders’ secret way to use Elastic IP addresses for non-public servers.
Not all servers should be publicly accessible. For example, you may have an internal EC2 instance which hosts your database server accessed by other application instances inside EC2. You want to architect your installation so that you can replace the database server (instance failure, resizing, etc) but you want to make it easy to get all your application servers to start using the new instance.
There are a number of design approaches which people have used to accomplish this, including:
Hard code the internal IP address into the applications and modify it whenever the internal server changes to a new instance (ugh and ouch).
Run your own DNS server (or use an external DNS service) and change the IP address of the internal hostname to the new internal IP address (extra work and potentially extra failover time waiting for DNS propagation).
Store the internal IP address in something like SimpleDB and change it when you want to point to a new EC2 instance (extra work and requires extra coding for clients to keep checking the SimpleDB mapping)
The following approach is the one I use and is the topic of the rest of this article:
Assign an Elastic IP to the internal instance and use the external Elastic IP DNS name. To switch servers, simply re-assign the Elastic IP to a new EC2 instance
This last option uses a little-known feature of the Elastic IP Address system as implemented by Amazon EC2:
When an EC2 instance queries the external DNS name of an Elastic IP, the EC2 DNS server returns the internal IP address of the instance to which the Elastic IP address is currently assigned.
You may need to read that a couple times to grasp the implications as it is non-obvious that an “external” name will return an “internal” address.
$ ec2-allocate-address ADDRESS 18.104.22.168
The address returned at this point is the external Elastic IP address. You don’t want to use this external IP address directly for internal server access since you would be charged for network traffic.
The next step is to assign the Elastic IP address to an EC2 instance (which is going to be your internal server):
$ ec2-associate-address -i i-07612d6e 22.214.171.124 ADDRESS 126.96.36.199 i-07612d6e
Once the Elastic IP has been assigned to an instance, you can describe that instance to find the external DNS name (which will include the external Elastic IP address in it):
$ ec2-describe-instances i-07612d6e | egrep ^INSTANCE | cut -f4 ec2-75-101-137-243.compute-1.amazonaws.com
This is the permanent external DNS name for that Elastic IP address no matter how many times you change the instance to which it is assigned. If you query this DNS name from outside of EC2, it will resolve to the external IP address as shown above:
$ dig +short ec2-75-101-137-243.compute-1.amazonaws.com 188.8.131.52
However, if you query this DNS name from inside an EC2 instance, it will resolve to the internal IP address for the instance to which it is currently assigned:
$ dig +short ec2-75-101-137-243.compute-1.amazonaws.com 10.254.171.132
You can now use this external DNS name in your applications on EC2 instances to communicate with the server over the internal EC2 network and you won’t be charged for the network traffic as long as you’re in the same EC2 availability zone.
If you ever need to move the service to a new EC2 instance, simply reassign the Elastic IP address to the new EC2 instance:
$ ec2-associate-address -i i-3b783452 184.108.40.206 ADDRESS 220.127.116.11 i-3b783452
and the original external DNS name will immediately resolve to the internal IP address of the new instance:
$ dig +short ec2-75-101-137-243.compute-1.amazonaws.com 10.190.134.5
Existing connections will fail and new connections to the external DNS name will automatically be opened on the new instance, using either the public IP address or the private IP address depending on where the client is when requesting DNS resolution.
It is not entirely intuitive to have your application use names like
ec2-75-101-137-243.compute-1.amazonaws.com but you can make it clearer by creating a permanent entry in your DNS which points to that name with a CNAME alias. For example, using bind:
db.example.com. CNAME ec2-75-101-137-243.compute-1.amazonaws.com.
You can then use
db.example.com to refer to the server internally and still not have to update your DNS when you change instances.
Even though you are using an Elastic IP address, you don’t need (and often don’t want) to allow external users to be able to access your internal servers. For example, it is just asking for trouble to expose a MySQL server to the Internet. Keep the security groups tight so that the internal servers and services can only be accessed from your other EC2 instances.
Open TCP connections to the original server will not survive when the Elastic IP address is assigned to a new EC2 instance. Some applications and clients will automatically attempt to re-open a failed connection, getting through to the new server on the new internal IP address, but other applications may need to be kicked or signaled so they attempt a new connection to the server.
When using this approach, you need one Elastic IP address for each internal server which needs to be addressed. AWS accounts default to a limit of 5 Elastic IP addresses, but you can request an increased limit.
How do you solve the problem of connecting internal EC2 servers to each other?
Update 2009-07-20: Correct example host name.
Update 2012-03-06: Here’s the original forum post from Amazon that revealed this trick: Elastic internal IP address
Update 2012-04-02: Use different internal IP address for new instance example.