When working with KVM/QEMU virtualization on CentOS 7, many developers switch from firewalld to iptables for network management. A common frustration occurs when carefully configured iptables rules mysteriously disappear after reboot, replaced by unexpected default rules.
The issue typically manifests when:
# After configuration
iptables -L
# Shows correct rules
# After reboot
iptables -L
# Shows unexpected default rules instead
The extra rules appearing after reboot usually come from libvirtd or other services that modify iptables during their startup process.
Here's the definitive approach to solve this problem:
1. Proper Service Configuration
# Stop and disable firewalld
systemctl stop firewalld
systemctl mask firewalld
# Install and enable iptables-service
yum install iptables-services -y
systemctl enable iptables
systemctl start iptables
2. Rules Management Best Practices
Instead of directly modifying rules, use these commands:
# Clear existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
# Add your custom rules
iptables -t nat -A POSTROUTING -o enp6s0 -j MASQUERADE
iptables -A FORWARD -i enp6s0 -o virbr0 -j ACCEPT
# Save rules properly
service iptables save
# Or alternatively
/usr/libexec/iptables/iptables.init save
3. Critical Configuration File
Ensure /etc/sysconfig/iptables-config
contains:
IPTABLES_SAVE_ON_STOP="yes"
IPTABLES_SAVE_ON_RESTART="yes"
If you're still seeing unexpected rules, libvirtd might be the culprit. Try:
# Edit libvirtd configuration
vi /etc/libvirt/libvirtd.conf
# Add or modify these lines:
clear_emulator_capabilities = 0
iptables = 0
For systems where nothing else works, create a systemd service to enforce rules:
# Create service file
cat < /etc/systemd/system/iptables-persistent.service
[Unit]
Description=Apply persistent iptables rules
After=network.target
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/sysconfig/iptables
[Install]
WantedBy=multi-user.target
EOF
# Enable and start the service
systemctl daemon-reload
systemctl enable iptables-persistent
systemctl start iptables-persistent
After implementing any solution, verify with:
# Check current rules
iptables -L -n -v
iptables -t nat -L -n -v
# Check service status
systemctl status iptables
# Check boot sequence
ls -l /etc/systemd/system/multi-user.target.wants/iptables.service
When working with KVM virtualization on CentOS 7, many administrators encounter a frustrating scenario where carefully configured iptables rules disappear after system reboot. The problem manifests specifically when:
- Transitioning from firewalld to iptables-service
- Setting up NAT rules for KVM guest networking
- Rules appear to save correctly but don't persist through reboots
First, let's verify all critical components are properly configured:
# Check installed packages
rpm -q iptables-services
# Verify service status
systemctl status iptables
systemctl is-enabled iptables
The key insight is that simply enabling the service isn't enough. We need to ensure proper boot sequence handling:
# Correct service management sequence
systemctl stop firewalld
systemctl mask firewalld
systemctl enable iptables --now
CentOS 7 handles iptables persistence differently than previous versions. The proper save/restore procedure is:
# Save current rules (both methods work)
iptables-save > /etc/sysconfig/iptables
/usr/libexec/iptables/iptables.init save
# Verify the rules file contains correct NAT entries
cat /etc/sysconfig/iptables | grep MASQUERADE
Many administrators miss that libvirtd modifies iptables rules dynamically. To prevent this interference:
# Edit libvirtd configuration
vim /etc/libvirt/libvirtd.conf
# Add or modify these parameters:
iptables = 0
ebtables = 0
# Then restart services
systemctl restart libvirtd
systemctl restart iptables
Here's the complete, production-tested solution:
#!/bin/bash
# Permanent fix for iptables persistence on CentOS 7 with KVM
# Stop and disable firewalld
systemctl stop firewalld
systemctl mask firewalld
# Install and enable iptables
yum install -y iptables-services
systemctl enable iptables --now
# Configure libvirtd to not touch iptables
sed -i 's/#iptables =/iptables = 0/' /etc/libvirt/libvirtd.conf
sed -i 's/#ebtables =/ebtables = 0/' /etc/libvirt/libvirtd.conf
# Set up our rules
iptables -F
iptables -t nat -F
iptables -t nat -A POSTROUTING -o enp6s0 -j MASQUERADE
iptables -A FORWARD -i enp6s0 -o virbr0 -j ACCEPT
# Save rules persistently
/usr/libexec/iptables/iptables.init save
# Restart services
systemctl restart libvirtd
systemctl restart iptables
After implementing the solution, verify with:
# Check current rules
iptables -L -n -v
iptables -t nat -L -n -v
# Test persistence
reboot
iptables -L -n -v
- Verify /etc/sysconfig/iptables permissions (should be 600)
- Check systemd journal for errors: journalctl -u iptables
- Confirm no other services are modifying rules (like docker)
- Test with SELinux in permissive mode if issues persist