(01) UFW Basic Usage
This is the basis of UFW (Uncomplicated FireWall).
- Install UFW.
root@dlp:~# apt -y install ufw
- UFW is the frontend tool of nftables/iptables. On Debian 12, default backend of UFW is nftables.
root@dlp:~# update-alternatives --config iptables
There are 2 choices for the alternative iptables (providing /usr/sbin/iptables).
Selection Path Priority Status
------------------------------------------------------------
* 0 /usr/sbin/iptables-nft 20 auto mode
1 /usr/sbin/iptables-legacy 10 manual mode
2 /usr/sbin/iptables-nft 20 manual mode
Press <enter> to keep the current choice[*], or type selection number:
- To use UFW, it needs to run UFW service. Furthermore, even if service is running, UFW is disabled by default, so it needs to enable it manually.
root@dlp:~# systemctl enable --now ufw
Synchronizing state of ufw.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable ufw
root@dlp:~# systemctl status ufw
* ufw.service - Uncomplicated firewall
Loaded: loaded (/lib/systemd/system/ufw.service; enabled; preset: enabled)
Active: active (exited) since Wed 2023-07-12 18:50:17 CDT; 1min 23s ago
Docs: man:ufw(8)
Process: 1254 ExecStart=/lib/ufw/ufw-init start quiet (code=exited, status=>
Main PID: 1254 (code=exited, status=0/SUCCESS)
CPU: 775us
# current status
root@dlp:~# ufw status
Status: inactive
# enable ufw
root@dlp:~# ufw enable
Firewall is active and enabled on system startup
root@dlp:~# ufw status
Status: active
# disable ufw
root@dlp:~# ufw disable
Firewall stopped and disabled on system startup
- This is the basis to allow services or port by UFW.
# incoming connections are all denied by default
root@dlp:~# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
# for example, allow SSH
root@dlp:~# ufw allow ssh
Rule added
Rule added (v6)
# for example, allow HTTP
root@dlp:~# ufw allow http
Rule added
Rule added (v6)
# for example, allow 2049/tcp
root@dlp:~# ufw allow 2049/tcp
Rule added
Rule added (v6)
root@dlp:~# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
2049/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
2049/tcp (v6) ALLOW IN Anywhere (v6)
# * when running [ufw allow (service name)], the port set in [/etc/services] is allowed
- This is the basis to delete rules by UFW.
root@dlp:~# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
2049/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
2049/tcp (v6) ALLOW IN Anywhere (v6)
# for example, delete the SSH allowing rule
root@dlp:~# ufw delete allow ssh
Rule deleted
Rule deleted (v6)
# for example, delete the 80/tcp allowing rule
root@dlp:~# ufw delete allow 80/tcp
Rule deleted
Rule deleted (v6)
# show status with rule number
root@dlp:~# ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] 2049/tcp ALLOW IN Anywhere
[ 2] 2049/tcp (v6) ALLOW IN Anywhere (v6)
# delete a rule with specifying rule number
root@dlp:~# ufw delete 2
Deleting:
allow 2049/tcp
Proceed with operation (y|n)? y
Rule deleted (v6)
# to delete all rules and disable UFW, run like follows
root@dlp:~# ufw reset
Resetting all rules to installed defaults. Proceed with operation (y|n)? y
Backing up 'user.rules' to '/etc/ufw/user.rules.20230712_185512'
Backing up 'before.rules' to '/etc/ufw/before.rules.20230712_185512'
Backing up 'after.rules' to '/etc/ufw/after.rules.20230712_185512'
Backing up 'user6.rules' to '/etc/ufw/user6.rules.20230712_185512'
Backing up 'before6.rules' to '/etc/ufw/before6.rules.20230712_185512'
Backing up 'after6.rules' to '/etc/ufw/after6.rules.20230712_185512'
root@dlp:~# ufw status
Status: inactive
- This is the basis to allow services or ports with specific source or destination hosts.
# for example, allow SSH only from [10.0.0.215]
root@dlp:~# ufw allow from 10.0.0.215 to any port ssh
Rule added
# for example, allow [80/tcp] only from [10.0.0.215] to [10.0.0.30]
root@dlp:~# ufw allow from 10.0.0.215 to 10.0.0.30 port 80 proto tcp
Rule added
# for example, limit SSH from [10.0.0.220]
# * over 6 consecutive SSH trial within 30 seconds are denided
root@dlp:~# ufw limit from 10.0.0.220 to any port ssh
Rule added
root@dlp:~# ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN 10.0.0.215
10.0.0.30 80/tcp ALLOW IN 10.0.0.215
22/tcp LIMIT IN 10.0.0.220
# when using limit, following ruleset are configured
root@dlp:~# nft list ruleset | grep 'dport 22'
# Warning: table ip filter is managed by iptables-nft, do not touch!
ip saddr 10.0.0.215 tcp dport 22 counter packets 0 bytes 0 accept
# Warning: table ip6 filter is managed by iptables-nft, do not touch!
ip saddr 10.0.0.220 tcp dport 22 ct state new xt match recent counter packets 0 bytes 0
ip saddr 10.0.0.220 tcp dport 22 ct state new xt match recent counter packets 0 bytes 0 jump ufw-user-limit
ip saddr 10.0.0.220 tcp dport 22 counter packets 0 bytes 0 jump ufw-user-limit-accept
- To configure ICMP related settings, edit the configuration file below. Incoming connections are denied all by default but ICMP related connections are allowed.
root@dlp:~# vi /etc/ufw/before.rules
# ICMP related connections are allowed by the settings below
# if you'd like to deny them, simply comment out all like follows
# ok icmp codes for INPUT
# -A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT
# ok icmp code for FORWARD
# -A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
# -A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
# -A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
# -A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT
# reload settings
root@dlp:~# ufw reload
Firewall reloaded
# to allow [echo-request] from the specific IP address or network, set like follows
# * answer to Ping from remote hosts
root@dlp:~# vi /etc/ufw/before.rules
# for example, allow [echo-request] from [10.0.0.0/24]
# ok icmp codes for INPUT
# -A ufw-before-input -p icmp --icmp-type destination-unreachable -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type time-exceeded -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type parameter-problem -j ACCEPT
# -A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT
-A ufw-before-input -p icmp --icmp-type echo-request -s 10.0.0.0/24 -j ACCEPT
# ok icmp code for FORWARD
# -A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
# -A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
# -A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
# -A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT
root@dlp:~# ufw reload
Firewall reloaded