How to Add Custom iptables Rules Persistently Alongside UFW in Ubuntu


3 views

While UFW (Uncomplicated Firewall) provides an excellent abstraction layer for managing firewall rules, there are cases where you need direct iptables access for advanced configurations. UFW actually builds upon iptables, meaning your custom rules can coexist - if implemented correctly.

The key locations for persistent iptables rules in Ubuntu are:

/etc/ufw/before.rules  # Rules applied before UFW processes its rules
/etc/ufw/after.rules   # Rules applied after UFW's rules
/etc/ufw/user.rules    # Alternative for user-specific rules

Let's say we want to log all dropped packets (which UFW doesn't provide by default):

# Edit the after.rules file
sudo nano /etc/ufw/after.rules

# Add these lines before the COMMIT line:
-A ufw-after-logging-input -j LOG --log-prefix "[UFW DROP] " --log-level 4
-A ufw-after-logging-forward -j LOG --log-prefix "[UFW DROP] " --log-level 4

After adding your rules, you need to:

# Save the file and reload UFW
sudo ufw disable
sudo ufw enable

This ensures your rules persist across reboots since they're stored in UFW's configuration files.

Here's how to implement rate limiting for SSH connections (something UFW can't do natively):

# Add to /etc/ufw/before.rules
# SSH brute-force protection
-A ufw-before-input -p tcp --dport 22 -m state --state NEW -m recent --set
-A ufw-before-input -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

Always verify your rules after implementation:

# Check all active iptables rules
sudo iptables -L -n -v

# Get more detailed output including line numbers
sudo iptables -L -n -v --line-numbers
  • Always add comments to your custom rules for future reference
  • Test rules manually before making them persistent
  • Document changes in /etc/ufw/ufw.conf
  • Consider using ufw allow/deny commands where possible

While UFW (Uncomplicated Firewall) provides a user-friendly interface for iptables, it's intentionally designed to be simple - which means it can't handle every possible networking scenario. When you need complex rules beyond UFW's capabilities, you'll need to work directly with iptables.

The proper location for persistent iptables rules in Ubuntu is the /etc/iptables.rules file. However, we'll need to create a system service to load these rules at boot. Here's the complete process:

# First save your current rules (including UFW rules)
sudo iptables-save | sudo tee /etc/iptables.rules

# Create a new systemd service file
sudo nano /etc/systemd/system/iptables-restore.service

Paste this content into your service file:

[Unit]
Description=Restore iptables rules
After=network.target

[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables.rules

[Install]
WantedBy=multi-user.target

To ensure your custom rules play nicely with UFW, follow these steps:

# Enable and start the service
sudo systemctl enable iptables-restore.service
sudo systemctl start iptables-restore.service

# Check UFW status to confirm everything works
sudo ufw status

Let's say you need to rate-limit incoming SSH connections:

# Add this to /etc/iptables.rules before COMMIT
-A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j REJECT
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

After making changes, always verify your rules:

# Check current rules
sudo iptables -L -n -v

# Test the new rules functionality
# For our SSH example:
for i in {1..5}; do ssh localhost; done

Remember that:

  • UFW changes won't automatically update your custom rules file
  • After modifying UFW rules, resave your iptables configuration
  • Your custom rules won't appear in ufw status output