Where to go next
What a fresh install exposes, and what to learn next.
You can now find your way around a Linux server, read and set permissions, manage users and sudo, run services and read their logs, look after disks, networking, archives and packages, and work through a failure layer by layer. This last lesson points those skills at a freshly installed server to see what it exposes and what it already protects, which is exactly where the hardening course begins. It then describes the three courses that follow and what each one expects you to know.
What listens on the network
The terminals in this section come from the course's default lab machine: an Ubuntu Server 26.04 cloud image with its updates applied and nothing else installed, plus two accounts the lab needs, the VM tool's lima and the course's deploy. First, what listens for connections. "Networking basics" used ss -tlnp for TCP; adding -u includes UDP, where some services listen without any connection at all:
Read the Local Address column. Port 22 on 0.0.0.0 and [::] is SSH on every IPv4 and IPv6 address, held by systemd, which listens for the first connection, and by sshd. The DNS stub of systemd-resolved listens on 127.0.0.53 and 127.0.0.54, and chrony's command port 323 on 127.0.0.1 and [::1]; loopback addresses are reachable only from the machine itself. UDP port 68 on the network interface's address is the DHCP client of systemd-networkd, which receives the machine's address lease. UDP port 5353, multicast DNS, is there only because the lab's VM tool turns it on in systemd-resolved; a default Ubuntu Server does not listen on it. So from the network, a fresh server offers SSH and nothing else.
systemd's own list adds two SSH sockets that ss -tulpn does not show, and neither is reachable from the network. The vsock one exists only inside a virtual machine (vsock is a channel between a VM and its host); the local Unix socket is bound by systemd on any machine with sshd installed.
Who can log in, and who can become root
Accounts with a real login shell are the ones a person can use, and membership of sudo decides who can act as root:
Four accounts have a login shell. sync is historical: its "shell" is /bin/sync, which flushes data to disk and exits, so the account cannot give anyone a shell. lima belongs to the VM tool; on a cloud server the same place is taken by ubuntu, the default user that cloud-init creates. deploy is in sudo, so the %sudo rule in /etc/sudoers makes it an administrator, and in adm, so it reads the logs. Two files in /etc/sudoers.d matter. 90-cloud-init-users is written by cloud-init: Ubuntu's cloud configuration gives its default user password-less sudo, which the VM tool uses for lima. 90-secopslog-lab gives deploy password-less sudo so the labs can run unattended; your own servers should not have it. Without such a file, %sudo asks for the user's password.
-xdev keeps find on the root filesystem, and sort makes the list easy to compare with a later one. Fifteen programs carry the set-user-ID bit and run as root whoever starts them: the account tools (passwd, chsh, chfn, gpasswd, newgrp), su and sudo (sudo-rs under /usr/lib/cargo/bin, and classic sudo installed as sudo.ws), the mount helpers, a D-Bus helper and ssh-keysign. The lesson on SUID, SGID and the sticky bit explained why each exists; any program that joins this list later deserves an explanation. File capabilities, the narrower alternative from the same lesson, need their own search, because find -perm -4000 does not see them:
ping and mtr-packet may open raw network sockets (cap_net_raw), and gst-ptp-helper belongs to the GStreamer media libraries (on an x86_64 server its path has x86_64-linux-gnu in place of aarch64-linux-gnu). snap-confine, the helper snapd uses to start sandboxed snaps, holds a long list that includes cap_setuid and cap_sys_admin, which together are as good as root. Treat a new line here exactly like a new SUID program.
What already protects it, and what is missing
The remaining checks cover how SSH authenticates, whether anything filters traffic, and which security subsystems are running:
The SSH server accepts keys only: Ubuntu's cloud images switch password logins off in 60-cloudimg-settings.conf, and where no file sets it, OpenSSH's own default is to accept passwords. root may log in with a key, but never with a password (prohibit-password); logging in as yourself and using sudo leaves a record of who did what, which a shared root login does not. The firewall front-end ufw is installed but inactive, and nftables holds a single table, a NAT table the VM tool adds for its DNS forwarding, so the server itself filters nothing. AppArmor is loaded and enforcing 103 of its profiles, so hardening means confining more programs, never switching it off. auditd, the kernel audit daemon, is not installed on Ubuntu (RHEL installs and enables it).
One bug-fix update is waiting, held back by phasing as "Packages and updates" explained, and unattended-upgrades installs security fixes every day. A fresh server is not without records either: sudo writes the commands it runs to the journal and /var/log/auth.log, useradd logs every account it creates, and sshd-session logs every login. What auditd would add are records made by the kernel, such as every program executed or every change to a watched file, which do not depend on each program choosing to log.
A RHEL 10 server starts from different defaults, which the hardening course shows next to Ubuntu's at every step: SELinux in enforcing mode instead of AppArmor, auditd installed and running, the SSH server as sshd.service, enabled directly rather than started by a socket, and no automatic updates until you install dnf-automatic.
Where the track goes next
Every observation above is a starting point in the next course. Linux hardening (Intermediate) takes this default install and hardens it one control at a time: patching and reboots, fewer services and packages, accounts and PAM, sudo policy, the SSH server, trustworthy logs and auditd, file permissions, mount options and disk encryption, sandboxing services with systemd, host firewalls and nftables, kernel settings and modules, AppArmor and SELinux, integrity monitoring and CIS benchmarks. For each control it states the threat, the configuration, how to verify it, what it costs, and how to roll it back. It assumes this course and nothing else.
The findings in this lesson map directly onto its lessons. SSH listening on every address, with root allowed in by key, is the subject of "Hardening the SSH server" and "Minimise services and packages". An inactive ufw and a ruleset with no filtering lead to "Host firewalls: ufw and firewalld". Password-less sudo for the cloud user belongs to "Hardening sudo", the SUID list to "Auditing permissions, SUID/SGID and umask", and the missing auditd to "auditd rules that matter". The nightly security updates, and the question of when the server reboots to use them, are where the course begins, in "Patching and update strategy".
Advanced Linux security comes after that. It is a defensive course: how intruders escalate privileges, persist and hide on a Linux host, explained only as deeply as detection needs, then the audit pipeline, osquery, eBPF and Falco to catch them, threat hunting, live triage, forensic artefacts and incident response. It expects this course and the hardening course, whose auditd rules, sudo policy and module signing it builds on.
Advanced Linux internals and tooling is the operations path: how Linux works underneath and how to go from a symptom to a bottleneck. It covers a method for performance problems, processes and the scheduler, virtual memory, cgroups and namespaces, filesystems and the block layer, the network stack, strace, perf, flame graphs and eBPF tools, and tuning only after measuring. It needs only this course; the hardening course helps with the background on security modules and kernel settings, and the security course is not required.
Try this
Record a baseline you can compare later. On a lab server, save the listeners (without process IDs, which change), the accounts with a login shell, the sudo group, the SUID list and the file capabilities in one file: { sudo ss -Htuln; awk -F: '$7 !~ /(nologin|false)$/ {print $1}' /etc/passwd; getent group sudo; sudo find / -xdev -perm -4000 -type f | sort; sudo getcap -r / 2>/dev/null; } > ~/baseline-before.txt. The braces group the commands, so one > sends all their output to the file (the space after { and the ; before } are required), and -H leaves out ss's header line. Make a harmless change, sudo useradd -m -s /bin/bash ns-test, save the same output to ~/baseline-after.txt and run diff ~/baseline-before.txt ~/baseline-after.txt. diff prints only the differences: a location line such as 15a16 (after line 15 of the first file, line 16 of the second was added), then the added line marked with >, here > ns-test. Then find the change in the logs with journalctl -t useradd -n 2, and remove the account with sudo userdel -r ns-test. Keep the first file; as you work through the hardening course, the diff shows what each lesson changed.
Takeaway
Before you change a server, record what it exposes in a form you can diff. A change you can show with a command anyone can rerun is worth more than a change you remember making.