Ever try to setup iptables in a redundant configuration? That’s exactly what I recently set out to accomplish and after a few bumps, figured out a nice clean way to accomplish it. Granted, I don’t yet have a way to do state failover but for my environment that wasn’t a concern. That being said, this was accomplished using iptables and keepalived. I did not use ipvs. I just built two iptables systems and installed keepalived. vrrp is done on the inside interface. Pretty easy other than a few gotchas. Here are some issues I ran into and how I got over them.

  • Limited IP addresses on the outside interface
    To get over this issue, I installed both firewalls without an outside IP. I turned all used addresses into virtual interfaces in the config. This way the firewall is not addressable if it’s not active. Until it claims an address it stays quiet.
  • Keepalived uses gratuitous ARP
    This was unfortunate. I use comcast business for my connection and their router does not support gratuitous ARP. It would keep the old MAC address after a failover. There are ways to get around this using aliased interfaces (look up ip link add link on google) but my way to get around this was much simpler. My firewalls are virtual machines and VMware lets you adjust MAC addresses. Therefore I gave the same MAC address to both machine’s external interfaces. To the internet it will look no different than business as usual.
  • Routes are not configured on failover
    Because I do not have an IP bound upon failover, the result is that the IP fails over but the routing table is wrong. To get over this I used a notify script as part of the config. You just put a line like line “notify_master /opt/script/masterrouteupdate” in your vrrp_instance configuration directive for the internal interface and in that file, I put:
    /sbin/route del -net default gw
    /sbin/route add -net netmask eth2
    /sbin/route add -net default gw
    Of course you’ll want to modify to fit your needs! (Some IPs modified to protect the innocent.) Note that you see I have it deleting a default rule – this is because I have two scripts, a master update and a backup update. The backup adds an internal route to the other firewall so when it reverts and pulls back inside it acts just like an inside host – mangeable, updatable, all that fun.
  • Services bound externally don’t pickup
    Some services running on the machine that bind to the external interface did not pickup on the IP change. For those, I had to add kill -HUP to the script to reread their configs and the machine setup. Problem solved.

And thus, my config is born:

global_defs {
notification_email {
smtp_connect_timeout 60
router_id stigr

vrrp_instance VI_INT {
interface eth0
state MASTER
virtual_router_id 151
priority 101
virtual_ipaddress { dev eth4 dev eth5 dev eth5

  notify_master /path/to/master_active
notify_backup /path/to/backup_active

The end configuration is a very fast failover that allows me to manage both systems internally but save on resources externally. It’s not flawless as I said – no state failover – but the end result is admirable.

Note: Some may wonder why I didn’t use the virtual_routes directive. Well honestly, because I found it to not work and it didn’t give me the flexibility to have an alternate backup route – something I needed for system updates.