Short answer: The commands you will use most on a Linux server are df -hT and du for disk, free -h, ps and top for memory and processes, systemctl and journalctl for services and logs, ip, ss -tulpn and dig for networking, and dnf (AlmaLinux, Rocky, RHEL) or apt (Debian, Ubuntu) for packages. The tables below group them by task, with the flags that matter on a production box.
We ran these commands on our lab servers on 7 October 2026: AlmaLinux 9.8 with cPanel & WHM 11.138 (dnf, systemd and general commands) and Debian 12.15 (apt and dpkg commands). Read-only commands ran as shown. tar, rsync, sed -i, find -delete and kill ran only on test files we created and then removed. Commands that change the system (service restarts, useradd, passwd -l, package installs, set-timezone) were checked against each tool’s --help output on the same servers, but not run, because our lab rules forbid changes.
Table of Contents
Files and disk space
| Command | What it does |
|---|---|
df -hT | Free space per filesystem, human sizes, with filesystem type |
df -i / | Inode usage. A disk can be “full” with free GB left if inodes run out |
du -xh --max-depth=1 /var | sort -rh | head | Biggest directories one level down, staying on one filesystem (-x) |
ncdu -x / | Interactive disk browser. Not installed by default: EPEL on AlmaLinux (we saw ncdu 1.22 there), main repo on Debian |
find /home -xdev -type f -size +100M | Files larger than 100 MB |
find /var/log -type f -name "*.gz" -mtime +30 | Compressed logs older than 30 days |
lsof +L1 | Deleted files still held open. Their space is not freed until the process restarts |
lsof -i :443 -sTCP:LISTEN | Which process listens on a port |
Real output from our AlmaLinux lab (the -x tmpfs -x devtmpfs options hide memory-backed filesystems):
# df -hT -x tmpfs -x devtmpfs
Filesystem Type Size Used Avail Use% Mounted on
/dev/vda1 ext4 79G 13G 62G 18% /
/dev/loop0 ext4 3.4G 68M 3.1G 3% /tmp
When df says the disk is full but du cannot find the space, run lsof +L1. A log file deleted while Apache or MariaDB still has it open keeps using space. Restart that service, or truncate the file through /proc/<pid>/fd/. On our lab, lsof +L1 listed only small Dovecot and dbus files, which is normal.
Before you delete by age, run the same find with -print, read the list, then swap -print for -delete:
find /var/log/myapp -name "*.log" -mtime +30 -print # review first
find /var/log/myapp -name "*.log" -mtime +30 -delete # then delete
For a full cleanup procedure on a hosting server, see our disk full runbook.
Processes and memory
| Command | What it does |
|---|---|
uptime | Load average for 1, 5 and 15 minutes. Compare with the CPU count from nproc |
top / htop | Live view. In top, press M to sort by memory, P by CPU. htop was installed on our cPanel lab |
top -b -n1 | head -15 | One snapshot, good for pasting into a ticket |
ps aux --sort=-%mem | head | Processes using the most memory |
ps -eo pid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head | Custom columns, including how long each process has run |
pgrep -a sshd | PIDs and command lines matching a name |
free -h | RAM and swap. Read the available column, not free |
vmstat 1 5 | Five one-second samples. High si/so means swapping; high wa means waiting on disk |
kill PID | Ask a process to stop (SIGTERM) |
kill -9 PID | Force-kill (SIGKILL). Last resort: the process cannot clean up |
# free -h
total used free shared buff/cache available
Mem: 3.8Gi 1.7Gi 313Mi 71Mi 1.9Gi 2.1Gi
Swap: 127Mi 127Mi 0.0Ki
On our 4 GB cPanel lab only 313 MB is “free”, but 2.1 GB is available, because the kernel drops cache when an application needs memory. The swap is full, which is worth a look, but it is not an emergency while vmstat shows si and so at 0.
Services and logs (systemctl and journalctl)
| Command | What it does |
|---|---|
systemctl status nginx | State, main PID, and the last log lines |
systemctl restart nginx | Stop and start. reload rereads config without dropping connections, if the service supports it |
systemctl enable --now nginx | Start now and at every boot |
systemctl is-active httpd crond | One word per unit; handy in scripts |
systemctl --failed | Every failed unit. Check this first after a reboot |
systemctl list-timers | systemd timers, with next and last run times |
systemctl cat crond | The unit file, including any drop-in overrides |
systemctl daemon-reload | Required after you edit a unit file |
journalctl -u sshd --since "1 hour ago" | Logs for one unit in a time window |
journalctl -p err -b | Errors and worse since the last boot |
journalctl -u nginx -f | Follow new lines live, like tail -f |
journalctl -k | Kernel messages (OOM killer, disk errors) |
journalctl -g "Failed password" -u sshd | Grep inside the journal |
journalctl --disk-usage | Space used by the journal |
journalctl --vacuum-time=14d | Delete archived journal files older than 14 days |
On our cPanel lab, systemctl --failed immediately showed a real problem:
# systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
● cpgreylistd.service loaded failed failed cPanel Greylisting Daemon
On AlmaLinux 9 servers without rsyslog, /var/log/secure may be empty or missing. Our lab had no rsyslog package and a 0-byte /var/log/secure, yet the journal held over 1,000 failed SSH passwords from the last 24 hours. If a log file looks empty, ask journalctl instead.
The unit name for SSH is sshd on AlmaLinux and ssh on Debian and Ubuntu. Check with systemctl list-unit-files | grep ssh. For timer files, our systemd unit generator writes them with safe defaults.
Networking
| Command | What it does |
|---|---|
ip -br addr | One line per interface with its addresses |
ip route show default | Default gateway(s) |
ss -tulpn | Listening TCP and UDP sockets with the owning process (replaces netstat -tulpn) |
ss -tn state established "( dport = :443 or sport = :443 )" | Live connections on port 443 |
ping -c 3 203.0.113.10 | Three pings and a loss summary |
mtr -rwc 10 -n 203.0.113.10 | Report mode: loss and latency per hop, no DNS lookups |
traceroute -n 203.0.113.10 | Path to a host |
dig +short example.com A | DNS answer only |
dig @1.1.1.1 example.com NS +short | Ask a specific resolver |
dig -x 203.0.113.10 +short | Reverse DNS (PTR) |
curl -I https://example.com | HTTP status and response headers only |
curl -s -o /dev/null -w "%{http_code} %{time_total}s\n" https://example.com | Status code and total time, for quick checks |
In mtr, 100% loss on a middle hop that later hops do not show is usually a router that ignores ICMP, not a fault. We saw exactly that on hops 1 and 4 from our lab. Only loss that continues to the final hop matters. Our online traceroute runs the same test from other countries.
Packages on minimal installs: dig comes from bind-utils on AlmaLinux (dnf provides /usr/bin/dig told us) and from bind9-dnsutils on Debian 12.
Users, permissions and sudo
| Command | What it does |
|---|---|
id bob | UID, GID and groups |
useradd -m -s /bin/bash -G wheel bob | Create a user with a home directory, bash, and the wheel group (sudo on AlmaLinux; use sudo on Debian) |
usermod -aG wheel bob | Add to a group. Without -a, -G replaces all supplementary groups |
passwd -l bob / passwd -u bob | Lock / unlock the password. SSH keys still work, so also expire the account or remove keys |
usermod -L -e 1 bob | Lock the password and expire the account, which stops key logins too |
passwd -S bob | Password status (locked, set, algorithm) |
chage -l bob | Password and account expiry dates |
chmod 640 file / chmod -R u+rwX dir | Set permissions (capital X adds execute only to directories) |
chown -R bob:bob /home/bob/app | Change owner and group recursively |
sudo -l | What the current user may run with sudo |
chown -R and chmod -R on the wrong path can break a whole server, for example on / or /home. Record the current state first with getfacl -R dir > perms.acl (restore with setfacl --restore=perms.acl), and double-check the path before you press Enter.
Need the octal value for a permission set? Use our chmod calculator.
Packages: dnf and apt side by side
| Task | AlmaLinux / Rocky / RHEL (dnf) | Debian / Ubuntu (apt) |
|---|---|---|
| Refresh package lists | automatic (force with dnf makecache --refresh) | apt update |
| List available updates | dnf check-update | apt list --upgradable |
| Security updates only | dnf updateinfo list --security | from the -security suite (shown by apt list) |
| Install updates | dnf upgrade | apt upgrade |
| Install a package | dnf install mtr | apt install mtr |
| Remove a package | dnf remove mtr | apt remove mtr |
| Is it installed? Which version? | rpm -q openssh-server | dpkg -l openssh-server |
| Which package owns a file? | rpm -qf /usr/sbin/sshd | dpkg -S /usr/sbin/sshd |
| Which package provides a command? | dnf provides /usr/bin/dig | apt-file search bin/dig (needs the apt-file package) |
| Package details | dnf info curl | apt show curl |
| Installed vs candidate version | dnf list --installed curl | apt-cache policy curl |
| History | dnf history list | /var/log/apt/history.log |
On our Debian 12 lab, apt list --upgradable showed pending security updates for libpng16-16 and linux-image-amd64, and the suite shows as oldstable-security because Debian 13 is now the stable release. On AlmaLinux, dnf updateinfo list --security listed the kernel advisory ALSA-2026:74438. Add -C to dnf commands to read the local cache without contacting the mirrors.
On cPanel servers, do not remove or downgrade packages that cPanel manages (EA4, MariaDB, cpanel-*). Let upcp handle them, and see our upcp failed guide if updates stop.
Archives and file transfer
| Command | What it does |
|---|---|
tar -czf site.tar.gz -C /srv site | Create a gzip archive of /srv/site with relative paths |
tar -tzf site.tar.gz | List the contents without extracting |
tar -xzf site.tar.gz -C /restore | Extract into a chosen directory |
rsync -avhn --delete src/ dst/ | Dry run (-n) that shows what a mirror would change |
rsync -avh -e "ssh -p 2222" src/ bob@203.0.113.10:/backup/ | Copy over SSH on a custom port |
scp -P 2222 file bob@203.0.113.10:/tmp/ | Single file over SSH. Note capital -P for the port in scp |
The trailing slash matters in rsync: src/ copies the contents of src, while src creates dst/src. We tested this flow on scratch data:
rsync -a src/ mirror/ # first copy
echo change >> src/f1.txt
rsync -avhn --delete src/ mirror/ # dry run: lists only f1.txt
rsync -avh --delete src/ mirror/ # real run after you read the list
--delete removes files in the destination that are not in the source. Swapping source and destination by mistake wipes your data, so always run with -n first.
Text processing: grep, awk, sed, sort | uniq -c
| Command | What it does |
|---|---|
grep -rn "DB_HOST" /var/www/ | Recursive search with line numbers |
grep -rl "eval(base64" /home/*/public_html | Only the names of files that match |
awk '{print $9}' access_log | sort | uniq -c | sort -rn | Count HTTP status codes in a combined-format log |
awk '{s+=$10} END {print s/1024/1024 " MB"}' access_log | Sum bytes sent |
awk -F: '$3>=1000 {print $1}' /etc/passwd | Normal (non-system) users |
sed -n '100,120p' file | Print lines 100 to 120 |
sed -i.bak 's/old/new/' file | Edit in place and keep file.bak |
Top sources of failed SSH passwords in the last 24 hours, straight from the journal:
journalctl -u sshd --since "24 hours ago" --no-pager \
| grep "Failed password" | grep -oE "from [0-9.]+" \
| sort | uniq -c | sort -rn | head
55 from x.x.x.x
46 from x.x.x.x
46 from x.x.x.x
Swap the pattern for grep -oP "Invalid user \K\S+" to see which usernames bots try. On our lab, the top guesses were admin and ubuntu.
Cron and time
| Command | What it does |
|---|---|
crontab -l | Current user’s cron jobs (crontab -l -u bob for another user, as root) |
crontab -e | Edit them safely (syntax is checked on save) |
ls /etc/cron.d /etc/cron.daily | System-wide jobs that crontab -l does not show |
journalctl -u crond --since today | Did the job run? (unit is cron on Debian) |
timedatectl | Time zone, UTC time and whether the clock is synced |
timedatectl set-timezone UTC | Change the time zone |
chronyc tracking | NTP offset and stratum (chrony is the default on AlmaLinux) |
Build schedules without guessing fields with our cron expression helper.
Security quick checks
| Command | What it shows |
|---|---|
last -a -n 20 | Recent logins and reboots, with source host |
lastb -n 20 | Recent failed logins (root only; reads /var/log/btmp) |
w | Who is logged in right now, and what they are running |
ss -tulpn | Every listening port. Anything you cannot explain needs a look |
systemctl list-unit-files --state=enabled | Everything that starts at boot |
find / -xdev -perm -4000 -type f | SUID binaries; compare with a known-good list |
rpm -Va / debsums -c | Package files whose checksum changed (debsums is a separate package; it was not installed on our Debian lab) |
These are triage commands, not an audit. For a structured check, run our server security audit script. If you think the server is already compromised, follow the incident response runbook and do not reboot first.
Official documentation: journalctl man page · ss man page · RHEL 9: Managing software with DNF · Debian Reference: package management
Related: Disk full on a production server: recovery runbook · Harden SSH AlmaLinux 9: Secure Setup in 15 Minutes · CSF Commands Cheat Sheet: Allow, Deny, Ports and Tempbans · Multi-Server Health Check over SSH · AI Command Explainer and Risk Checker for Linux and PowerShell
Frequently asked questions
What replaced netstat on modern Linux?
ss, which is part of iproute2, the same package as the ip command. ss -tulpn gives the same listening-port view as netstat -tulpn. netstat comes from the older net-tools package; it was installed on both our labs, but you cannot count on it everywhere.
Why does df show a full disk when du shows free space?
Usually a deleted file is still held open by a running process. lsof +L1 lists those files; restart the process that holds them and the space is released.
Where are the SSH login logs on AlmaLinux 9?
In the systemd journal. /var/log/secure only fills up when rsyslog is installed and running. Use journalctl -u sshd to read them either way.
How do I lock a Linux user without deleting it?
passwd -l bob locks the password only, so SSH keys still work. usermod -L -e 1 bob locks the password and expires the account, which blocks key logins too.
What is the dnf equivalent of apt update?
dnf refreshes its metadata automatically when it is older than the configured expiry, so there is no separate step. dnf makecache –refresh forces a refresh, and dnf check-update lists available updates.