🏠 Home / Hub

Linux 06 — System Administration

System administration covers everything from monitoring resources and managing packages to scheduling jobs and managing the environment. These are the day-to-day operations of keeping a Linux system running well.

1. Disk and Storage

# df — disk free (filesystem-level view)
$ df -h                         # human-readable (K, M, G)
$ df -hT                        # include filesystem type
$ df -h /home                   # specific filesystem
$ df -i                         # inode usage (number of files)
$ df -h --total                 # grand total line

# Example output:
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   18G   29G  39% /
/dev/sda2       200G  145G   45G  77% /home
tmpfs           7.8G  1.2M  7.8G   1% /run

# du — disk usage (directory-level view)
$ du -sh /var/log                # total size of /var/log
$ du -sh *                       # size of each item in current dir
$ du -sh /* 2>/dev/null          # size of each root-level dir
$ du -h /var/log | sort -h       # sort by size
$ du -sh /var/* | sort -h        # all dirs under /var, sorted
$ du -d 1 -h /var/               # depth limit: 1 level deep
$ du --max-depth=2 -h /home      # depth limit: 2 levels
$ du -h --exclude='*.mp4' /home  # exclude certain files

# Find largest files
$ find /var -type f -size +50M -exec ls -lh {} \; | sort -k5 -h

# Disk health
$ sudo fdisk -l                  # list all disk partitions
$ sudo lsblk                     # block device tree
$ sudo lsblk -f                  # with filesystem info
$ sudo blkid                     # block device UUIDs and types
$ sudo smartctl -a /dev/sda      # SMART disk health (install: apt install smartmontools)

2. Memory and System Resources

# free — memory information
$ free -h                        # human-readable
$ free -m                        # in megabytes
$ free -s 2                      # update every 2 seconds
$ free -h --si                   # use 1000 instead of 1024 as base

# Example output:
              total        used        free      shared  buff/cache   available
Mem:           15Gi       6.2Gi       1.8Gi       512Mi       7.1Gi       8.7Gi
Swap:         2.0Gi          0B       2.0Gi

# "available" is what can actually be given to new processes
# buff/cache is used by OS for disk caching (can be freed if needed)

# Detailed memory info
$ cat /proc/meminfo              # raw kernel memory statistics

# vmstat — virtual memory stats
$ vmstat 1 5                     # report every 1 second, 5 times
$ vmstat -s                      # summary statistics

# CPU information
$ lscpu                          # CPU details
$ cat /proc/cpuinfo              # raw CPU info
$ nproc                          # number of processing units

System Information

# Kernel and OS version
$ uname -a                       # all system info
$ uname -r                       # kernel version only
$ uname -m                       # machine hardware (x86_64, aarch64)

$ lsb_release -a                 # distribution info (Debian/Ubuntu)
$ cat /etc/os-release            # distribution info (all distros)
$ cat /etc/debian_version        # Debian version
$ cat /etc/redhat-release        # RHEL/CentOS version

# System uptime and load
$ uptime
10:23:45 up 15 days, 2:14,  2 users,  load average: 0.52, 0.58, 0.65
# up X days = time since last reboot
# load average = 1/5/15 minute CPU load (1.0 per core = 100% on that core)

$ uptime -p                      # pretty format: up 15 days, 2 hours, 14 minutes
$ uptime -s                      # when system started: 2024-06-10 08:09:31

# Who is logged in
$ w                              # who + what they're doing + load
$ who                            # who is logged in
$ last                           # login history
$ last reboot                    # last reboot times

3. Package Management — apt (Debian/Ubuntu)

# apt — the front-end package manager

# Update package index (always do this first)
$ sudo apt update                           # refresh package list
$ sudo apt update && sudo apt upgrade       # update everything

# Install packages
$ sudo apt install nginx                    # install nginx
$ sudo apt install nginx php-fpm mysql-server  # multiple packages
$ sudo apt install -y nginx                 # auto-yes (no prompts)
$ sudo apt install --no-install-recommends nginx  # minimal install

# Remove packages
$ sudo apt remove nginx                     # remove but keep config
$ sudo apt purge nginx                      # remove + delete config files
$ sudo apt autoremove                       # remove orphaned dependencies
$ sudo apt purge --autoremove nginx         # remove + config + orphans

# Upgrade
$ sudo apt upgrade                          # upgrade installed packages (safe)
$ sudo apt full-upgrade                     # upgrade including removals (more thorough)
$ sudo apt dist-upgrade                     # Debian-style dist upgrade

# Search and info
$ apt search nginx                          # search for packages
$ apt show nginx                            # show package details
$ apt list --installed                      # list installed packages
$ apt list --upgradable                     # packages with updates available
$ dpkg -l                                   # list all installed (detailed)
$ dpkg -l | grep nginx                      # is nginx installed?
$ dpkg -L nginx                             # files installed by nginx package
$ dpkg -S /usr/sbin/nginx                   # which package owns this file?

# Cache management
$ sudo apt clean                            # clear download cache
$ sudo apt autoclean                        # remove old downloaded packages
$ du -sh /var/cache/apt/archives            # how big is the cache

# Hold/unhold package version
$ sudo apt-mark hold nginx                  # prevent nginx from being upgraded
$ sudo apt-mark unhold nginx                # allow upgrades again
$ apt-mark showhold                         # list held packages

4. Package Management — yum/dnf (CentOS/RHEL/Fedora)

# dnf — modern yum replacement (RHEL 8+, Fedora, CentOS 8+)
# yum — still available on older CentOS/RHEL 7

$ sudo dnf update                           # update all packages
$ sudo dnf upgrade                          # same as update (aliases)
$ sudo dnf install nginx                    # install package
$ sudo dnf install nginx php-fpm mariadb-server
$ sudo dnf remove nginx                     # remove package
$ sudo dnf autoremove                       # remove unused dependencies

# Search and info
$ dnf search nginx                          # search packages
$ dnf info nginx                            # package details
$ dnf list installed                        # list installed packages
$ dnf list available | grep nginx           # search available
$ rpm -qa                                   # list all installed (raw)
$ rpm -qi nginx                             # package info
$ rpm -ql nginx                             # files in package
$ rpm -qf /usr/sbin/nginx                   # which package owns file

# Groups
$ dnf group list                            # list package groups
$ dnf group install "Development Tools"     # install a group

# Repos
$ dnf repolist                              # list enabled repos
$ dnf config-manager --add-repo URL        # add repo

# EPEL — extra packages for enterprise Linux
$ sudo dnf install epel-release             # enable EPEL repo

5. Snap and Flatpak

# Snap — Canonical's universal package format (Ubuntu default)
$ snap list                      # installed snaps
$ snap find firefox              # search snap store
$ sudo snap install firefox      # install
$ sudo snap remove firefox       # remove
$ sudo snap refresh              # update all snaps
$ sudo snap refresh firefox      # update specific snap

# Flatpak — Red Hat's universal format
$ flatpak list                   # installed flatpaks
$ flatpak search gimp            # search
$ flatpak install flathub org.gimp.GIMP  # install from Flathub
$ flatpak run org.gimp.GIMP      # run
$ flatpak uninstall org.gimp.GIMP
$ flatpak update                 # update all

6. Archives and Compression

# tar — the Linux archiving standard
# Syntax: tar [operation][modifiers] archive files

# Create archives
$ tar -czf archive.tar.gz /path/to/dir/     # create gzip compressed archive
$ tar -cjf archive.tar.bz2 /path/to/dir/   # create bzip2 archive (smaller, slower)
$ tar -cJf archive.tar.xz /path/to/dir/    # create xz archive (best compression)
$ tar -cf archive.tar /path/to/dir/        # create without compression
$ tar -czf backup_$(date +%Y%m%d).tar.gz /etc/  # timestamped backup

# Extract archives
$ tar -xzf archive.tar.gz                  # extract gzip archive
$ tar -xjf archive.tar.bz2                 # extract bzip2
$ tar -xJf archive.tar.xz                  # extract xz
$ tar -xf archive.tar.gz                   # auto-detect compression
$ tar -xzf archive.tar.gz -C /tmp/         # extract to specific directory
$ tar -xzf archive.tar.gz file.txt         # extract single file

# List archive contents
$ tar -tzf archive.tar.gz                  # list gzip archive
$ tar -tf archive.tar.gz                   # list (auto-detect)

# Flags reference
# c = create, x = extract, t = list, u = update
# z = gzip, j = bzip2, J = xz
# f = file (must be last before filename)
# v = verbose (show files as processed)
# C = change to directory

# zip/unzip
$ zip archive.zip file1 file2 file3        # create zip
$ zip -r archive.zip directory/            # recursive zip
$ zip -e secure.zip sensitive_file         # encrypted zip
$ unzip archive.zip                        # extract
$ unzip archive.zip -d /tmp/               # extract to directory
$ unzip -l archive.zip                     # list contents
$ unzip -t archive.zip                     # test integrity

# gzip/gunzip — single file compression
$ gzip file.txt                            # compress (creates file.txt.gz, removes original)
$ gzip -k file.txt                         # keep original
$ gzip -d file.txt.gz                      # decompress
$ gunzip file.txt.gz                       # same as gzip -d
$ gzip -l file.txt.gz                      # show compression ratio
$ zcat file.txt.gz                         # read without decompressing

7. Environment Variables

# View environment
$ env                            # all environment variables
$ printenv                       # same
$ printenv PATH                  # specific variable
$ echo $HOME                     # print variable value
$ echo $USER $SHELL $PWD         # multiple variables

# Important environment variables
# $PATH    — directories searched for commands
# $HOME    — current user's home directory
# $USER    — current username
# $SHELL   — current shell binary path
# $EDITOR  — default text editor
# $LANG    — locale setting
# $TERM    — terminal type
# $PS1     — command prompt format
# $DISPLAY — X11 display (for GUI apps)

# Set variables
$ MY_VAR="hello"                 # set in current shell only
$ export MY_VAR="hello"          # export to child processes
$ export PATH="$PATH:/opt/myapp/bin"  # add to PATH

# Unset variables
$ unset MY_VAR

# Set variable for single command only
$ EDITOR=vim crontab -e          # use vim for this command only
$ DEBUG=true ./script.sh         # pass variable to script

# Shell configuration files (load order matters!)
# ~/.bashrc      — interactive non-login shells (most daily use)
# ~/.bash_profile — login shells (SSH connections, TTY login)
# /etc/environment  — system-wide, all processes
# /etc/profile      — system-wide login shells
# /etc/profile.d/*.sh — modular profile scripts

# Edit ~/.bashrc to persist settings
$ nano ~/.bashrc
# Add these lines:
export EDITOR=vim
export PATH="$PATH:$HOME/.local/bin"
alias ll='ls -lah'
alias gs='git status'

# Apply changes to current session
$ source ~/.bashrc
$ . ~/.bashrc                    # same (dot command)

8. Cron Jobs — Scheduled Tasks

# crontab — per-user cron schedule
$ crontab -e                     # edit your crontab (opens in $EDITOR)
$ crontab -l                     # list your current crontab
$ crontab -r                     # remove your crontab (careful!)
$ sudo crontab -e -u alice       # edit alice's crontab (as root)
$ crontab -l -u alice            # list alice's crontab

# Cron syntax: minute hour day-of-month month day-of-week command
# ┌───────────── minute (0-59)
# │ ┌───────────── hour (0-23)
# │ │ ┌───────────── day of month (1-31)
# │ │ │ ┌───────────── month (1-12 or Jan-Dec)
# │ │ │ │ ┌───────────── day of week (0-7, 0 and 7 = Sunday)
# │ │ │ │ │
# * * * * * command-to-execute

# Cron examples
0 2 * * *        /usr/bin/backup.sh                    # daily at 2:00 AM
*/15 * * * *     /usr/bin/check_status.sh              # every 15 minutes
0 0 * * 0        /usr/bin/weekly_report.sh             # every Sunday midnight
0 */4 * * *      /usr/bin/sync_data.sh                 # every 4 hours
30 8 1 * *       /usr/bin/monthly_invoice.sh           # 1st of month at 8:30
0 9-17 * * 1-5   /usr/bin/business_hours_check.sh      # hourly Mon-Fri 9am-5pm
@reboot          /usr/bin/startup_script.sh            # at system boot
@daily           /usr/bin/daily_cleanup.sh             # shorthand for 0 0 * * *
@weekly          /usr/bin/weekly_backup.sh             # 0 0 * * 0
@monthly         /usr/bin/monthly_report.sh            # 0 0 1 * *

