You know ls, cd, chmod, and how to install a package. That gets you through a desktop session, but it does not get you through a failed boot, a full disk at 3 a.m., or a compromised SSH daemon. The jump from “Linux user” to “Linux administrator” is a jump in how you think: you stop typing commands and start reasoning about processes, storage layers, networks, and automation. This roadmap lays out the skills in the order they pay off, with the commands and config files you will touch at each stage.
Quick Takeaways
- Learn in layers: services and processes first, then storage, networking, security, automation, and finally observability and containers.
systemdis the center of gravity. Nearly every mainstream distribution (Ubuntu, Debian, RHEL, Rocky, Fedora, SUSE) uses it, so mastersystemctlandjournalctlearly.- Automate everything you do twice. Bash scripts first, then Ansible for fleets.
- Practice on disposable VMs. Break boot loaders, fill disks, and lock yourself out of SSH on purpose, so the real incident is not your first attempt.
| Stage | Focus | Core Tools | Typical Time |
|---|---|---|---|
| 1 | Processes and services | systemd, ps, journalctl |
2-3 weeks |
| 2 | Storage and filesystems | lsblk, LVM, ext4/XFS |
3-4 weeks |
| 3 | Networking | ip, ss, nftables |
3-4 weeks |
| 4 | Security hardening | SSH, sudo, SELinux/AppArmor |
3-4 weeks |
| 5 | Automation | Bash, cron, Ansible |
4-6 weeks |
| 6 | Monitoring and containers | Prometheus, Podman/Docker |
4-6 weeks |
Prerequisites: What “The Basics” Means
Before you start this roadmap, confirm you can do the following without looking anything up:
- Navigate the filesystem hierarchy (
/etc,/var,/usr,/home,/proc). - Edit files in
vimornano. - Manage users, groups, and basic permissions (
chmod,chown). - Use pipes and redirection (
|,>,>>,2>&1). - Install and remove software with
apt,dnf, orzypper.
Pick one distribution family and stay with it for the first three months. A Debian-family system (Ubuntu Server, Debian) or a RHEL-family system (Rocky Linux, AlmaLinux) both work. Learn the second family afterward; the concepts transfer, and only the package manager and some paths change.
| Factor | Debian/Ubuntu | RHEL/Rocky/Alma |
|---|---|---|
| Package manager | apt, dpkg |
dnf, rpm |
| Mandatory access control | AppArmor | SELinux |
| Default firewall front end | ufw (optional) |
firewalld |
| Release model | Ubuntu LTS: 5 years standard | RHEL-compatible: about 10 years |
| Enterprise support | Canonical | Red Hat |
| Best for learning | Large community, fast answers | Job market in enterprise shops |
Stage 1: Master Processes and Services with systemd
Most “my service is down” tickets end at systemd. It starts services, tracks their dependencies, restarts them on failure, and collects their logs.
Core systemctl Commands
systemctl status nginx # State, PID, recent log lines
systemctl enable --now nginx # Start now and at every boot
systemctl restart nginx # Stop then start
systemctl reload nginx # Re-read config without dropping connections
systemctl list-units --failed # Everything that crashed
systemctl daemon-reload # Re-read unit files after editing them
--now combines enabling and starting in one step. reload only works when the daemon supports it, so check the unit’s ExecReload= line.
Read Logs with journalctl
journalctl -u nginx --since "1 hour ago" # One unit, time-bounded
journalctl -p err -b # Errors from the current boot
journalctl -b -1 # Previous boot (after a crash)
journalctl -f -u sshd # Follow live
The -p err flag filters by priority. -b -1 is the fastest way to see what happened before an unexpected reboot, but only if persistent journaling is on. Verify with ls /var/log/journal. If the directory is missing, run mkdir -p /var/log/journal and systemctl restart systemd-journald.
Write Your Own Unit File
Create /etc/systemd/system/myapp.service:
[Unit]
Description=My Application
After=network-online.target
Wants=network-online.target
[Service]
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server --port 8080
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/lib/myapp
[Install]
WantedBy=multi-user.target
Restart=on-failure revives the process after a crash. ProtectSystem=strict mounts the filesystem read-only for the service except for paths you list, which is cheap, effective sandboxing.
Understand Processes
Learn ps aux, top/htop, kill, nice, and renice. Know the difference between signals: SIGTERM (15) asks politely, SIGKILL (9) cannot be caught, and SIGHUP (1) conventionally means “reload config.” Read /proc/<PID>/status and /proc/<PID>/fd to see what a process actually holds open. A zombie process (state Z) is already dead; its parent has not collected the exit status, so you fix the parent, not the zombie.
Stage 2: Storage, Filesystems, and LVM
Disk problems cause the most painful outages. Learn this layer before you need it.
Inspect the Block Layer
lsblk -f # Devices, filesystems, UUIDs, mountpoints
df -hT # Usage by filesystem, with type
df -i # Inode usage (a full inode table looks like a full disk)
du -xh --max-depth=1 /var | sort -h # Find what is eating space
The -x flag in du stays on one filesystem, which prevents wandering into mounted volumes. When df -h shows free space but writes fail with “No space left on device,” run df -i.
Choose a Filesystem
| Feature | ext4 | XFS | Btrfs |
|---|---|---|---|
| Maturity | Very high | Very high | Moderate |
| Online grow | Yes | Yes | Yes |
| Online shrink | Offline only | Not supported | Yes |
| Snapshots | No (use LVM) | No (use LVM) | Native |
| Checksums on data | No | Metadata only | Yes |
| Best for | General purpose | Large files, databases | Snapshots, desktops, NAS |
| Default in | Debian, Ubuntu | RHEL family | openSUSE, Fedora Workstation |
LVM in Five Commands
Logical Volume Manager lets you resize storage without repartitioning.
pvcreate /dev/sdb # Mark disk as a physical volume
vgcreate data_vg /dev/sdb # Create a volume group
lvcreate -n logs -L 20G data_vg # Carve out a 20 GB logical volume
mkfs.xfs /dev/data_vg/logs # Format it
mount /dev/data_vg/logs /var/log/app # Mount it
To grow later: lvextend -r -L +10G /dev/data_vg/logs. The -r flag resizes the filesystem in the same step.
Persist Mounts Safely
Edit /etc/fstab using UUIDs, not /dev/sdX names, because device names change between boots:
UUID=3f1c2a9e-1111-2222-3333-444455556666 /var/log/app xfs defaults,noatime,nofail 0 2
nofail lets the system boot if the disk is missing. Test every change with mount -a before you reboot. A typo in /etc/fstab drops you into emergency mode.
Stage 3: Networking
Modern Tooling
The legacy ifconfig, netstat, and route commands come from the deprecated net-tools package. Use the iproute2 replacements:
| Legacy | Modern | Purpose |
|---|---|---|
ifconfig |
ip addr |
Show/set addresses |
route |
ip route |
Routing table |
netstat -tulpn |
ss -tulpn |
Listening sockets |
arp |
ip neigh |
Neighbor cache |
ip -br addr # Brief interface summary
ss -tulpn # TCP/UDP listeners with owning process
dig +short example.com # DNS lookup
curl -v https://example.com # Full HTTP/TLS exchange
traceroute -n 8.8.8.8 # Path to a host, no DNS lookups
The -tulpn flags mean TCP, UDP, listening, process names, numeric ports. Run it with sudo to see process names for all sockets.
Learn the Network Config Stack for Your Distro
| Distro Family | Common Config Tool | Config Location |
|---|---|---|
| Ubuntu Server | Netplan (renders to systemd-networkd or NetworkManager) |
/etc/netplan/*.yaml |
| RHEL/Rocky | NetworkManager (nmcli) |
/etc/NetworkManager/system-connections/ |
| Debian | ifupdown or systemd-networkd |
/etc/network/interfaces |
Sample Netplan static address:
network:
version: 2
ethernets:
eth0:
addresses: [192.168.1.50/24]
routes:
- to: default
via: 192.168.1.1
nameservers:
addresses: [1.1.1.1, 9.9.9.9]
Apply with netplan try, which rolls back automatically if you lose connectivity. Never use netplan apply first on a remote machine.
Firewalls
Understand the layers: the kernel’s netfilter framework, with nftables as the modern front end and iptables as the legacy one. ufw and firewalld sit on top.
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
Always allow SSH before enabling a default-deny policy.
Stage 4: Security Hardening
Lock Down SSH
Edit /etc/ssh/sshd_config (or a drop-in under /etc/ssh/sshd_config.d/):
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
AllowUsers deploy admin
Validate before restarting: sshd -t. Keep your current session open while you test a second login. Generate keys with ssh-keygen -t ed25519.
sudo and Least Privilege
Edit sudoers only with visudo, which syntax-checks the file. Prefer drop-in files in /etc/sudoers.d/ over editing the main file. Grant specific commands, not blanket ALL.
Mandatory Access Control
| Feature | SELinux | AppArmor |
|---|---|---|
| Model | Label-based | Path-based |
| Default on | RHEL, Fedora | Ubuntu, Debian, SUSE |
| Complexity | Higher | Lower |
| Granularity | Very fine | Per-program profiles |
| Status command | getenforce |
aa-status |
Do not disable SELinux when something breaks. Check /var/log/audit/audit.log, run ausearch -m avc -ts recent, and use audit2why to learn what the denial means. Fix the label with restorecon -Rv /path or a boolean via setsebool -P.
Patching and Intrusion Defense
- Enable unattended security updates (
unattended-upgradeson Debian/Ubuntu,dnf-automaticon RHEL family). - Install
fail2banto ban IPs that brute-force SSH. - Audit with
lynis audit systemfor a prioritized hardening list. - Review
last,lastb, andwhofor suspicious logins.
Stage 5: Automation
Bash Scripting Fundamentals
Start every production script with strict mode:
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
-e exits on error, -u fails on unset variables, and pipefail makes a pipeline fail if any stage fails.
A practical disk-alert script:
#!/usr/bin/env bash
set -euo pipefail
THRESHOLD=85
df -hP | awk 'NR>1 {gsub("%","",$5); if ($5+0 > '"$THRESHOLD"') print $6, $5"%"}' |
while read -r mount usage; do
logger -p user.warning "Disk alert: $mount at $usage"
done
df -P forces POSIX output so awk columns stay predictable, and logger writes to the journal.
Scheduling: cron vs systemd Timers
| Factor | cron | systemd timer |
|---|---|---|
| Setup | One line in crontab -e |
Two unit files |
| Logging | Mail or manual redirect | Automatic in journalctl |
| Missed runs (machine off) | Skipped | Catch up with Persistent=true |
| Dependencies | None | Full unit ordering |
| Resource limits | None | Native (CPUQuota=, MemoryMax=) |
A timer for nightly backups, /etc/systemd/system/backup.timer:
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
Pair it with backup.service, then run systemctl enable --now backup.timer and verify with systemctl list-timers.
Configuration Management with Ansible
Ansible is agentless and works over SSH, which makes it the best first tool. A minimal playbook:
- hosts: webservers
become: true
tasks:
- name: Install nginx
ansible.builtin.package:
name: nginx
state: present
- name: Ensure nginx is running
ansible.builtin.service:
name: nginx
state: started
enabled: true
Run it with ansible-playbook -i inventory.ini site.yml --check --diff first. --check simulates, and --diff shows what would change. Idempotency is the core idea: running the playbook twice produces the same result.
Stage 6: Monitoring, Logging, and Containers
Know Your Performance Tools
| Symptom | First Tool | What to Read |
|---|---|---|
| High load average | uptime, top |
Load vs CPU core count |
| Memory pressure | free -h, vmstat 1 |
available, swap in/out (si/so) |
| Slow disk | iostat -xz 1 |
%util, await |
| Network saturation | iftop, ss -s |
Throughput, socket states |
| Unknown process behavior | strace -p PID |
System calls and errors |
Linux load average counts runnable and uninterruptible (I/O-waiting) tasks, so a high load with low CPU usually means a disk or NFS bottleneck.
Centralized Monitoring
Learn the standard open-source stack: node_exporter exposes host metrics, Prometheus scrapes and stores them, and Grafana visualizes them. Add Alertmanager for notifications. Understand rsyslog or the journal forwarding model for centralized logs.
Containers
Learn what containers actually are: processes isolated with kernel namespaces and limited by cgroups. Then use them.
podman run -d --name web -p 8080:80 docker.io/library/nginx:stable
podman ps
podman logs -f web
podman generate systemd --new --name web # Or use Quadlet on newer versions
Podman runs rootless and daemonless, and it is the default on RHEL-family systems. Docker remains widely used. The CLI is nearly identical, so learn one and you can use both.
Practical Troubleshooting Scenarios
Scenario 1: Fixing a System That Drops to Emergency Mode After an fstab Error
- At the emergency prompt, enter the root password.
- Remount root read-write:
mount -o remount,rw /. - Open
/etc/fstaband comment out the failing line. - Verify with
mount -a, thensystemctl daemon-reload. - Reboot with
systemctl reboot.
Use journalctl -xb to find which mount failed.
Scenario 2: Repairing a Corrupted GRUB Bootloader
Boot a live ISO, then:
sudo mount /dev/sda2 /mnt # Root partition
sudo mount /dev/sda1 /mnt/boot/efi # EFI partition (UEFI systems)
for d in dev proc sys run; do sudo mount --bind /$d /mnt/$d; done
sudo chroot /mnt
grub-install /dev/sda # Legacy BIOS; use --target=x86_64-efi for UEFI
update-grub # Debian/Ubuntu
exit
On RHEL-family systems, replace the last regeneration step with grub2-mkconfig -o /boot/grub2/grub.cfg (BIOS) or the path under /boot/efi/EFI/<distro>/ (UEFI).
Scenario 3: Preventing Disk Saturation from Runaway Logs
Create /etc/logrotate.d/myapp:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
Test with logrotate -d /etc/logrotate.d/myapp (dry run). Also cap the journal: set SystemMaxUse=1G in /etc/systemd/journald.conf and restart systemd-journald. If space is already gone, find deleted-but-open files with lsof +L1; restarting the holding process releases the space.
Scenario 4: Locked Out by a Bad SSH Config
Use the provider’s console or hypervisor access, revert the change in /etc/ssh/sshd_config, run sshd -t, and systemctl restart sshd. Prevention: always keep a second session open, and test with sshd -T to print the effective configuration.
Suggested Learning Path and Practice Labs
| Month | Goal | Lab Project |
|---|---|---|
| 1 | Services and logs | Write a custom systemd unit and break it on purpose |
| 2 | Storage | Add a virtual disk, build LVM, grow it live |
| 3 | Networking and firewall | Build a two-VM network with static IPs and nftables rules |
| 4 | Security | Harden SSH, run lynis, fix findings |
| 5 | Automation | Provision a web server fully with Ansible |
| 6 | Monitoring and containers | Deploy Prometheus and Grafana in containers |
Certifications that map to this roadmap: RHCSA, LFCS (Linux Foundation Certified SysAdmin), and CompTIA Linux+. They are hands-on or performance-flavored, which suits administrators better than multiple-choice exams alone. Use KVM/libvirt, VirtualBox, or a cloud free tier for labs, and snapshot before every experiment.
Frequently Asked Questions
What should I learn after Linux basics?
Learn systemd service management first, then storage (LVM, filesystems), networking (ip, ss, firewalls), security hardening (SSH, sudo, SELinux/AppArmor), Bash automation, and Ansible. Add monitoring and containers once those are solid.
How long does it take to become a Linux system administrator?
Expect roughly six months of consistent lab practice to reach junior-level competence, and one to two years of production experience to handle incidents independently. Hands-on practice matters more than reading.
Which Linux distribution should I learn for a sysadmin career?
Start with Ubuntu Server or Debian for ease of learning, and learn a RHEL-family distribution such as Rocky Linux or AlmaLinux because enterprise environments rely heavily on it. The skills overlap by about 80 percent.
Do I need to learn programming to be a Linux administrator?
You need Bash scripting at minimum. Python is the best second language for automation, API work, and tooling. Deep software development skills are optional.




