We used the command provided above to set the default From
IP address on outbound connections to the floating IP address:
iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to-source <ANCHORIP>
where <ANCHOR_IP> should be replaced by your actual anchor IP address. The anchor
IP address can be obtained with the following command (which hangs if you have
already executed the command above!)
/usr/bin/curl -s http://169.254.169.254/metadata/v1/interfaces/public/0/anchor_ipv4/address
However, we then ran into the Digital Ocean block on SMTP connections
originating from a floating IP address. This wasted days of our time!
We eventually solved this by adding an extra rule to the POSTROUTING
table as follows:
iptables -t nat -A POSTROUTING -p tcp --dport 587 -o eth0 -j SNAT --to-source <FIXEDIP>
where <FIXEDIP> is the fixed IP address of your droplet (as appears in
your droplet list in the Digital Ocean web management interface).
This iptables command says to make SMTP a special case and to use the droplet’s
fixed IP address as a From address for outbound SMTP connections.
You have to issue the commands in the correct order so that the special case
SMTP rule ends up BEFORE the catchall rule in the resulting POSTROUTING rule
chain. So do them in this order:
iptables -t nat -A POSTROUTING -p tcp --dport 587 -o eth0 -j SNAT --to-source <FIXEDIP>
iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to-source <ANCHORIP>
If you are engineering a general solution, put in a rule for each port that
is commonly used for SMTP:
# Assumes the POSTROUTING chain is empty at this point.
iptables -t nat -A POSTROUTING -p tcp --dport 25 -o eth0 -j SNAT --to-source <FIXEDIP>
iptables -t nat -A POSTROUTING -p tcp --dport 465 -o eth0 -j SNAT --to-source <FIXEDIP>
iptables -t nat -A POSTROUTING -p tcp --dport 587 -o eth0 -j SNAT --to-source <FIXEDIP>
iptables -t nat -A POSTROUTING -p tcp --dport 2525 -o eth0 -j SNAT --to-source <FIXEDIP>
iptables -t nat -A POSTROUTING -p tcp --dport 2526 -o eth0 -j SNAT --to-source <FIXEDIP>
iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to-source <ANCHORIP>
If all goes well, you will end up with a POSTROUTING chain that looks like this:
[root@www1 ~]# iptables -t nat --list
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT tcp -- anywhere anywhere multiport dports smtp,urd,submission,ms-v-worlds,ema-sent-lm /* 455 Use fixed IP for SMTP outbound */ to:<FIXEDIP>
SNAT tcp -- anywhere anywhere /* 456 Use floating IP for outbound */ to:<ANCHORIP>
[root@www1 ~]#
Reminder: You can delete the first entry in a chain like this:
iptables -t nat -D POSTROUTING 1
Reminder: If you want your new iptables to survive a reboot,
save it using a command something like this:
/sbin/service iptables save
If you are coding all this in Puppet, the following might be helpful:
firewall { '455 Use fixed IP for SMTP outbound':
table => 'nat', # -t nat
chain => 'POSTROUTING', # -A POSTROUTING
proto => 'tcp', # -p tcp
dport => [25,465,587,2525,2526], # --dport 587 (etc)
outiface => 'eth0', # -o eth0
jump => 'SNAT', # -j SNAT
tosource => $fixed_ip_address, # --to-source $fixed_ip_address
# It seems like a good idea to ensure that the rule to allow established
# connections to continue unharmed is implemented before we monkey around
# with anything else. Perhaps this 'require' isn't needed, but I've
# included it to be on the safe side.
#
require => Firewall['002 accept related established rules'],
}
firewall { '456 Use floating IP for outbound':
table => 'nat', # -t nat
chain => 'POSTROUTING', # -A POSTROUTING
proto => 'tcp', # -p tcp
outiface => 'eth0', # -o eth0
jump => 'SNAT', # -j SNAT
tosource => $anchor_ip_address, # --to-source $anchor_ip_address
# It is essential that the firewall rule to allow all established
# connections to continue unharmed is implemented before the floating
# IP address is made the default for all outbound traffic because if
# you don't do this, it seems that existing connections suddenly
# switch to the floating IP address mid-session! Apart from anything else,
# this causes all SSH sessions to the node to fail, which causes
# any manual Puppet SSH session to be terminated!
#
require => Firewall['002 accept related established rules'],
}
I hope this saves someone some time!
Ross Williams
good question - I’m also curious about whether this is possible for a HA setup I have in mind ..
(I have already been told that floating IP’s can’t have PTR records or forward SMTP traffic so I’m a bit concerned whether they are ‘fit for purpose’ ..)
@animaexos After struggling with this, I achieved it using iptables.
Run this command from your server to retrieve anchor IP address
Then run this command to redirect all outgoing traffic to your floating ip.
To build on what @marcoscvp90 said, in PF the same rule would be:
port is optional if you want to nat all traffic through the floating ip.
Hello,
How would the rule in iptables be for me to work with ping packages?
I tried with iptables -t nat -A POSTROUTING -p icmp -o eth0 -j SNAT –to-source <ANCHORIP> but it does not work. The shared IP continues to appear and not the floating.
Thanks.