A firewall controls network traffic entering, leaving, or passing through a system.
A simple way to think about a firewall is:
A firewall is a rule-based traffic guard.
It checks packets against rules and decides whether to allow, block, reject, forward, or log them.
INTERNET TRAFFIC ---> |--------------------------| ---> INTERNAL NETWORK
[IP:123.45.67.89] | | [Accepted IP: 123.45.67.89]
Port 80 HTTP | +----------------+ | Port 80 -> Allowed
| | FIREWALL | |
| | Rules Applied: | |
[IP: 98.76.54.32] | | - Allow HTTP | | [Rejected IP: 98.76.54.32]
Port 22 SSH | | - Block SSH | | Port 22 -> Blocked
| +----------------+ |
| |
|--------------------------|
Firewalls are used to:
- allow trusted traffic
- block unwanted traffic
- limit exposed services
- protect servers from scans and attacks
- restrict access by source IP
- log suspicious packets
- rate-limit abusive traffic
- forward traffic to another port or host
A firewall does not make a vulnerable service safe by itself, but it reduces what can reach that service.
A firewall rule usually answers these questions:
| Firewall Rule Component | Description |
|---|---|
| Direction | Is the traffic incoming, outgoing, or forwarded? |
| Protocol | Does the rule apply to TCP, UDP, ICMP, or all protocols? |
| Port | Which port(s) are affected (e.g., 22, 80, 443, 8080)? |
| Source | Which IP address or subnet is the traffic coming from? |
| Destination | Which IP address or subnet is the traffic going to? |
| Action | What should happen to matching traffic: allow, drop, reject, log, or forward? |
Example:
Allow incoming TCP traffic from anywhere to port 22.
This means SSH is reachable.
Another example:
Deny incoming TCP traffic from anywhere to port 80.
This means HTTP is blocked.
Firewalls commonly use these actions:
| Firewall Target | Description |
|---|---|
| ACCEPT | Allow the packet to pass. |
| DROP | Silently discard the packet without notifying the sender. |
| REJECT | Block the packet and send an error response to the sender. |
| LOG | Record information about the packet, then continue processing subsequent rules. |
| DNAT (Destination NAT) | Rewrite the packet's destination IP address and/or port. |
| SNAT (Source NAT) | Rewrite the packet's source IP address. |
| MASQUERADE | Dynamically rewrite the source IP address for NAT, commonly used for internet sharing when the external IP may change. |
DROP is quiet. The client may wait until timeout.
REJECT is explicit. The client receives a refusal.
Example difference:
| Action | Client Behavior |
|---|---|
| DROP | The packet is silently discarded. The client waits and eventually times out. |
| REJECT | The packet is blocked and an error response is sent. The client quickly receives a "connection refused" or "unreachable" message. |
Traffic direction matters.
| Traffic Direction | Description |
|---|---|
| Incoming traffic | Remote client → this machine |
| Outgoing traffic | This machine → remote server |
| Forwarded traffic | One network → this machine/router → another network |
Diagram:
Incoming:
Internet ---> Server
Outgoing:
Server ---> Internet
Forwarded:
LAN Client ---> Linux Router ---> Internet
Most host firewalls focus on incoming traffic.
Routers, gateways, and NAT systems also care heavily about forwarded traffic.
Many services listen on well-known ports.
| Port / Protocol | Service |
|---|---|
| 22/tcp | SSH |
| 53/tcp, 53/udp | DNS |
| 80/tcp | HTTP |
| 443/tcp | HTTPS |
| 25/tcp | SMTP |
| 3306/tcp | MySQL / MariaDB |
| 5432/tcp | PostgreSQL |
| 21/tcp | FTP (control connection) |
Check listening services with:
sudo ss -tulnpExample output:
Netid State Local Address:Port Peer Address:Port Process
tcp LISTEN 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1100,fd=3))
tcp LISTEN 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=2200,fd=6))
Interpretation:
- sshd is listening on TCP port 22.
- nginx is listening on TCP port 80.
- A firewall can decide whether remote clients can reach those ports.
Linux has several firewall management tools.
Common ones include:
- iptables
- nftables
- ufw
- firewalld
This note focuses on:
- iptables
- ufw
- firewalld
A simple comparison:
| Firewall Tool | Description |
|---|---|
| iptables | Low-level and powerful firewall framework; commonly found on older Linux systems. |
| ufw (Uncomplicated Firewall) | Simple and beginner-friendly firewall interface; commonly used on Ubuntu. |
| firewalld | Zone-based, dynamic firewall management tool; commonly used on Fedora, RHEL, CentOS, AlmaLinux, and Rocky Linux. |
Modern systems often use nftables underneath, even when administrators use higher-level tools such as firewalld or ufw.
Firewall mistakes can lock you out of a remote server.
Before changing firewall rules over SSH:
- allow SSH first
- know your current source IP
- use a temporary rollback plan
- keep a second session open
- avoid setting default deny before allowing SSH
- test carefully
A safe pattern is:
- Allow SSH from your trusted IP.
- Confirm the rule exists.
- Only then enable stricter defaults.
- Test with a new SSH session before closing the old one.
On remote servers, a bad firewall command can cause this:
- You block port 22.
- Your SSH session disconnects.
- You cannot reconnect.
- Recovery may require console, cloud rescue mode, or provider access.
iptables is a low-level firewall tool for managing packet filtering rules.
It uses tables, chains, and rules.
The most common table for basic filtering is:
filter
The default chains in the filter table are:
- INPUT
- FORWARD
- OUTPUT
Diagram:
Packet entering local machine
|
v
INPUT chain
|
v
local service, if allowed
Packet leaving local machine
|
v
OUTPUT chain
|
v
network
Packet passing through machine
|
v
FORWARD chain
|
v
another network
Use:
sudo iptables -LA more useful version includes numbers and numeric ports:
sudo iptables -L -n -v --line-numbersExample output:
Chain INPUT (policy ACCEPT)
num pkts bytes target prot opt in out source destination
1 1200 96K ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
2 5 420 DROP icmp -- * * 0.0.0.0/0 0.0.0.0/0 icmp echo-request
3 200 18K ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
4 20 1600 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Chain FORWARD (policy DROP)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- * * 192.168.1.0/24 192.168.1.0/24
2 0 0 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT)
num pkts bytes target prot opt in out source destination
Interpretation:
- INPUT policy is ACCEPT.
- Established connections are allowed.
- ICMP echo requests are dropped.
- SSH on port 22 is allowed.
- HTTP on port 80 is allowed.
- FORWARD policy is DROP.
- OUTPUT policy is ACCEPT.
Rule order matters.
iptables checks rules from top to bottom.
Packet arrives
|
v
Rule 1 match? yes -> action
|
no
v
Rule 2 match? yes -> action
|
no
v
Rule 3 match? yes -> action
|
no
v
Default policy
If a broad DROP rule appears before an ACCEPT rule, the later ACCEPT may never be reached.
Example bad order:
- DROP all traffic
- ACCEPT port 22
The SSH allow rule is useless because traffic was already dropped.
Allow incoming HTTP:
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPTMeaning:
| iptables Option | Description |
|---|---|
| -A INPUT | Append a rule to the INPUT chain. |
| -p tcp | Match TCP packets. |
| --dport 80 | Match packets with destination port 80. |
| -j ACCEPT | Jump to the ACCEPT target and allow matching packets. |
Allow SSH:
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPTBlock ping:
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROPFirst list with line numbers:
sudo iptables -L INPUT -n -v --line-numbersExample:
Chain INPUT (policy ACCEPT)
num target prot source destination
1 ACCEPT tcp 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
2 ACCEPT tcp 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Delete rule 2:
sudo iptables -D INPUT 2Interpretation:
- The second rule in the INPUT chain is removed.
- If that rule allowed HTTP, HTTP may now be blocked depending on other rules and policy.
iptables changes are usually runtime-only unless saved.
On Debian-based systems:
sudo iptables-save | sudo tee /etc/iptables/rules.v4You may need:
sudo apt install iptables-persistentOn older Red Hat-based systems:
sudo service iptables saveImportant:
If rules are not saved, they may disappear after reboot.
UFW stands for Uncomplicated Firewall.
It provides a simpler interface for common firewall tasks.
It is common on Ubuntu and beginner-friendly systems.
Check status:
sudo ufw status numberedExample output:
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] 1000:2000/tcp ALLOW IN 192.168.1.0/24
[ 5] 22/tcp ALLOW IN Anywhere (v6)
[ 6] 80/tcp ALLOW IN Anywhere (v6)
[ 7] 443/tcp ALLOW IN Anywhere (v6)
Interpretation:
- UFW is active.
- SSH, HTTP, and HTTPS are allowed from anywhere.
- Ports 1000 through 2000 are allowed only from 192.168.1.0/24.
- IPv6 versions of some rules also exist.
Allow SSH:
sudo ufw allow sshAllow port 22 explicitly:
sudo ufw allow 22/tcpAllow HTTP:
sudo ufw allow httpAllow HTTPS:
sudo ufw allow httpsDeny HTTP:
sudo ufw deny httpDelete a numbered rule:
sudo ufw status numbered
sudo ufw delete 2Enable UFW:
sudo ufw enableDisable UFW:
sudo ufw disableA common safe server policy is:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enableMeaning:
- Block unsolicited inbound traffic.
- Allow outbound traffic initiated by the server.
- Allow SSH so administrators can connect.
- Enable the firewall.
On a remote server, allow SSH before enabling UFW.
firewalld is a dynamic firewall manager commonly used on Fedora, RHEL, CentOS, AlmaLinux, and Rocky Linux.
It organizes rules into zones.
A zone represents a trust level.
Examples:
| Firewalld Zone | Description |
|---|---|
| public | For untrusted networks; only explicitly allowed services are accessible. |
| home | For home networks with a moderate level of trust. |
| work | For work networks with trusted devices and services. |
| internal | For internal trusted networks. |
| trusted | All network traffic is allowed. |
| drop | Incoming traffic is silently dropped. |
| block | Incoming traffic is rejected with an error response. |
Diagram:
eth0 connected to internet
|
v
public zone
|
v
allow ssh, http, https
eth1 connected to office LAN
|
v
internal zone
|
v
allow more trusted services
firewalld has two configurations:
- runtime active now, lost after reload or reboot
- permanent saved on disk, used after reload or reboot
Commands without --permanent usually affect runtime only.
Commands with --permanent save the rule, but the rule usually needs reload before it becomes active.
Common pattern:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reloadList active zone configuration:
sudo firewall-cmd --list-allExample output:
public (active)
target: default
interfaces: eth0
services: ssh dhcpv6-client http https
ports: 8080/tcp 9090/tcp
masquerade: no
forward-ports:
rich rules:
rule family="ipv4" source address="192.168.0.0/24" accept
rule family="ipv4" source address="10.0.0.0/8" port port="443" protocol="tcp" accept
Interpretation:
- The active zone is public.
- Interface eth0 is assigned to it.
- SSH, HTTP, and HTTPS are allowed.
- Custom ports 8080/tcp and 9090/tcp are allowed.
- There are rich rules for specific source networks.
Check zones:
sudo firewall-cmd --get-zones
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zonesAllow SSH permanently:
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reloadAllow a custom port:
sudo firewall-cmd --permanent --add-port=8443/tcp
sudo firewall-cmd --reloadRemove HTTP:
sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --reloadList again:
sudo firewall-cmd --list-allMove an interface to the internal zone:
sudo firewall-cmd --permanent --zone=internal --change-interface=eth1
sudo firewall-cmd --reload
sudo firewall-cmd --zone=internal --list-allCreate a custom zone:
sudo firewall-cmd --permanent --new-zone=web-admin
sudo firewall-cmd --permanent --zone=web-admin --add-service=https
sudo firewall-cmd --permanent --zone=web-admin --add-source=192.168.50.0/24
sudo firewall-cmd --reloadInterpretation:
- A new zone called web-admin is created.
- HTTPS is allowed in that zone.
- Only traffic from 192.168.50.0/24 is associated with it.
Rich rules allow more specific matching.
Allow HTTPS only from 10.0.0.0/8:
sudo firewall-cmd --permanent \
--add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" service name="https" accept'
sudo firewall-cmd --reloadList rich rules:
sudo firewall-cmd --list-rich-rulesExample output:
rule family="ipv4" source address="10.0.0.0/8" service name="https" accept
Interpretation:
Only clients from 10.0.0.0/8 match this HTTPS allow rule.
Use ufw:
- simple host firewall
- small servers
- desktops
- Ubuntu-style systems
Use firewalld:
- zone-based firewalling
- multiple interfaces
- enterprise distributions
- runtime and permanent rule management
Use iptables:
- low-level control
- legacy systems
- advanced packet filtering
- systems without a higher-level firewall manager
Rule of thumb:
- ufw is easiest.
- firewalld is better for zones.
- iptables is powerful but easier to misconfigure.
Allow remote administration through SSH while blocking web traffic on HTTP port 80.
Check current status:
sudo ufw status numberedAllow SSH:
sudo ufw allow 22/tcpDeny HTTP:
sudo ufw deny 80/tcpEnable UFW if not already enabled:
sudo ufw enablesudo ufw status numberedExample output:
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN Anywhere
[ 2] 80/tcp DENY IN Anywhere
From another machine:
ssh user@SERVER_IP
curl -I http://SERVER_IPExample SSH result:
user@SERVER_IP's password:
Example HTTP result:
curl: (7) Failed to connect to SERVER_IP port 80: Connection refused
or:
curl: (28) Connection timed out
Interpretation:
- SSH is allowed, so remote administration works.
- HTTP is blocked, so web traffic cannot reach port 80.
- A timeout usually suggests DROP-like behavior.
- Connection refused may mean no service is listening or the firewall rejected it.
Create a secure default host firewall posture.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enablesudo ufw status verboseExample output:
Status: active
Logging: on
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
Interpretation:
- Unsolicited inbound traffic is blocked.
- Outbound traffic from the server is allowed.
- SSH remains reachable.
- This is a common baseline for servers.
Prevent the system from replying to ping requests.
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROPsudo iptables -L INPUT -n -v --line-numbersExample output:
num pkts bytes target prot opt source destination
1 3 252 DROP icmp -- 0.0.0.0/0 0.0.0.0/0 icmp echo-request
From another host:
ping SERVER_IPExample output:
PING SERVER_IP 56(84) bytes of data.
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Interpretation:
- The server is not replying to ICMP echo requests.
- This can reduce casual network discovery.
- However, blocking all ICMP can also make troubleshooting harder.
List line numbers:
sudo iptables -L INPUT --line-numbersDelete the matching rule number:
sudo iptables -D INPUT 1Restrict access to a web service so only one trusted client can connect.
Allow HTTP from one IP:
sudo ufw allow from 192.168.1.50 to any port 80 proto tcpDeny other HTTP traffic:
sudo ufw deny 80/tcpsudo ufw status numberedExample output:
Status: active
To Action From
-- ------ ----
[ 1] 80/tcp ALLOW IN 192.168.1.50
[ 2] 80/tcp DENY IN Anywhere
From allowed host:
curl -I http://SERVER_IPExample output:
HTTP/1.1 200 OK
From blocked host:
curl -I http://SERVER_IPExample output:
curl: (28) Failed to connect: Connection timed out
Interpretation:
- The trusted IP can access HTTP.
- Other sources are blocked.
- This is useful for admin panels, staging sites, or private dashboards.
Avoid locking yourself out while changing firewall rules over SSH.
First, find your client IP from the server side:
echo "$SSH_CLIENT"Example output:
203.0.113.25 53244 22
Allow SSH from your IP:
sudo ufw allow from 203.0.113.25 to any port 22 proto tcpAllow fallback SSH generally if needed:
sudo ufw allow 22/tcpThen set defaults:
sudo ufw default deny incoming
sudo ufw default allow outgoingEnable:
sudo ufw enableOpen a new terminal and test a second SSH connection before closing the first.
Before risky changes, schedule a rollback:
echo "sudo ufw disable" | at now + 5 minutesIf the firewall works, cancel the job:
atq
atrm JOB_IDInterpretation:
- The rollback timer protects against accidental lockout.
- If you lose SSH access, UFW disables itself after 5 minutes.
- If everything works, cancel the rollback job.
Reduce SSH attack surface by allowing only known source addresses.
Allow trusted IP:
sudo ufw allow from 203.0.113.25 to any port 22 proto tcpDeny other SSH:
sudo ufw deny 22/tcpsudo ufw status numberedExample output:
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp ALLOW IN 203.0.113.25
[ 2] 22/tcp DENY IN Anywhere
Interpretation:
- Only 203.0.113.25 can connect to SSH.
- Other IP addresses are denied.
- This reduces brute-force exposure.
- Do not do this unless you know your trusted IP is stable.
- If your IP changes, you may lock yourself out.
Limit repeated connection attempts to reduce brute-force or abuse.
UFW has a simple built-in rate limit:
sudo ufw limit sshCheck:
sudo ufw status numberedExample output:
Status: active
To Action From
-- ------ ----
[ 1] 22/tcp LIMIT IN Anywhere
Interpretation:
- UFW allows SSH but rate-limits repeated connection attempts.
- This can help reduce brute-force attempts.
Limit new TCP connections to port 8080:
sudo iptables -A INPUT -p tcp --dport 8080 -m conntrack --ctstate NEW \
-m limit --limit 100/minute --limit-burst 20 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8080 -j DROPCheck:
sudo iptables -L INPUT -n -v --line-numbersExample output:
num pkts bytes target prot source destination
1 1000 60K ACCEPT tcp 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 ctstate NEW limit: avg 100/min burst 20
2 200 12K DROP tcp 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080
Interpretation:
- New connections to port 8080 are allowed up to the rate limit.
- Excess traffic is dropped.
- This can reduce simple connection floods, but it is not a full DDoS solution.
Record blocked packets for investigation.
Add a logging rule before a drop rule:
sudo iptables -A INPUT -m limit --limit 10/min --limit-burst 5 \
-j LOG --log-prefix "iptables denied: " --log-level 4
sudo iptables -A INPUT -j DROPOn many systems:
sudo journalctl -k | grep "iptables denied"or:
sudo dmesg | grep "iptables denied"Example log:
kernel: iptables denied: IN=eth0 OUT= MAC=... SRC=198.51.100.20 DST=203.0.113.10 LEN=60 PROTO=TCP SPT=51512 DPT=23
Interpretation:
- A packet from 198.51.100.20 tried to reach port 23.
- Port 23 is Telnet, which is usually unsafe.
- The packet was logged and then dropped.
- Always rate-limit firewall logging.
- Logging every dropped packet can flood logs and hurt performance.
Redirect traffic arriving on port 8080 to a service listening on port 80.
This redirects local incoming TCP port 8080 to port 80:
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80If testing from the same host, also use OUTPUT redirect:
sudo iptables -t nat -A OUTPUT -p tcp -o lo --dport 8080 -j REDIRECT --to-port 80sudo iptables -t nat -L -n -v --line-numbersExample output:
Chain PREROUTING (policy ACCEPT)
num pkts bytes target prot source destination
1 10 600 REDIRECT tcp 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 redir ports 80
Run a web server on port 80, then from another host:
curl -I http://SERVER_IP:8080Example output:
HTTP/1.1 200 OK
Interpretation:
- The client connects to port 8080.
- iptables redirects the connection to local port 80.
- The web server responds successfully.
Prevent the server from connecting to a known unwanted destination.
Block outgoing traffic to a specific IP:
sudo ufw deny out to 203.0.113.200sudo ufw status numberedExample output:
Status: active
To Action From
-- ------ ----
[ 1] 203.0.113.200 DENY OUT Anywhere
curl http://203.0.113.200Example output:
curl: (7) Failed to connect to 203.0.113.200 port 80
Interpretation:
- The local system is blocked from connecting to that IP.
- Outbound filtering can help prevent compromised systems from calling known malicious infrastructure.
Firewalls usually filter IP addresses, ports, protocols, and interfaces.
Blocking domains is more complicated because domain names can resolve to changing IP addresses.
For domain-based blocking, consider:
- DNS filtering
- proxy filtering
- application-layer controls
- regularly updated IP sets
Allow web traffic using firewalld.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reloadsudo firewall-cmd --list-allExample output:
public (active)
services: ssh http https
ports:
Interpretation:
- The public zone allows SSH, HTTP, and HTTPS.
- Web clients should be able to connect if services are listening.
Check listening services:
sudo ss -tulnp | grep -E ':80|:443'Allow a custom TCP port, such as 8443.
sudo firewall-cmd --permanent --add-port=8443/tcp
sudo firewall-cmd --reloadsudo firewall-cmd --list-portsExample output:
8443/tcp
Interpretation:
- TCP port 8443 is open in the active zone.
- A service still must be listening on that port for clients to connect.
Understand why a rule may disappear after reload.
sudo firewall-cmd --add-port=9090/tcpCheck:
sudo firewall-cmd --list-portsExample:
9090/tcp
Reload:
sudo firewall-cmd --reloadCheck again:
sudo firewall-cmd --list-portsExample:
No output.
Interpretation:
- The rule was runtime-only.
- It disappeared after reload.
- Use --permanent for persistent rules.
sudo firewall-cmd --permanent --add-port=9090/tcp
sudo firewall-cmd --reloadUse firewall tools to separate service problems from firewall problems.
A web service should be reachable, but clients cannot connect.
sudo systemctl status nginxExample:
Active: active (running)
sudo ss -tulnp | grep ':80'Example:
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=2200,fd=6))
Interpretation:
- nginx is running and listening on port 80.
- If remote clients cannot connect, firewall or network path may be the issue.
UFW:
sudo ufw status numberedfirewalld:
sudo firewall-cmd --list-alliptables:
sudo iptables -L INPUT -n -v --line-numbersStatus: active
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp DENY IN Anywhere
Interpretation:
- The service is running.
- The firewall blocks port 80.
- Allow HTTP or remove the deny rule.
sudo ufw allow 80/tcpUnderstand that firewall rules are only one part of connectivity.
- Is the service running?
- Is the service listening on the expected port?
- Is it listening on the correct address?
- Does the firewall allow the traffic?
- Is the cloud firewall/security group open?
- Is the client using the correct IP and port?
- Is routing correct?
- Is SELinux blocking the service?
Commands:
sudo systemctl status SERVICE
sudo ss -tulnp
ip addr
ip route
sudo ufw status numbered
sudo firewall-cmd --list-all
sudo iptables -L -n -vExample issue:
- Firewall allows port 80.
- Service listens only on 127.0.0.1:80.
- Remote clients still cannot connect.
Check:
sudo ss -tulnp | grep ':80'Output:
tcp LISTEN 0 511 127.0.0.1:80 0.0.0.0:* users:(("nginx",pid=2200,fd=6))
Interpretation:
- The service listens only on localhost.
- The firewall is not the main problem.
- Configure the service to listen on the external interface or 0.0.0.0 if appropriate.
When a connection fails:
- Identify source IP, destination IP, protocol, and port.
- Check whether the service is listening.
- Check local firewall rules.
- Check cloud or upstream firewall rules.
- Test from the client.
- Check logs and packet counters.
- Confirm rule order.
- Confirm persistence after reboot or reload.
Example:
| Field | Value |
|---|---|
| Client IP | 192.168.1.50 |
| Server IP | 192.168.1.10 |
| Protocol | TCP |
| Port | 443 |
| Direction | Incoming |
This prevents vague troubleshooting.
sudo ss -tulnp | grep ':443'If there is no listener, the firewall is not the only issue.
UFW:
sudo ufw status numberedfirewalld:
sudo firewall-cmd --list-alliptables:
sudo iptables -L INPUT -n -v --line-numbersiptables counters can show whether traffic is matching rules.
sudo iptables -L INPUT -n -v --line-numbersExample:
num pkts bytes target prot source destination
1 0 0 ACCEPT tcp 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
2 150 9K DROP all 0.0.0.0/0 0.0.0.0/0
Interpretation:
- The HTTPS allow rule has 0 packet matches.
- The traffic may not be reaching this host, or another firewall is blocking it earlier.
Use:
curl -I http://SERVER_IP
nc -vz SERVER_IP 22
nc -vz SERVER_IP 443Example:
Connection to SERVER_IP 22 port [tcp/ssh] succeeded!
Interpretation:
- The TCP connection to port 22 succeeded.
- The service is reachable from this client.
Check listening services:
sudo ss -tulnpiptables:
sudo iptables -L -n -v --line-numbers
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -D INPUT RULE_NUMBER
sudo iptables-saveUFW:
sudo ufw status numbered
sudo ufw status verbose
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw deny 80/tcp
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable
sudo ufw delete RULE_NUMBERfirewalld:
sudo firewall-cmd --list-all
sudo firewall-cmd --get-zones
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --remove-service=http
sudo firewall-cmd --permanent --add-port=8443/tcp
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rulesTesting:
curl -I http://SERVER_IP
nc -vz SERVER_IP PORT
ping SERVER_IP
traceroute SERVER_IPLogs:
sudo journalctl -k
sudo dmesg
sudo journalctl -u firewalld
sudo tail -f /var/log/ufw.logIf you added temporary iptables rules, list them first:
sudo iptables -L INPUT -n -v --line-numbersDelete only the test rules by number:
sudo iptables -D INPUT RULE_NUMBERFor UFW, list and delete numbered rules:
sudo ufw status numbered
sudo ufw delete RULE_NUMBERFor firewalld test ports:
sudo firewall-cmd --permanent --remove-port=8443/tcp
sudo firewall-cmd --permanent --remove-port=9090/tcp
sudo firewall-cmd --reloadIf you created a custom firewalld zone:
sudo firewall-cmd --permanent --delete-zone=web-admin
sudo firewall-cmd --reload- Configure the firewall to allow SSH on port 22 but block HTTP on port 80. Test both from another machine.
- Set the default policy to deny incoming traffic and allow outgoing traffic. Explain why SSH must be allowed before enabling this policy remotely.
- Block ICMP echo requests and confirm that another host cannot ping the machine. Then remove the rule and test again.
- Allow HTTP only from a specific IP address. Test from the allowed IP and from a blocked IP.
- Create a safe rollback plan before changing firewall rules on a remote server.
- Restrict SSH to a trusted source IP. Explain the risk if your source IP changes.
- Rate-limit SSH or another TCP service and explain what kind of abuse this helps reduce.
- Add logging for dropped packets with rate limiting. Review logs and interpret one dropped packet entry.
- Forward local port 8080 to port 80 and verify that traffic to 8080 reaches the web service.
- Block outgoing traffic to a specific IP address and test the result with
curlornc. - With firewalld, add a runtime-only port rule, reload firewalld, and observe that the rule disappears.
- With firewalld, create a permanent custom port rule and verify it survives reload.
- Diagnose a service that is running but unreachable. Check the service, listening port, firewall rules, and client test output.
- Compare the same rule implemented with
iptables,ufw, andfirewalld. - Write a short firewall troubleshooting report including source IP, destination IP, protocol, port, rule checked, test command, output, and interpretation.