Claude
Skills
Sign in
Back

firewall

Included with Lifetime
$97 forever

Linux firewall configuration skill: UFW (Uncomplicated Firewall), iptables, nftables fundamentals, and fail2ban intrusion prevention. USE WHEN: - Setting up UFW on a new server (default deny-in, allow-out, selective port opens) - Configuring rate limiting and per-IP connection limits with UFW or iptables - Installing and tuning fail2ban for SSH, Nginx, and custom application jails - Writing iptables NAT rules (MASQUERADE for WireGuard/VPN, DNAT for port forwarding) - Diagnosing lockouts, fail2ban false positives, or blocked legitimate traffic - Setting up cloud security groups as the first layer of defence DO NOT USE FOR: - Application-level authentication / authorisation (use authentication skill) - SSL/TLS certificate management (use ssl-tls skill) - Kubernetes NetworkPolicy rules (use kubernetes skill) - WAF (Web Application Firewall) rules — Nginx rate limiting covers basic cases

Cloud & DevOps

What this skill does


# Firewall Configuration — UFW, iptables, nftables, fail2ban

## Defence-in-Depth Model

A production server should have **at least two layers**:

1. **Cloud security group** — controls traffic at the hypervisor/VPC level; blocks reach the host NIC. Cheapest filter; stateful by default. Configure this first.
2. **Host-based firewall** (UFW / iptables / nftables) — applied by the kernel; catches port scans, limits rate of connections, enforces policy if security group is misconfigured.
3. **fail2ban** — bans IP addresses that show malicious behaviour patterns (too many auth failures, suspicious request patterns) by inserting iptables rules.

---

## UFW — Full Server Lockdown Sequence

Run this sequence on a fresh server before exposing it to the internet. **Keep your current SSH session open while testing — UFW changes take effect immediately.**

```bash
# 1. Install UFW (usually pre-installed on Ubuntu)
sudo apt-get install -y ufw

# 2. Set default policies — deny all inbound, allow all outbound
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 3. Allow SSH BEFORE enabling UFW (otherwise you lock yourself out)
sudo ufw allow 22/tcp comment 'SSH'
# Or limit SSH to your own IP range:
sudo ufw allow from 203.0.113.0/24 to any port 22 proto tcp comment 'SSH from office'

# 4. Allow web traffic
sudo ufw allow 80/tcp  comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'

# 5. Allow other application ports as needed
sudo ufw allow 5432/tcp comment 'PostgreSQL — app subnet only'
# Better: restrict by source IP
sudo ufw allow from 10.0.1.0/24 to any port 5432 proto tcp comment 'PostgreSQL internal'

# 6. Enable UFW (prompts for confirmation)
sudo ufw enable

# 7. Verify status
sudo ufw status verbose
sudo ufw status numbered   # Shows rule numbers for easier deletion
```

---

## UFW Common Operations

```bash
# Remove a rule by number (get numbers from 'ufw status numbered')
sudo ufw delete 5

# Remove a rule by specification (exact match)
sudo ufw delete allow 80/tcp

# Rate-limit a port (UFW built-in: block IPs that connect > 6 times in 30s)
sudo ufw limit 22/tcp comment 'Rate-limit SSH brute force'

# Allow by named service (reads /etc/services)
sudo ufw allow smtp
sudo ufw allow 'Nginx Full'    # Application profile from /etc/ufw/applications.d/

# List available application profiles
sudo ufw app list
sudo ufw app info 'Nginx Full'

# Logging levels: off, low, medium, high, full
sudo ufw logging medium

# Reload (re-read rules without disabling)
sudo ufw reload

# Disable UFW completely
sudo ufw disable

# Reset to defaults (removes all rules)
sudo ufw reset

# Check UFW log
tail -f /var/log/ufw.log
journalctl -k | grep UFW
```

---

## iptables Fundamentals

UFW is a frontend to iptables. For advanced use cases (NAT, custom chains), work directly with iptables.

### Chains and Tables

| Table | Chains | Purpose |
|---|---|---|
| `filter` (default) | INPUT, FORWARD, OUTPUT | Accept / drop / reject packets |
| `nat` | PREROUTING, POSTROUTING, OUTPUT | Address and port translation |
| `mangle` | All five chains | Modify packet headers (TTL, QoS marks) |
| `raw` | PREROUTING, OUTPUT | Bypass connection tracking |

### Common iptables Commands

