Table of Contents
-
Understanding Redundant Firewalls & iptables
- 1.1 What is iptables?
- 1.2 Why Redundancy Matters
- 1.3 Redundancy Architectures: Active-Passive vs. Active-Active
-
Prerequisites & Architecture Design
- 2.1 Hardware/Software Requirements
- 2.2 Network Topology
-
Step 1: Setting Up the Base Firewalls
- 3.1 Installing Linux & iptables
- 3.2 Configuring Network Interfaces
- 3.3 Basic iptables Rule Setup
-
Step 2: Ensuring Rule Consistency with Sync
- 4.1 Manual Rule Sync (iptables-save/restore)
- 4.2 Automated Sync with Configuration Management
-
Step 3: Implementing Failover with Keepalived (VRRP)
- 5.1 What is VRRP?
- 5.2 Installing Keepalived
- 5.3 Configuring Keepalived for Active-Passive Failover
- 5.4 Health Checks for Firewall Availability
-
Step 4: Testing the Redundant Setup
- 6.1 Simulating a Firewall Failure
- 6.2 Verifying Traffic Flow & Rule Enforcement
- 6.3 Testing Stateful Connection Continuity
-
Advanced: Active-Active & State Sync with conntrackd
- 7.1 Active-Active Architecture
- 7.2 Syncing Connection States with conntrackd
1. Understanding Redundant Firewalls & iptables
1.1 What is iptables?
iptables is a user-space utility for configuring Linux kernel firewall rules. It filters traffic based on predefined rules (e.g., allow/deny traffic from a specific IP, port, or protocol) and operates at the network layer (Layer 3) and transport layer (Layer 4) of the OSI model. Key features include:
- Stateful inspection: Tracks active connections (e.g.,
ESTABLISHED,NEWstates) to allow return traffic. - Chain-based structure: Rules are organized into chains (
INPUT,OUTPUT,FORWARD) and tables (filter,nat,mangle). - Flexibility: Supports custom rules, logging, and integration with other tools (e.g.,
ipsetfor IP list management).
1.2 Why Redundancy Matters
A single firewall is a SPOF. Redundancy ensures:
- High Availability (HA): Traffic continues flowing if one firewall fails (e.g., hardware failure, network outage).
- Business Continuity: Critical services (e.g., web servers, databases) remain accessible to users and clients.
- Security Resilience: A failed firewall won’t expose the network to unfiltered traffic during downtime.
1.3 Redundancy Architectures
Two common redundancy models exist:
Active-Passive (Default for Simplicity)
- Active Firewall: Handles all traffic and holds a “virtual IP” (VIP) that clients use to route traffic.
- Passive Firewall: Idle until the active firewall fails, then takes over the VIP and traffic.
- Pros: Simple to configure; minimal complexity.
- Cons: Underutilizes the passive firewall’s resources.
Active-Active
- Both firewalls handle traffic simultaneously (e.g., via load balancing).
- Pros: Better resource utilization; higher throughput.
- Cons: Complex (requires syncing stateful connections and load balancing).
We’ll focus on active-passive first (easier to implement) and touch on active-active later.
2. Prerequisites & Architecture Design
2.1 Hardware/Software Requirements
- Two Linux Servers: Physical or virtual (e.g., Ubuntu 22.04 LTS, CentOS Stream 9).
- Minimum specs: 2 CPU cores, 2GB RAM, 20GB storage.
- Two network interfaces (NICs) per server:
eth0/enp0s3: WAN (internet-facing).eth1/enp0s8: LAN (internal network-facing).
- Network Switches: For connecting WAN/LAN to firewalls (use redundant switches to avoid switch SPOF).
- Software:
iptables(preinstalled on most Linux distros).iptables-persistent(to save rules across reboots).Keepalived(for VRRP-based failover).conntrackd(optional, for syncing stateful connections in active-active setups).
2.2 Network Topology

