Which services are listening on your VPS, and what can be reached from the outside?
Every program that accepts connections listens on a port: SSH on 22, a web server on 80 and 443, MariaDB on 3306. Every port that can be reached from outside is a door into your server. A website usually only needs 22, 80 and 443 from outside. Here you'll learn how to see what's listening, on which address, and how to check what the rest of the internet sees.
Seeing what's listening
Run this on your VPS:
sudo ss -tulpn
The options mean: TCP (-t), UDP (-u), listening only (-l), which program (-p) and numbers instead of names (-n). An example:
tcp LISTEN 0.0.0.0:22 users:(("sshd",...))
tcp LISTEN 0.0.0.0:443 users:(("nginx",...))
tcp LISTEN 127.0.0.1:3306 users:(("mariadbd",...))
tcp LISTEN 0.0.0.0:6379 users:(("redis-server",...))
tcp LISTEN [::]:22 users:(("sshd",...))
The important column is Local Address, the address the program listens on:
| Address | Meaning |
|---|---|
0.0.0.0 | All IPv4 addresses, including your public address: reachable from outside unless a firewall blocks it |
[::] | All IPv6 addresses: the same for IPv6 |
127.0.0.1 or [::1] | Only the server itself (loopback): never reachable from outside |
127.0.0.53 or 127.0.0.54 | Also loopback: the local DNS helper of systemd-resolved |
In the example, MariaDB is fine: only programs on the server itself can reach it. Redis listens on all addresses, and that's exactly the mistake this is about.
Locking it down in the service itself
A database, cache or admin panel should almost never be reachable from outside. The best first step is to have the service listen on loopback only. On Debian and Ubuntu:
| Program | Setting | File |
|---|---|---|
| MariaDB or MySQL | bind-address = 127.0.0.1 | /etc/mysql/mariadb.conf.d/50-server.cnf |
| PostgreSQL | listen_addresses = 'localhost' | /etc/postgresql/<version>/main/postgresql.conf |
| Redis | bind 127.0.0.1 -::1 and protected-mode yes | /etc/redis/redis.conf |
Then restart the service (see Managing services with systemctl on your VPS) and check again with ss -tulpn. If you want to reach the database from your laptop yourself, use an SSH tunnel instead of an open port, see An SSH config: log in with a short name.
The firewall as a second layer
A firewall blocks anything that accidentally listens on all addresses anyway. How to set up ufw is explained in A firewall with ufw (or nftables). Don't rely on a single layer: a firewall can be switched off, or a rule can be too broad.
ports:) bypass ufw. A database with "3306:3306" is then reachable from outside, even if ufw says the port is closed. Prefix it with 127.0.0.1:, or don't publish the port at all. See Docker and the firewall: publishing ports safely.Checking from outside
ss shows what's listening on the server, but not what your firewall lets through. The real check is done from another computer, not from the server itself. With nc (netcat) on Mac or Linux:
nc -vz -w 3 203.0.113.10 6379 nc -6 -vz -w 3 2001:db8::10 6379
On Windows, PowerShell does the same with Test-NetConnection 203.0.113.10 -Port 6379. Fill in your own IPv4 and IPv6 address; you'll find them in the VPS screen. Here's how to read the result:
- Open (succeeded): something is listening and it's reachable from outside.
- Closed (Connection refused): nothing is listening, or the firewall is actively refusing.
- Filtered (time-out): a firewall is silently dropping the traffic.
For a database, closed and filtered are both fine. Test IPv6 too: a common mistake is a firewall with only IPv4 rules while the service also listens on [::]. A port scanner such as nmap checks many ports at once; only use such a scanner on your own server.
Your VPS is fully self-managed: you decide which services listen and how your firewall is set up. We help with the WebOké part, such as the VPS screen, the network and snapshots.
Want to learn more? Take the free course VPS and Linux server management, lesson 5.1 Ports and listening services or lesson 5.2 A firewall with ufw and nftables.