```bash
# List all rules with line numbers and counters
sudo iptables -L -n -v --line-numbers
sudo iptables -t nat -L -n -v          # NAT table

# Allow established/related connections (essential — add before deny rules)
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT                    # Allow loopback

# Allow specific port
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Block a specific IP
sudo iptables -I INPUT -s 192.0.2.100 -j DROP

# Reject with ICMP (polite; informs sender)
sudo iptables -A INPUT -p tcp --dport 25 -j REJECT --reject-with tcp-reset

# Limit connection rate (SYN flood protection)
sudo iptables -A INPUT -p tcp --syn --dport 80 \
    -m connlimit --connlimit-above 20 -j REJECT

# Save rules persistently (package: iptables-persistent)
sudo apt-get install -y iptables-persistent
sudo netfilter-persistent save       # Saves to /etc/iptables/rules.v4 and rules.v6

# Restore saved rules
sudo netfilter-persistent reload

# Flush all rules (dangerous — default policy must be ACCEPT first)
sudo iptables -P INPUT ACCEPT
sudo iptables -F
sudo iptables -X
```

### NAT — MASQUERADE (WireGuard / VPN Gateway)

```bash
# Enable IP forwarding (also set in sysctl.d)
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/50-ip-forward.conf
sudo sysctl -p /etc/sysctl.d/50-ip-forward.conf

# Masquerade VPN traffic going out via eth0
# (wg0 = WireGuard interface; eth0 = public internet interface)
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

# Allow forwarded traffic from VPN
sudo iptables -A FORWARD -i wg0 -j ACCEPT
sudo iptables -A FORWARD -o wg0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

sudo netfilter-persistent save
```

### NAT — DNAT (Port Forwarding)

```bash
# Forward external :8080 to internal host 10.0.1.10:80
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 \
    -j DNAT --to-destination 10.0.1.10:80
sudo iptables -A FORWARD -p tcp -d 10.0.1.10 --dport 80 \
    -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
```

---

## nftables Basics

nftables is the successor to iptables (used by default on Debian 11+ and Ubuntu 22.04+). UFW still uses iptables-legacy by default on Ubuntu.

```bash
# Check if nftables is in use
sudo nft list ruleset

# Basic nftables configuration file: /etc/nftables.conf
cat > /etc/nftables.conf <<'NFTABLES'
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;

        iif lo accept comment "Allow loopback"
        ct state established,related accept comment "Allow established connections"
        ct state invalid drop comment "Drop invalid packets"

        tcp dport 22 accept comment "SSH"
        tcp dport { 80, 443 } accept comment "HTTP/HTTPS"

        # ICMP (allow ping)
        ip  protocol icmp   icmp type echo-request accept
        ip6 nexthdr  icmpv6 accept

        log prefix "nft-drop: " flags all counter drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}
NFTABLES

sudo systemctl enable --now nftables
sudo nft -f /etc/nftables.conf   # Apply immediately
```

---

## fail2ban — Complete Configuration

### Install

```bash
sudo apt-get install -y fail2ban
# Copy default config so updates don't overwrite your changes
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
```

### /etc/fail2ban/jail.local — Full Example

```ini
[DEFAULT]
# Global defaults (inherited by all jails unless overridden)
bantime   = 1h            # How long to ban (increase to 24h or 7d for repeat offenders)
findtime  = 10m           # Window in which maxretry failures trigger a ban
maxretry  = 5             # Number of failures before ban
ignoreip  = 127.0.0.1/8 ::1 10.0.0.0/8 203.0.113.0/24
            # ^ Whitelist: loopback, private network, office IP range
banaction = iptables-multiport
banaction_allports = iptables-allports
action    = %(action_mwl)s  # Ban + log + send email with whois/log context
# For email (requires mailutils): set destemail and sender
destemail = [email protected]
sender    = [email protected]
mta       = sendmail

# --- SSH -------------------------------------------------------------------
[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = %(sshd_log)s
backend  = %(sshd_backend)s
maxretry = 3
bantime  = 24h

# --- Nginx: too many requests (from rate-limit log entries) ----------------
[nginx-req-limit]
enabled  = true
filter   = nginx-req-limit
port     = http,https
logpath  = /var/log/nginx/myapp.error.log
maxretry = 10
findtime = 1m
bantime  = 1h

# --- Nginx: authentication failures --------------

Related in Cloud & DevOps