# System-wide cron
$ ls /etc/cron.d/                # system cron jobs
$ ls /etc/cron.daily/            # scripts run daily
$ ls /etc/cron.weekly/           # scripts run weekly
$ ls /etc/cron.hourly/           # scripts run hourly

# Redirect cron output to avoid email
0 2 * * * /usr/bin/backup.sh >> /var/log/backup.log 2>&1

# at — run a one-time job at a specific time
$ at 14:30                       # schedule for 2:30 PM
at> /usr/bin/report.sh
at> Ctrl+D
$ at now + 2 hours               # 2 hours from now
$ at midnight tomorrow           # midnight tonight
$ atq                            # list pending jobs
$ atrm 3                         # remove job number 3

9. Aliases

# Alias — shorthand for commands
# Temporary (current session only)
$ alias ll='ls -lah'
$ alias gs='git status'
$ alias la='ls -A'
$ alias cls='clear'
$ alias ..='cd ..'
$ alias ...='cd ../..'
$ alias grep='grep --color=auto'
$ alias df='df -h'
$ alias du='du -h'
$ alias please='sudo'

# View aliases
$ alias                          # list all aliases
$ alias ll                       # show specific alias

# Remove an alias
$ unalias ll

# Make permanent: add to ~/.bashrc
$ cat >> ~/.bashrc << 'EOF'

