What ports are and how Linux services listen
A port is how a server sorts incoming traffic to the right service. Learn to read what is listening with ss, and tell a local port from a public one.
What a port actually is
A port is a number that lets one server run many services at once without their traffic getting mixed up. Your VPS has one IP address, but it might run a web server, an SSH server, and a database at the same time. When a packet arrives, the operating system needs to know which of those it is for. The port number is the answer. Web traffic goes to port 443, SSH to port 22. The IP address gets the packet to your server; the port gets it to the right program on that server.
A port is a 16-bit number: 16 bits give 0 to 65535, and 0 is reserved, so ports run from 1 to 65535 in practice. Ports below 1024 are the "well-known" ports and need root to open, which is why standard services live there: 22 for SSH, 80 for HTTP, 443 for HTTPS, 53 for DNS. Anything above 1024 is fair game for ordinary programs.
There are two kinds, TCP and UDP, and a port number in one is separate from the same number in the other. TCP is the connection-based protocol most services use, such as SSH, HTTP, and databases. UDP is connectionless and used for things like DNS and some VPNs. When you open a firewall you usually name which one, for example 22/tcp.
Listening means a program is waiting on a port
A program that wants to receive connections asks the kernel to "listen" on a port. From that moment the port is open on the machine and the program answers anything that arrives there, subject to the firewall. A port with nothing listening simply refuses connections. So the first question in any security check is: what is listening, and where.
The command to answer that is ss:
sudo ss -tlnp
The flags mean TCP (t), listening sockets only (l), numeric ports (n, so you see 22 not ssh), and the owning process (p). A typical result:
State Recv-Q Local Address:Port Process
LISTEN 0 0.0.0.0:22 sshd
LISTEN 0 127.0.0.1:5432 postgres
LISTEN 0 [::]:80 nginx
The Process column tells you which program owns each port, which is how you track down something you did not mean to leave running.
The Local Address column is the part that matters
Read the address in front of each port carefully, because it decides who can reach the service. There are three cases you will see constantly.
0.0.0.0:22 means "listen on every IPv4 address this machine has," including its public one. The service is reachable from the internet over IPv4, a firewall permitting.
[::]:80 means the same thing for IPv6: listen on every IPv6 address, public included. Many programs bind here by default, and on Linux a :: socket often accepts IPv4 as well.
127.0.0.1:5432 means "listen on loopback only." 127.0.0.1 is the address a machine uses to talk to itself, and it is not routable from anywhere else. A service bound here is reachable only from the same server, never from the internet, no matter what your firewall says. That Postgres line above is safe by construction.
The practical rule falls straight out of this: a database, a cache, or an admin panel that only your own applications use should bind to 127.0.0.1, not 0.0.0.0. If it never listens on a public address, there is nothing for an attacker to reach.
Listening is not the same as reachable
One more distinction saves a lot of confusion. A port being open on the machine, meaning a program is listening, is different from that port being reachable from outside, meaning the firewall allows it. Both must be true for a remote client to connect.
So there are two layers of control. You decide what listens, by setting each service's bind address. And you decide what the outside world can reach, with a firewall. A well-run server uses both: services bind only where they need to, and a firewall denies everything you did not explicitly allow. Reading what is listening with ss is step one; deciding what the firewall permits is step two, covered in firewalls 101 with UFW.
There is a subtlety that bites people here. IPv4 and IPv6 are separate, and a firewall that only covers IPv4 leaves the [::] services open on IPv6. That specific trap has its own post: the IPv6 firewall trap.
FAQ
How do I see what ports are open on my Linux server?
Run sudo ss -tlnp for TCP or sudo ss -ulnp for UDP. That lists every listening socket, the port, the local address it is bound to, and the process that owns it. Read the Local Address column: 0.0.0.0 or [::] means the service is exposed to the network, while 127.0.0.1 means it listens only on the machine itself.
What is the difference between 0.0.0.0 and 127.0.0.1?
0.0.0.0 means "listen on all IPv4 addresses," including the public one, so the service can be reached from the network. 127.0.0.1 is loopback, the address the machine uses to talk to itself, and it is not routable from anywhere else, so a service bound to it is reachable only locally. Bind internal services to 127.0.0.1 so they are never exposed.
Do I need to open a port in the firewall for a service to work?
Only for services that must be reached from other machines. A service bound to 127.0.0.1 needs no firewall rule because nothing external can reach it anyway. A service on 0.0.0.0 or [::] needs a firewall rule to allow the traffic, and should be denied by default until you add one.
What is the difference between a TCP port and a UDP port?
TCP is connection-based and used by most services, such as SSH, web servers, and databases. UDP is connectionless and used by DNS and some VPNs. The same number in TCP and UDP are separate ports, so 53/tcp and 53/udp are different. When you write firewall rules you name the protocol, for example 22/tcp.