In partnership with

Free email without sacrificing your privacy

Gmail is free, but you pay with your data. Proton Mail is different.

We don’t scan your messages. We don’t sell your behavior. We don’t follow you across the internet.

Proton Mail gives you full-featured, private email without surveillance or creepy profiling. It’s email that respects your time, your attention, and your boundaries.

Email doesn’t have to cost your privacy.

After #012 I went back to the logs, but not the SSH ones. I looked at the firewall's.

In the last 24 hours, UFW on my test server blocked 4,326 packets aimed at ports 80 and 443. Nothing on that server listens on either port.

That raised a better question than "who's knocking?" It was: what is this server actually listening on, and who can reach it?

Here's how I checked.

The one command

sudo ss -tulnp

Each flag earns its place:

  • -t shows TCP sockets and -u shows UDP sockets

  • -l shows only listening sockets

  • -n skips name lookups, so you see real port numbers

  • -p shows which process owns each socket (use sudo so you can see all of them)

Here's my output, trimmed to the columns that matter:

Netid  State   Local Address:Port    Process
udp    UNCONN  127.0.0.54:53         systemd-resolve
udp    UNCONN  127.0.0.53%lo:53      systemd-resolve
tcp    LISTEN  127.0.0.53%lo:53      systemd-resolve
tcp    LISTEN  127.0.0.54:53         systemd-resolve
tcp    LISTEN  0.0.0.0:22            sshd
tcp    LISTEN  [::]:22               sshd

Read the Local Address column first. It tells you who is allowed to connect:

  • 127.x.x.x means this machine only. Nothing outside can connect to it.

  • 0.0.0.0 means every IPv4 address on the server.

  • [::] means every IPv6 address on the server.

So on my server, the DNS resolver is local-only, and SSH is listening everywhere. That matches what I did in #012. (On Ubuntu, systemd also shows up on the SSH lines because it holds the listening socket.)

Local-only versus everywhere

To see the difference for yourself, run a tiny web server two ways. Python is already on Ubuntu, so there's nothing to install. Use an empty folder so it can't serve real files:

mkdir -p ~/demo && cd ~/demo

First, bind it to localhost only:

python3 -m http.server 8080 --bind 127.0.0.1

In a second terminal on the server:

sudo ss -tlnp | grep 8080

Mine showed 127.0.0.1:8080, owned by python3. And from the server itself:

curl -I http://127.0.0.1:8080

That returned 200 OK.

Now from my Windows PC, against my own server:

Test-NetConnection YOUR_SERVER_IP -Port 8080

TcpTestSucceeded : False. The server answers itself and nobody else. That's the point of 127.0.0.1.

Stop that server with Ctrl+C and start another, this time on every interface:

python3 -m http.server 8081 --bind 0.0.0.0

Now ss showed 0.0.0.0:8081. (Only IPv4, since I asked for 0.0.0.0 and not ::.)

Listening is not the same as reachable

Here's the catch. The server was now listening on every interface, but when I tried it from my PC, it timed out:

curl.exe -m 5 -I http://YOUR_SERVER_IP:8081
curl: (28) Connection timed out after 5010 milliseconds

UFW's default is to deny incoming connections, and I'd only allowed SSH. A service can be listening on 0.0.0.0 and still be unreachable because the firewall drops the traffic first.

So I opened that one port on purpose:

sudo ufw allow 8081/tcp
sudo ufw status verbose

UFW added a rule for IPv4 and one for IPv6, and the status listed both.

I expected the next test to succeed. It didn't. curl.exe from my PC still timed out.

What I could confirm:

  • The server answered 200 OK locally on 8081.

  • UFW listed the rule, and logged no blocks for port 8081.

  • From the same PC, port 22 connected fine (TcpTestSucceeded : True).

So the listener was fine, the host firewall was fine, and my PC could reach the server on SSH. Something else was in the path.

It was a second firewall. My server had a cloud firewall attached in the provider's dashboard, sitting in front of the server and separate from UFW. After I removed it, the same test succeeded, and curl got an answer:

HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.12.3

That is the "make sure they agree" point from #012, caught on my own server. The port was open in UFW and still unreachable, because a second firewall said no. Two layers, two rule sets. I removed the cloud firewall entirely just to test, which I wouldn't do on a server that matters. The better move is to add the one port to it for the test, then take that rule back out. I put my cloud firewall back after the lab.

When I was done, I removed the rule and stopped the server:

sudo ufw delete allow 8081/tcp

Then I stopped the demo with Ctrl+C, removed the folder, and ran ss -tulnp and ufw status verbose again to confirm I was back where I started.

What the firewall log showed

Back to those 4,326 packets. UFW writes what it blocks to the kernel log, so I counted them:

sudo journalctl -k --since "24 hours ago" --no-pager | grep -c "UFW BLOCK"
4326

Then I used the same counting trick from #011:

sudo journalctl -k --since "24 hours ago" --no-pager | grep "UFW BLOCK" | grep -o 'DPT=[0-9]*' | sort | uniq -c | sort -rn | head
4275 DPT=443
  51 DPT=80

