Updated: 12 October 2026 · Applies to: UFW 0.36.2, iptables 1.8.11 / nftables 1.1.6 (Ubuntu 26.04), systemd 257 and firewalld 2.4.3 (AlmaLinux 10.2), firewalld 1.3.4 (AlmaLinux 9), Windows Defender Firewall on Windows Server (commands from Microsoft’s documentation)
A port is open only while a program listens on it. To close a port, stop that program (sudo systemctl disable --now SERVICE) or make it listen on 127.0.0.1 only. To block a port that must stay in use, add a firewall rule: sudo ufw deny 3306/tcp on Ubuntu, remove the port from the firewalld zone on AlmaLinux, Rocky Linux or RHEL, or on Windows Server run New-NetFirewallRule -DisplayName "Block 3306" -Direction Inbound -Protocol TCP -LocalPort 3306 -Action Block.
Close or block?
- Close: nothing listens any more, so nobody can connect, from outside or from the server itself. Best when you do not need the service.
- Block: the program keeps running and the firewall stops outside traffic. Best when local programs or a few trusted addresses still need it, for example a database.
1. Find what listens on the port
$ sudo ss -ltnp 'sport = :8080'
State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0 5 127.0.0.1:8080 0.0.0.0:* users:(("python3",pid=160,fd=3))
sudo ss -ltnup lists every listening TCP and UDP port. An address of 0.0.0.0 or * means the port is reachable from other machines unless the firewall blocks it; 127.0.0.1 means only the server itself can connect. More in check open ports and find which process is using a port.
2. Close the port: stop the service
$ sudo systemctl disable --now demo-web Removed '/etc/systemd/system/multi-user.target.wants/demo-web.service'. $ sudo ss -ltnp 'sport = :8080' State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
(Lab output from our test system with a demo service.) --now stops it at once and disable keeps it from starting at boot; a plain systemctl stop lasts only until the next restart. If you still need the program locally, set it to listen on 127.0.0.1 in its own configuration instead, then restart it.
Socket units keep the port open. Some services are started by systemd when a connection arrives, and then systemd itself listens on the port. Stopping only the service warned:
$ sudo systemctl stop demo-sock.service Stopping 'demo-sock.service', but its triggering units are still active: demo-sock.socket
and ss still showed the port, now owned by systemd. sudo systemctl disable --now demo-sock.socket closed it. SSH works this way on Ubuntu 24.04 and 26.04 (ssh.socket), so never close your SSH port without another way in; see change the SSH port safely.
3. Free a port that is in use
When a program cannot start because something else holds its port, it fails with an error such as OSError: [Errno 98] Address already in use. Find and end the old process:
$ sudo fuser -v 8080/tcp
USER PID ACCESS COMMAND
8080/tcp: root 222 F.... python3
$ sudo fuser -k 8080/tcp
8080/tcp: 222
fuser is in the package psmisc. Without it, use lsof:
$ sudo lsof -nP -i :8080 -sTCP:LISTEN COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME python3 3527 root 3u IPv4 9753969 0t0 TCP 127.0.0.1:8080 (LISTEN) $ sudo kill $(lsof -t -i :8080 -sTCP:LISTEN)
If the process belongs to a service, stop the service with systemctl instead (step 2); a service with Restart=always comes straight back after a kill. To end processes safely in general, see find and kill processes.
4. Close a port you opened in the firewall
UFW (Ubuntu and Debian): delete the allow rule with the same words you used to add it:
$ sudo ufw delete allow 8080/tcp Rule deleted Rule deleted (v6)
Deleting by number (sudo ufw status numbered, then sudo ufw delete 2) removes only that one line. In our test it removed the IPv4 rule and left 8080/tcp (v6) open, so check sudo ufw status afterwards and delete the (v6) line too.
firewalld (AlmaLinux, Rocky Linux and RHEL): remove the port or service from the zone. A zone with the default target rejects everything it does not list (according to the firewalld manual), so this closes it:
$ sudo firewall-cmd --permanent --remove-port=8080/tcp success $ sudo firewall-cmd --reload success $ sudo firewall-cmd --list-ports $ sudo firewall-cmd --list-services cockpit dhcpv6-client ssh
That last line is the default on AlmaLinux 10.2. If you do not use the Cockpit web console, sudo firewall-cmd --permanent --remove-service=cockpit and a reload close port 9090 too. Opening works the same way in reverse: open a port on RHEL, AlmaLinux and Rocky Linux.
5. Block a port that stays in use
Deny (drop) and reject both block; the difference is what the other side sees. In our test from a second machine with nc -zv -w 5 SERVER 3306, deny ended in port 3306 (tcp) timed out, while reject answered failed: Connection refused at once. Drop is the usual choice for internet traffic; reject is friendlier for your own networks and outgoing rules.
UFW:
sudo ufw deny 3306/tcp # block incoming TCP 3306 sudo ufw reject 3306/tcp # or: refuse it sudo ufw deny out 25/tcp # block outgoing SMTP from this server sudo ufw insert 1 allow from 203.0.113.10 to any port 3306 proto tcp
UFW checks rules from the top and the first match wins, so the insert 1 rule lets one address in while others stay blocked. UFW adds the same rule for IPv6 when IPV6=yes in /etc/default/ufw. More in set up the UFW firewall on Ubuntu.
firewalld, to block a port for one network while it stays open for others:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.0/24" port port="3306" protocol="tcp" reject' sudo firewall-cmd --reload
Plain iptables or nftables, only on a server without UFW or firewalld: sudo iptables -I INPUT -p tcp --dport 3306 -j DROP. These rules are lost on reboot unless you save them (iptables-persistent and sudo netfilter-persistent save on Debian and Ubuntu). With nftables, the rule is tcp dport 3306 drop in an input chain of /etc/nftables.conf.
Docker: according to Docker’s documentation, ports published with -p bypass the chains UFW uses, so a UFW deny rule does not block them. Publish such ports on 127.0.0.1 only (-p 127.0.0.1:3306:3306) or add rules to the DOCKER-USER chain.
Windows Server
According to Microsoft’s documentation, in PowerShell as administrator:
- Find the process on a port:
Get-NetTCPConnection -LocalPort 8080 -State Listen | Select-Object LocalAddress, LocalPort, OwningProcess, or in a command promptnetstat -ano | findstr :8080(the last column is the process ID). - Close it:
Stop-Process -Id 1234(ortaskkill /pid 1234 /f). For a Windows service,Stop-Service -Name SERVICENAMEand thenSet-Service -Name SERVICENAME -StartupType Disabledso it stays off after a restart. - Close a port you opened in the firewall:
Remove-NetFirewallRule -DisplayName "Allow 8080"(use the rule’s own display name). - Block it while the program runs:
New-NetFirewallRule -DisplayName "Block 3306 in" -Direction Inbound -Protocol TCP -LocalPort 3306 -Action Block New-NetFirewallRule -DisplayName "Block SMTP out" -Direction Outbound -Protocol TCP -RemotePort 25 -Action Block
Microsoft states that explicit block rules take precedence over conflicting allow rules, so on Windows you cannot block a port for everyone and then allow one address with a second rule: restrict the allow rule to that address with -RemoteAddress instead. See open a port in Windows Firewall.
Check the result and keep your access
Test from another machine, not from the server itself: nc -zv -w 5 SERVER_IP 3306 (test ports with nc). Never close or block the port you manage the server with (SSH 22 or your custom SSH port, RDP 3389) without another way in, and keep the VPS console or IPMI ready in case you lock yourself out.
Official documentation: firewalld.zone, Windows Firewall rules, Get-NetTCPConnection and Docker packet filtering and firewalls.
Ucartz services for this topic
- KVM VPS hosting: NVMe SSD and full root access, with Free Basic Managed Support.
- Unmanaged dedicated servers: full root access and free IPMI KVM, with Free Basic Managed Support.
- Linux server management: hardening, patching, monitoring and automation for Ubuntu, Debian, RHEL and AlmaLinux.
