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 -tulnpEach flag earns its place:
-tshows TCP sockets and-ushows UDP sockets-lshows only listening sockets-nskips name lookups, so you see real port numbers-pshows which process owns each socket (usesudoso 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.xmeans this machine only. Nothing outside can connect to it.0.0.0.0means 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 ~/demoFirst, bind it to localhost only:
python3 -m http.server 8080 --bind 127.0.0.1In a second terminal on the server:
sudo ss -tlnp | grep 8080Mine showed 127.0.0.1:8080, owned by python3. And from the server itself:
curl -I http://127.0.0.1:8080That returned 200 OK.

Now from my Windows PC, against my own server:
Test-NetConnection YOUR_SERVER_IP -Port 8080TcpTestSucceeded : 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.0Now 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:8081curl: (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 verboseUFW 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 OKlocally 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/tcpThen 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"4326Then 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 | head4275 DPT=443
51 DPT=80Nothing 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 -5The 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
lowlogging 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.
Run
sudo ss -tulnpand save the output.For each line, write down: who owns it, and is it local-only (
127.x) or everywhere (0.0.0.0/[::])?Start a demo server on localhost only, and confirm
ssshows127.0.0.1.Try to reach it from another computer. It should fail.
Restart it on
0.0.0.0and try again. With UFW's default deny, it should still fail.Open that one port in UFW, test again, and note what happens. If it still fails, check for a second firewall at your provider.
Close it: delete the UFW rule, stop the server, remove the folder.
Run
ss -tulnpandufw status verboseagain 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
ufw man page, logging section
https://manpages.ubuntu.com/manpages/noble/en/man8/ufw.8.html
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