Nothing was listening on either port. UFW dropped every one before it mattered.

Then I checked where they came from:

sudo journalctl -k --since "24 hours ago" --no-pager | grep "UFW BLOCK" | grep -o 'SRC=[0-9.]*' | sort | uniq -c | sort -rn | head -5

The top five sources sent 744, 300, 249, 237, and 20 packets. The first four add up to about a third of the total. In all, the 4,326 packets came from 1,835 different source addresses.

A few honest caveats:

  • These are packets, not visitors. One scanner can send several.

  • UFW's default low logging is rate-limited, so the real volume could be higher. Treat my numbers as a floor.

  • This is one server over one day.

  • I'm not going to guess who is behind any of it.

What I will say is that the only door I left open on this server is SSH, and #012 was about making that one hard to use.

Try This: map your own server

Use a disposable Ubuntu server, not one anyone depends on. The whole lab took me about 40 minutes, including opening and closing the port. Give yourself an hour the first time.

  1. Run sudo ss -tulnp and save the output.

  2. For each line, write down: who owns it, and is it local-only (127.x) or everywhere (0.0.0.0 / [::])?

  3. Start a demo server on localhost only, and confirm ss shows 127.0.0.1.

  4. Try to reach it from another computer. It should fail.

  5. Restart it on 0.0.0.0 and try again. With UFW's default deny, it should still fail.

  6. Open that one port in UFW, test again, and note what happens. If it still fails, check for a second firewall at your provider.

  7. Close it: delete the UFW rule, stop the server, remove the folder.

  8. Run ss -tulnp and ufw status verbose again and confirm you're back to the start.

Save the before and after output, the commands, and what surprised you. Mine surprised me at step 6, and I'd rather you saw that than a tidy ending.

Only do this on your own server, and keep the demo port open for minutes, not days. A demo web server is a throwaway tool, not something to leave running on the internet.

Worth Knowing

It explains the logging levels and says low is rate-limited, which is why my block counts are a floor.

The full list of flags and filters.

Remote roles worth a look this week

Why spend your evenings on ss, firewalls, and Linux basics? Because employers keep asking for these skills. Here are four current remote roles, from true entry level to early career.

Listings can close quickly. I checked each one on the employer's own page while preparing this issue, but always check the employer's page before applying.

Linux Support Engineer, JetRails

Remote | Salary starting at $45,000 | 1+ year in customer service or technical support

A Linux-heavy support role at a managed hosting company. You'd help customers by phone, ticket, and chat with Linux and AWS server problems. They list Ubuntu or CentOS, DNS, networking and IP routing, MySQL, cPanel, and hands-on AWS (EC2, CloudWatch, Auto Scaling). Know before you apply: this is a 24/7 support environment, and they ask for availability for weekends and overnight shifts.

IT Support Specialist, Zillow

Remote U.S., Eastern Time hours | 0-2 years | $27.30-$45.90 per hour depending on location, plus equity eligibility

A genuine entry-level IT role. The work is desktop and end-user support: setting up and retiring laptops, basic troubleshooting for network connectivity, printing, and account access, and documenting what you did in the ticketing system. They ask for a high school diploma or equivalent and 0-2 years of related experience.

Technical Support Engineer, Lumana

Remote, U.S. Eastern Time Zone (hybrid for NYC) | $70K-$90K + equity | 1-3 years

Hands-on troubleshooting across TCP/IP, DNS, DHCP, routing, firewalls, servers, and edge devices. Linux and Python are nice-to-haves. Know before you apply: this is an evenings and weekends support position, and you must live in the Eastern Time Zone.

Technical Support Engineer L2, LucidLink

Remote U.S. | $72K-$90K base + equity + bonus eligibility | 2+ years

Support for a cloud file-streaming product across macOS, Windows, and Linux. The work includes reproducing customer issues, running live debug sessions, and collecting logs and debug data. TCP/IP knowledge is required, with cloud, networking, and scripting as pluses. Daytime U.S. hours.

What these have in common

Look at the four together and the same things keep coming up: Linux, networking basics, troubleshooting, reading logs, documenting your work, and explaining it clearly to someone else. Knowing what your server is listening on, and who can reach it, is exactly the kind of thing those basics cover.

None of that guarantees a job. Nothing does. But these skills keep showing up because employers keep needing them, and every one of them is something you can practice on a cheap server or a free VM this weekend.

If you're building the fundamentals

I'm also building SecureByDefault Learning Paths, a free GitHub repo that organizes Linux, networking, troubleshooting, cloud, hands-on projects, and career paths into a learning order. It's a work in progress and I add to it regularly.

Your next step

New to Linux?

The free Linux Starter Kit includes the commands, a practice plan, log examples, and a beginner server checklist.

If someone forwarded you this issue, you can subscribe here: https://newsletter.securebydefault.io/

Next issue

My server greets me every time I log in with the same two messages: a restart is required, and some security updates are waiting. Next time: what to do about updates on a Linux server, what "restart required" actually means, and how to see what's pending before you touch anything.

Talk soon,

Ron
SecureByDefault

Reply

Avatar

or to participate

Recommended for you

View all
caret-right