You installed a service, but the network is silent
You installed a web server or a database on Fedora. You start the service. You check the status, and it says active. You try to connect from another machine on the network, and the connection times out. You are staring at the terminal, wondering why the port is invisible. The service is running, but the network is silent. This is the moment you need to check open ports and active connections.
What is actually happening
A listening port is like a phone number. The process is the person answering the phone. The firewall is the receptionist who decides who gets through. If the process isn't running, no one answers. If the firewall blocks the call, the caller hears a busy signal or silence, even though the person is sitting there with the phone.
Fedora uses ss to show you the phone numbers and the people. It uses firewall-cmd to show you the receptionist's rules. You need to check all three layers to find the break. A service can be listening on localhost only, bound to the wrong interface, or blocked by a firewall zone. The symptom looks the same from the outside, but the fix is different for each case.
Check listening ports and processes
Here's how to list every process listening on a port, including the PID and process name. This command replaces netstat and reads directly from the kernel socket tables, making it faster and more accurate on modern Fedora systems.
# -t shows TCP, -u shows UDP, -l shows listening sockets, -p shows process info, -n skips DNS resolution for speed
sudo ss -tulpn
The output shows columns for Netid, State, Local Address:Port, and Process. Look for LISTEN in the State column. The Local Address:Port tells you where the service is bound. 0.0.0.0:80 means the service listens on all IPv4 interfaces. [::]:80 means it listens on all IPv6 interfaces. 127.0.0.1:80 means it only accepts connections from the local machine. If you see 127.0.0.1, remote connections will fail. The service is intentionally restricted to localhost.
The Process column shows the PID and name. If this column is empty, you likely ran the command without sudo. The kernel hides process details for sockets owned by other users. Run the command with sudo to see the full picture.
Run ss with sudo. Without root, you miss the process names and can't see ports owned by other users.
Filter connections by IP and state
Here's how to narrow the view to a specific port or IP address when the full list is too noisy. Filtering helps you isolate a single service or check the state of connections to a specific client.
# Filter for connections to a specific destination IP and port
ss -ant dst 192.168.1.50 sport = :80
The -a flag shows all sockets, not just listening ones. The -n flag keeps addresses numeric. The filter syntax uses dst for destination, src for source, sport for source port, and dport for destination port. You can combine filters with spaces. The = operator matches exactly.
Connection states matter. ESTAB means an active connection. TIME-WAIT means the connection closed recently and the kernel is waiting to reuse the port. CLOSE-WAIT means the remote side closed the connection, but the local process hasn't closed its end yet. A flood of CLOSE-WAIT sockets often indicates a bug in the application code that isn't closing sockets properly.
Filter early. A full dump of connections is noise. Narrow to the IP or port you care about.
Verify the firewall rules
Here's how to verify the firewall allows traffic to the port you just found. A service can be listening perfectly, but firewalld will drop packets if the port isn't allowed in the active zone.
# List all rules in the active zone to see allowed services and ports
sudo firewall-cmd --list-all
The output shows the target, interfaces, sources, services, and ports. Check the interfaces line to see which zone your network card is in. If your interface is in public, check the public zone rules. A port open in trusted does nothing if your interface is in public.
Use --query-port to check a specific port. This returns yes or no and is useful for scripts.
# Check if a specific port is allowed in the public zone
sudo firewall-cmd --zone=public --query-port=8080/tcp
If the port is missing, add it. Use --add-port for a temporary change that lasts until the next reload. Use --permanent --add-port to make the change survive reboots. Always reload the firewall after making permanent changes. The runtime configuration and the persistent configuration diverge until you reload.
# Add port permanently and reload the firewall to apply changes
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
Check the zone. A port open in trusted does nothing if your interface is in public.
Check SELinux denials
Here's how to check if SELinux is blocking the service from binding to a port or connecting to a backend. SELinux can prevent a service from listening on a non-standard port or from making outbound connections, even if the firewall allows the traffic.
# Search audit logs for recent AVC denials related to network operations
sudo ausearch -m avc -ts recent | grep -E "name_connect|name_bind"
The output shows type=AVC lines with denied and scontext/tcontext. The scontext is the process trying to act. The tcontext is the target. If you see name_bind denied, the service tried to open a port and SELinux said no. If you see name_connect denied, the service tried to connect outbound and SELinux blocked it.
Fedora logs SELinux denials with human-readable summaries in the journal. This is often faster than parsing raw audit logs.
# View SELinux denial summaries with explanation hints
sudo journalctl -t setroubleshoot
The summary tells you what happened and often suggests a fix, like enabling a boolean or fixing a file context. Do not disable SELinux to fix the issue. Fix the policy. Disabling SELinux removes a layer of security and hides the root cause.
Read the denial message. SELinux tells you exactly what was blocked and by which policy.
Verify the fix
Run ss -tulpn again. Look for the port in the output. Verify the address is 0.0.0.0 or [::] if you need remote access. Run firewall-cmd --list-all and confirm the port appears in the active zone. Check journalctl -t setroubleshoot for new denials.
Test from the client side. Use curl, nc, or the application itself to connect from a remote machine. A local ss check only proves the server is ready. It does not prove the network path is clear. If the connection succeeds, the fix is solid. If it fails, check the remote host's firewall and routing.
Test from the client side. A listening port means nothing if the client can't reach it.
Common pitfalls
Connection refused and Connection timed out are different errors. Connection refused means the packet reached the server, but no process is listening on that port. The server actively rejected the connection. Check ss -tulpn to see if the service is running and bound to the correct address. Connection timed out means the packet never got a reply. The firewall is likely dropping the packet, or the network path is broken. Check firewall-cmd and routing.
IPv6 binding can be tricky. [::]:80 usually binds to both IPv6 and IPv4 on modern kernels, but this depends on the net.ipv6.bindv6only sysctl setting. If the service binds to [::1]:80, it only accepts IPv6 localhost connections. Check the binding address carefully.
netstat is deprecated. Fedora ships ss as the default. netstat is slower because it reads from /proc/net files instead of kernel tables. It also lacks some modern filtering features. Use ss unless you are maintaining a legacy script that requires netstat output format.
Trust the error message. Connection refused means the port is closed. Connection timed out means the firewall is dropping packets.
When to use which tool
Use ss -tulpn when you need a fast, complete list of listening ports and the processes owning them.
Use ss -ant when you want to see established connections and their current state.
Use firewall-cmd --list-all when you suspect the firewall is dropping packets before they reach the service.
Use journalctl -t setroubleshoot when ss shows the port is open but the service still fails to function due to policy restrictions.
Use netstat only when you are maintaining legacy scripts that explicitly require its output format.