August 14, 2026
Hands-On UFW Firewall on Ubuntu 24.04: Testing Network Ports with Kali Linux and Nmap
Building a small virtual security lab to understand how firewall rules affect network connectivity.

By Tanya Bhardwaj
5 min read
Introduction
When learning cybersecurity, it is easy to understand a command without really understanding what changes when you run it.
I wanted to approach networking differently.
Instead of only reading about firewalls and network ports, I built a small virtual lab where I could create a service, scan it from another machine, apply a firewall rule, and then scan it again.
For this experiment, I used Ubuntu 24.04.4 LTS as the system being protected and Kali Linux 2024.4 as the testing machine. I used UFW (Uncomplicated Firewall) to manage the firewall and Nmap to observe the network from Kali.
The experiment followed a simple process:
Create a service → scan it → enable the firewall → scan again → allow the port → verify the change.
The goal was not simply to learn UFW commands, but to actually observe how firewall configuration changes what another machine can see.
Lab Environment
The lab consisted of two virtual machines running in VMware Workstation Pro:
- Ubuntu 24.04.4 LTS — target/protected machine
- Kali Linux 2024.4 — testing machine
- UFW — firewall management
- Nmap — network scanning
- Python 3 HTTP server — temporary test service
- TCP port 8000 — controlled test port
Both virtual machines were connected to the same virtual network, allowing Kali to communicate with Ubuntu.
1. Verifying the Ubuntu Environment
Before starting the experiment, I verified the Ubuntu version.
I opened a terminal and ran:
lsb_release -alsb_release -aThe output confirmed that I was working with Ubuntu 24.04.4 LTS, with the codename Noble.
2. Checking the Existing Network State
Before changing anything, I wanted to understand what network sockets were already listening on Ubuntu.
I used:
ss -tulnss -tulnThe command displayed the TCP and UDP sockets currently listening on the system.
The output included several locally bound services, including DNS- and printing-related sockets.
I also checked the initial UFW status:
sudo ufw status verbosesudo ufw status verboseAt this point, UFW was inactive.
This gave me a useful baseline before introducing my own test service.
3. Performing a Baseline Nmap Scan
Next, I switched to Kali Linux and performed a basic scan against the Ubuntu VM.
I used:
nmap <UBUNTU-IP>nmap <UBUNTU-IP>Nmap scanned its default set of 1,000 TCP ports.
The Ubuntu host was reachable, but the scanned TCP ports were reported as closed.
This established the initial network state before I created a specific service for the firewall experiment.
4. Creating a Controlled Test Service
The initial scan did not give me an open TCP service that I could conveniently use for the firewall demonstration.
Rather than changing an existing system service, I decided to create a temporary service specifically for the experiment.
On Ubuntu, I started Python's built-in HTTP server:
python3 -m http.server 8000 --bind 0.0.0.0python3 -m http.server 8000 --bind 0.0.0.0The server started listening on TCP port 8000.
I then returned to Kali and scanned that specific port:
nmap -p 8000 <UBUNTU-IP>nmap -p 8000 <UBUNTU-IP>The result showed:
8000/tcp open8000/tcp open
This gave me a controlled starting point for testing the firewall.
5. Configuring UFW
After confirming that port 8000 was reachable, I configured UFW on Ubuntu.
First, I set the default incoming policy to deny:
sudo ufw default deny incomingsudo ufw default deny incomingThen I allowed outgoing traffic:
sudo ufw default allow outgoingsudo ufw default allow outgoingFinally, I enabled UFW:
sudo ufw enablesudo ufw enableUbuntu confirmed that the firewall was active and enabled on system startup.
I then checked the configuration:
sudo ufw status verbosesudo ufw status verboseThe important part of the output was:
Status: active
Default: deny (incoming), allow (outgoing)Status: active
Default: deny (incoming), allow (outgoing)
This configuration creates a restrictive baseline where incoming connections require an explicit firewall rule to be permitted.
6. Testing the Effect of the Firewall
I started the Python HTTP server again in a separate Ubuntu terminal:
python3 -m http.server 8000 --bind 0.0.0.0python3 -m http.server 8000 --bind 0.0.0.0I left the server running and returned to Kali.
I then performed the same scan:
nmap -p 8000 <UBUNTU-IP>nmap -p 8000 <UBUNTU-IP>This time, the result changed to:
8000/tcp filtered8000/tcp filtered
This was the key observation in the experiment.
The Python service was still running, but the firewall was now affecting how the port could be reached from Kali.
Before UFW:
8000/tcp open8000/tcp openAfter enabling UFW with incoming connections denied:
8000/tcp filtered8000/tcp filteredSeeing this change through an actual Nmap scan made the firewall behaviour much easier to understand.
7. Creating an Explicit UFW Allow Rule
Next, I wanted to demonstrate the opposite situation.
Instead of relying only on the default-deny policy, I explicitly allowed TCP port 8000.
On Ubuntu, I ran:
sudo ufw allow 8000/tcpsudo ufw allow 8000/tcpI then verified the firewall configuration:
sudo ufw status verbosesudo ufw status verboseThe output showed the new rule allowing port 8000.
This demonstrates an important firewall concept: a default-deny policy does not mean that every service has to remain inaccessible. Specific traffic can be allowed through explicit rules.
8. Verifying the Firewall Rule with Nmap
Finally, I returned to Kali and performed the same scan once more:
nmap -p 8000 <UBUNTU-IP>nmap -p 8000 <UBUNTU-IP>This time, Nmap reported:
8000/tcp open8000/tcp open
The complete experiment now had a clear progression:
This was the result I wanted to observe.
9. What I Learned From the Experiment
This small lab helped me connect several networking and security concepts.
A firewall controls traffic, not the existence of a service
The Python server continued to run as a listening service. UFW affected whether incoming network traffic from Kali could reach it.
Nmap provides an external perspective
Checking the Ubuntu configuration locally tells me what the system believes is happening. Scanning it from Kali gave me another perspective: what another machine could actually observe across the network.
Default-deny is a useful security principle
Using:
sudo ufw default deny incomingsudo ufw default deny incomingcreates a restrictive baseline where incoming connections require deliberate permission.
Firewall rules should be verified
It isn't enough to run:
sudo ufw allow 8000/tcpsudo ufw allow 8000/tcpand assume that everything worked.
I verified the rule with UFW and then tested the result externally using Nmap.
That combination of configuration + verification was one of the most useful lessons from this experiment.
10. Cleaning Up the Lab
Because the Python HTTP server was created specifically for this experiment, I stopped it after completing the tests.
I used:
Ctrl + CCtrl + CI also removed the temporary firewall rule:
sudo ufw delete allow 8000/tcpsudo ufw delete allow 8000/tcpFinally, I checked the firewall configuration again:
sudo ufw status verbosesudo ufw status verboseThis left the Ubuntu VM in a cleaner state while keeping UFW enabled.
Conclusion
This experiment changed the way I think about firewall configuration.
Instead of simply learning that UFW can allow or deny traffic, I was able to see the effect of those rules from another machine.
The experiment followed a simple cycle:
Create → Scan → Configure → Scan → Allow → Verify.
Starting with an accessible service on port 8000, I could see Nmap report the port as open. After applying a default-deny incoming policy with UFW, the same port became filtered. After explicitly allowing TCP port 8000, it became open again.
For me, this reinforced an important lesson in cybersecurity:
Don't just learn what a security tool does. Build a controlled environment, change one thing, and observe what actually happens.
This lab is also a starting point for future experiments involving network enumeration, firewall configuration, vulnerable machines, and defensive security testing.