When migrating from Rackspace to AWS, many developers encounter the "bind: cannot assign requested address" error when trying to run network services. This specific issue with freegeoip highlights a fundamental difference between traditional hosting and AWS's elastic network architecture.
The error occurs because AWS instances have specific networking requirements:
# This will fail if the IP isn't properly assigned to the instance
$GOPATH/bin/freegeoip -addr="192.0.2.1:8080"
Unlike Rackspace where you can bind to any available IP, AWS requires:
- The IP must be assigned to the instance's network interface
- Security groups must allow inbound traffic
- Network ACLs must permit the traffic
Here are three working approaches:
1. Bind to All Interfaces
The simplest solution is to bind to all available interfaces:
# Works on any interface including localhost
$GOPATH/bin/freegeoip -addr="0.0.0.0:8080"
2. Use Elastic IP Properly
If you must use a specific IP:
# First, associate the Elastic IP to your instance
aws ec2 associate-address --instance-id i-1234567890abcdef0 --public-ip 192.0.2.1
# Then verify it's attached to an interface
ip addr show
3. Check Security Configurations
Ensure proper security group rules:
# Example AWS CLI command to add inbound rule
aws ec2 authorize-security-group-ingress \
--group-id sg-903004f8 \
--protocol tcp \
--port 8080 \
--cidr 0.0.0.0/0
When the error persists:
- Verify interface assignment:
ip addr show
- Check port availability:
netstat -tulnp | grep 8080
- Test binding with Python:
python3 -c "import socket; s = socket.socket(); s.bind(('0.0.0.0', 8080))"
For production deployments:
# Run as service with systemd
[Unit]
Description=FreeGeoIP Service
After=network.target
[Service]
ExecStart=/home/ubuntu/bin/freegeoip -addr="0.0.0.0:8080"
User=ubuntu
Restart=always
[Install]
WantedBy=multi-user.target
After migrating from Rackspace to AWS, I encountered a frustrating networking issue while deploying the freegeoip service. While the same configuration worked perfectly on Rackspace's Ubuntu servers, AWS instances (both Red Hat and Ubuntu) threw this error:
listen tcp <MY IP ADDRESS>:8080: bind: cannot assign requested address
The error occurs when the application tries to bind to a specific IP address that isn't available on the machine. In AWS environments, this typically happens because:
- The specified IP isn't assigned to any network interface
- The IP belongs to an Elastic IP not associated with the instance
- Security group or NACL restrictions
First check your instance's network interfaces:
ifconfig -a
# Or for newer systems:
ip addr show
Also verify your Elastic IP assignment in AWS console or via CLI:
aws ec2 describe-addresses --public-ips <YOUR_IP>
Here are three approaches that worked in different AWS scenarios:
Solution 1: Bind to All Interfaces
Modify the freegeoip command to listen on all available interfaces:
$GOPATH/bin/freegeoip -addr="0.0.0.0:8080"
Solution 2: Use Instance Metadata
Get the actual private IP programmatically:
LOCAL_IP=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)
$GOPATH/bin/freegeoip -addr="${LOCAL_IP}:8080"
Solution 3: Proper Elastic IP Binding
If you must use a specific public IP:
# First ensure proper NAT configuration
sudo iptables -t nat -A PREROUTING -d <ELASTIC_IP> -j DNAT --to-destination <PRIVATE_IP>
sudo iptables -A FORWARD -d <PRIVATE_IP> -j ACCEPT
# Then bind to the private IP
$GOPATH/bin/freegeoip -addr="<PRIVATE_IP>:8080"
Remember that AWS networking has some special behaviors:
- Elastic IPs aren't directly bound to instances
- VPC networking uses NAT for public IPs
- Security groups must allow inbound traffic
Always verify your security group rules:
aws ec2 describe-security-groups --group-ids <YOUR_GROUP_ID>
For production deployments, consider running in a container with proper port mapping:
docker run -p 8080:8080 fiorix/freegeoip -http ":8080"
Or using systemd for better service management:
[Unit]
Description=FreeGeoIP Service
After=network.target
[Service]
ExecStart=/home/ubuntu/bin/freegeoip -http ":8080"
User=ubuntu
Restart=always
[Install]
WantedBy=multi-user.target