Diagram: Active-Passive Firewall Topology
- Clients (e.g., workstations, servers) route traffic to a VIP (e.g.,
192.168.1.1). - The active firewall owns the VIP and forwards traffic between WAN (
10.0.0.0/24) and LAN (192.168.1.0/24). - Firewalls are connected to WAN/LAN switches; switches connect to upstream routers (WAN) and internal servers (LAN).
3. Step 1: Setting Up the Base Firewalls
3.1 Installing Linux & iptables
- Install a Linux distro (e.g., Ubuntu) on both firewalls. Name them
fw-activeandfw-passive. - Update packages and install required tools:
# On Ubuntu/Debian sudo apt update && sudo apt install -y iptables iptables-persistent keepalived # On CentOS/RHEL sudo dnf install -y iptables iptables-services keepalived sudo systemctl enable --now iptables # Persist rules
3.2 Configuring Network Interfaces
Assign static IPs to each firewall’s NICs. Replace X with 1 for fw-active and 2 for fw-passive:
WAN Interface (eth0)
fw-active:10.0.0.X/24(e.g.,10.0.0.1/24).fw-passive:10.0.0.X/24(e.g.,10.0.0.2/24).- Gateway:
10.0.0.254(upstream router IP).
LAN Interface (eth1)
fw-active:192.168.1.X/24(e.g.,192.168.1.10/24).fw-passive:192.168.1.X/24(e.g.,192.168.1.11/24).
Example Netplan Config (Ubuntu):
Create /etc/netplan/01-netcfg.yaml on both firewalls:
network:
version: 2
renderer: networkd
ethernets:
eth0: # WAN
addresses: [10.0.0.1/24] # Use 10.0.0.2 for fw-passive
gateway4: 10.0.0.254
nameservers:
addresses: [8.8.8.8, 8.8.4.4]
eth1: # LAN
addresses: [192.168.1.10/24] # Use 192.168.1.11 for fw-passive
Apply with: sudo netplan apply.
3.3 Basic iptables Rule Setup
Define a baseline iptables policy to allow essential traffic (e.g., SSH, HTTP/HTTPS) and block everything else. Apply the same rules to both firewalls to ensure consistency post-failover.
Step 1: Flush Existing Rules
sudo iptables -F # Flush all chains
sudo iptables -X # Delete custom chains
sudo iptables -t nat -F # Flush nat table
Step 2: Set Default Policies
Deny all incoming/forwarded traffic by default; allow outgoing:
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
Step 3: Allow Essential Traffic
# Allow loopback (localhost) traffic
sudo iptables -A INPUT -i lo -j ACCEPT
# Allow SSH (adjust port if using non-default, e.g., 2222)
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Allow established/related connections (stateful inspection)
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# Forward HTTP/HTTPS traffic from LAN to WAN (adjust ports as needed)
sudo iptables -A FORWARD -i eth1 -o eth0 -p tcp --dport 80 -j ACCEPT
sudo iptables -A FORWARD -i eth1 -o eth0 -p tcp --dport 443 -j ACCEPT
sudo iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
# Enable NAT (MASQUERADE) for LAN clients to access WAN
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
Step 4: Save Rules
Persist rules across reboots:
# Ubuntu/Debian
sudo netfilter-persistent save # Uses iptables-persistent
# CentOS/RHEL
sudo service iptables save
4. Step 2: Ensuring Rule Consistency with Sync
For redundancy to work, both firewalls must have identical iptables rules. If rules differ, failover could expose the network to unfiltered traffic.
4.1 Manual Rule Sync (For Small Setups)
Use iptables-save and iptables-restore to copy rules from fw-active to fw-passive:
# On fw-active: Save rules to a file
sudo iptables-save > /tmp/iptables.rules
# Copy to fw-passive (replace 192.168.1.11 with passive IP)
scp /tmp/iptables.rules [email protected]:/tmp/
# On fw-passive: Restore rules
sudo iptables-restore < /tmp/iptables.rules
sudo netfilter-persistent save # Persist
4.2 Automated Sync with Configuration Management
For large environments, use tools like Ansible or Puppet to enforce rule consistency:
Ansible Example
Create a playbook (sync-iptables.yml) to push rules to both firewalls:
- name: Sync iptables rules to firewalls
hosts: firewalls # Define in /etc/ansible/hosts
tasks:
- name: Copy iptables rules file
copy:
src: /path/to/iptables.rules # Centralized rule file
dest: /tmp/iptables.rules
mode: '0644'
- name: Restore iptables rules
command: iptables-restore < /tmp/iptables.rules
- name: Persist rules
command: netfilter-persistent save # Ubuntu/Debian
# For CentOS/RHEL: command: service iptables save
Run with: ansible-playbook sync-iptables.yml.
5. Step 3: Implementing Failover with Keepalived (VRRP)
To automate failover, we use Keepalived, which implements the Virtual Router Redundancy Protocol (VRRP). VRRP lets multiple routers (firewalls) share a VIP; the “master” (active) holds the VIP, and the “backup” (passive) takes over if the master fails.
5.1 What is VRRP?
- VIP: A shared IP (e.g.,
192.168.1.1) that clients use to route traffic. - Virtual Router ID (VRID): A unique ID (1-255) for the VRRP group (must match on both firewalls).
- Priority: Determines the master (higher priority wins; default: 100 for master, 90 for backup).
5.2 Installing Keepalived
Already installed in Step 3.1. Enable and start the service:
sudo systemctl enable --now keepalived
5.3 Configuring Keepalived for Active-Passive Failover
On fw-active (Master)
Edit /etc/keepalived/keepalived.conf:
vrrp_instance VI_1 {
state MASTER # This is the active firewall
interface eth1 # LAN interface (where VIP lives)
virtual_router_id 51 # Unique VRID (1-255)
priority 100 # Higher than backup (90)
advert_int 1 # VRRP heartbeat interval (1s)
# Authentication (prevents rogue VRRP routers)
authentication {
auth_type PASS
auth_pass securepassword123 # Same on both firewalls
}
# Virtual IP (VIP) to float between firewalls
virtual_ipaddress {
192.168.1.1/24 dev eth1 # VIP on LAN interface
}
# Health check: Restart Keepalived if iptables fails
track_script {
check_iptables
}
}
# Custom health check script
vrrp_script check_iptables {
script "/usr/local/bin/check-iptables.sh" # Path to script
interval 2 # Check every 2s
weight -20 # Reduce priority by 20 if check fails (triggers failover)
}
On fw-passive (Backup)
Edit /etc/keepalived/keepalived.conf (only differences from master are state and priority):
vrrp_instance VI_1 {
state BACKUP # Passive until master fails
interface eth1
virtual_router_id 51 # Same as master
priority 90 # Lower than master (100)
advert_int 1
authentication {
auth_type PASS
auth_pass securepassword123 # Same as master
}
virtual_ipaddress {
192.168.1.1/24 dev eth1
}
track_script {
check_iptables
}
}
vrrp_script check_iptables {
script "/usr/local/bin/check-iptables.sh"
interval 2
weight -20
}
5.4 Health Check Script
The check-iptables.sh script ensures the firewall is healthy (e.g., iptables rules are loaded, interfaces are up). Create it on both firewalls:
sudo nano /usr/local/bin/check-iptables.sh
Add:
#!/bin/bash
# Check if iptables rules are loaded (e.g., count > 0)
if ! iptables -L | grep -q "Chain INPUT"; then
exit 1 # Fail: No rules loaded
fi
# Check if LAN interface (eth1) is up
if ! ip link show eth1 | grep -q "UP"; then
exit 1 # Fail: Interface down
fi
exit 0 # Success: Firewall is healthy
Make executable:
sudo chmod +x /usr/local/bin/check-iptables.sh
5.5 Restart Keepalived
Apply the config on both firewalls:
sudo systemctl restart keepalived
sudo systemctl enable keepalived # Start on boot
6. Step 4: Testing the Setup
Verify failover works by simulating a failure and checking if the VIP floats to the passive firewall.
6.1 Verify Initial State
On fw-active, confirm it holds the VIP:
ip addr show eth1 # Look for "inet 192.168.1.1/24"
On fw-passive, the VIP should not appear on eth1.
6.2 Simulate Active Firewall Failure
Shut down fw-active or disconnect its LAN interface:
sudo poweroff # Or: sudo ip link set eth1 down
6.3 Verify Failover
On fw-passive, check if the VIP is now present:
ip addr show eth1 # Should show "inet 192.168.1.1/24"
From a LAN client, test connectivity to the internet (e.g., ping 8.8.8.8). Traffic should flow through fw-passive.
6.4 Test Rule Enforcement
On fw-passive, verify iptables rules are active:
sudo iptables -L # Rules should match fw-active’s
Attempt to access a blocked port (e.g., telnet 192.168.1.1 23). The connection should fail, confirming rules are enforced.
7. Advanced: Active-Active & State Sync with conntrackd
For active-active setups, use conntrackd to sync iptables’ connection tracking (conntrack) tables between firewalls. This ensures stateful connections (e.g., ongoing SSH sessions) aren’t dropped during failover.
7.1 Install conntrackd
sudo apt install -y conntrackd # Ubuntu/Debian
# CentOS/RHEL: sudo dnf install -y conntrackd
7.2 Configure conntrackd
Edit /etc/conntrackd/conntrackd.conf on both firewalls. Example for active-active sync:
SyncMode FTFW # Full sync (Forward Track Forward)
UDPInterface {
Address 192.168.1.10 # Local firewall’s LAN IP
Port 3780
OtherAddress 192.168.1.11 # Peer firewall’s LAN IP
}
General {
Nice 0
HashSize 32768
HashLimit 131072
}
Start conntrackd:
sudo systemctl enable --now conntrackd
8. Security Best Practices
- Harden Firewalls: Disable unused services (e.g.,
telnet), restrict SSH access (useAllowUsersinsshd_config), and enableufw/firewalldas a secondary layer. - Limit VRRP Access: Use
iptablesto block VRRP traffic from untrusted networks (VRRP uses IP protocol 112):sudo iptables -A INPUT -p vrrp -s 192.168.1.10,192.168.1.11 -j ACCEPT # Allow only peers sudo iptables -A INPUT -p vrrp -j DROP # Block others - Audit Rules: Regularly review iptables rules with
iptables -L -vto remove unnecessary entries. - Monitor Logs: Use
rsyslogto centralize logs (e.g.,/var/log/iptables.log) and tools like ELK Stack for analysis.
9. Troubleshooting Common Issues
| Issue | Solution |
|---|---|
| VIP not floating | Check Keepalived logs: journalctl -u keepalived. Ensure VRID, auth pass, and interface match on both firewalls. |
| iptables rules not syncing | Verify Ansible/Puppet playbooks are running; check file permissions on iptables.rules. |
| Conntrackd sync failures | Ensure UDP port 3780 is open between firewalls; check conntrackd -s for sync status. |
| Traffic drops post-failover | Use conntrackd to sync connection states; test with long-lived sessions (e.g., scp transfers). |
10. Conclusion
Redundant firewalls with iptables and Keepalived provide a robust defense against downtime and security breaches. By following this guide, you’ve built an active-passive setup with automated failover, consistent rule enforcement, and stateful connection support.
Key takeaways:
- Sync Rules: Always ensure both firewalls have identical iptables rules.
- Test Failover: Regularly simulate failures to validate HA.
- Monitor: Use tools like Nagios or Prometheus to track firewall health and VRRP status.
With this architecture, your network will remain secure and available—even when hardware or software fails.