# Custom aliases
alias ll='ls -lah'
alias la='ls -A'
alias l='ls -CF'
alias ..='cd ..'
alias ...='cd ../..'
alias grep='grep --color=auto'
alias df='df -h'
alias du='du -h'
alias free='free -h'
alias update='sudo apt update && sudo apt upgrade'
alias ports='ss -tlnp'
alias myip='curl -s ifconfig.me'
alias reload='source ~/.bashrc'
EOF

$ source ~/.bashrc

10. Symbolic and Hard Links

# Symbolic links (symlinks) — like a shortcut/pointer
$ ln -s /path/to/original /path/to/link    # create symlink
$ ln -s /opt/nginx-1.24/bin/nginx /usr/local/bin/nginx
$ ln -s /data/logs/app.log /var/log/app.log
$ ln -sf /path/to/new_target existing_link  # force (overwrite existing link)

# View symlinks
$ ls -la /usr/local/bin/nginx
lrwxrwxrwx 1 root root 25 Jun 15 /usr/local/bin/nginx -> /opt/nginx-1.24/bin/nginx

$ readlink /usr/local/bin/nginx            # show link target
$ readlink -f /usr/local/bin/nginx         # show final resolved path

# Hard links — both names point to same inode (same data on disk)
$ ln original.txt hardlink.txt             # create hard link
$ ls -li original.txt hardlink.txt         # same inode number!
# Deleting one doesn't affect the other
# Hard links cannot cross filesystems or link directories

# Difference: symlink vs hard link
# Symlink: separate file pointing to path (breaks if target moves/deleted)
# Hard link: another name for same inode (survives if other name deleted)

# Remove a symlink (DON'T use rm -r, it follows the link)
$ rm /usr/local/bin/nginx                  # remove symlink
$ unlink /usr/local/bin/nginx              # also works

11. Mount and /etc/fstab

# mount — attach filesystems
$ mount                                    # show all mounted filesystems
$ mount | grep /dev/sd                     # show disk mounts
$ sudo mount /dev/sdb1 /mnt               # mount device to mount point
$ sudo mount -t ext4 /dev/sdb1 /mnt       # specify filesystem type
$ sudo mount -o ro /dev/sdb1 /mnt         # mount read-only
$ sudo mount -o remount,rw /              # remount root as read-write
$ sudo mount -t tmpfs -o size=512m tmpfs /mnt/ram  # RAM filesystem
$ sudo umount /mnt                         # unmount (when not in use)
$ sudo umount -l /mnt                      # lazy unmount (safe if busy)

# /etc/fstab — auto-mount at boot
$ cat /etc/fstab
# <device>    <mountpoint> <fstype>  <options>       <dump> <pass>
UUID=abc-123   /            ext4      errors=remount-ro 0       1
UUID=def-456   /home        ext4      defaults          0       2
UUID=ghi-789   swap         swap      sw                0       0
/dev/sdb1      /data        xfs       defaults,nofail   0       2
192.168.1.5:/share /mnt/nfs nfs      defaults          0       0

# Use UUID (not /dev/sdX) because device names can change on reboot
$ blkid /dev/sdb1                          # get UUID
$ sudo mount -a                            # mount everything in fstab
$ sudo mount -o remount /data              # remount with fstab options

# NFS mount
$ sudo apt install nfs-common
$ sudo mount -t nfs 192.168.1.5:/share /mnt/nfs

# CIFS/SMB mount (Windows share)
$ sudo apt install cifs-utils
$ sudo mount -t cifs //server/share /mnt/smb -o user=alice,password=secret

12. systemd Timers

systemd timers are a modern alternative to cron with better logging and dependency management.

# Create a timer unit
$ sudo vim /etc/systemd/system/daily-backup.service
[Unit]
Description=Daily Backup Service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=backupuser
$ sudo vim /etc/systemd/system/daily-backup.timer
[Unit]
Description=Run daily backup at 2am
Requires=daily-backup.service

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
$ sudo systemctl daemon-reload
$ sudo systemctl enable --now daily-backup.timer
$ systemctl list-timers                    # list all timers and next run time
$ systemctl list-timers --all              # include inactive timers
$ journalctl -u daily-backup.service       # view backup logs

📌 Study Checklist