🐧 Linux The Foundation for Every Developer

🚀 Learn Linux the Right Way – Practical, In-Depth & RHCSA-Focused

Master Linux from the ground up, from basic commands and system navigation to advanced administration, networking, automation, and security.
These tutorials are designed for real-world learning and complete RHCSA exam preparation.

⬇️ Jump To

Introduction to Linux

Linux is a free, open-source operating system that powers everything from mobile devices to servers and supercomputers. It provides a stable, secure, and efficient platform for both personal and enterprise use.

Why Learn Linux?

  • It’s the backbone of cloud, DevOps, and server administration.

  • Used by major companies: Google, Amazon, Red Hat, IBM, and more.

  • Essential for certifications like RHCSA, RHCE, and LFCS.

Key Features

  • Multi-user and multi-tasking support

  • Open-source and customizable

  • Secure and stable

  • Community-driven development

💡 Pro Tip: Learning Linux gives you the foundation for working with any modern technology stack, from development to deployment.

Linux Architecture Overview

The Linux operating system is structured in layers, each with a specific role in how it operates.

Hardware ⮕ Kernel ⮕ System Libraries ⮕ Utilities ⮕ User Space

Here’s a simplified breakdown of its main components:

LayerDescription
HardwareThe physical components: CPU, memory, disks, and devices.
KernelThe brain of Linux: manages hardware, memory, and processes.
System LibrariesProvide functions that interact with the kernel (e.g., glibc).
System UtilitiesCore tools for managing files, processes, and users.
User SpaceWhere applications and user commands run.

💡 Pro Tip: The kernel is like a bridge between your hardware and software, it ensures they talk efficiently.

Linux Distributions

Below are some of the most popular Linux distributions widely used across different environments:

  • Ubuntu: Beginner-friendly and ideal for newcomers, developers, and desktop users.

  • Fedora: Known for its cutting-edge features and frequent updates.

  • CentOS Stream: A rolling-release model that tracks just ahead of RHEL.

  • RHEL (Red Hat Enterprise Linux): Enterprise-grade, stable, and widely adopted in production environments; essential for RHCSA/RHCE certifications.

  • AlmaLinux: A free, open-source, 1:1 binary-compatible alternative to RHEL, popular after CentOS transitioned to Stream.

  • Debian: Renowned for its stability, strong community support, and long-term reliability.

💡 Pro Tip: If you’re preparing for RHCSA, focus on RHEL or AlmaLinux, since both share the same commands, structure, and package management system

Accessing the Command Line in Linux

Bash Shell

The Bash (Bourne Again Shell) is the default command-line interface in most Linux systems, used to execute commands, run scripts, and automate administrative tasks.

[user@host ~]$ →  Shell Prompt

[user@host ~]# →  Superuser Shell Prompt

Login using SSH

SSH (Secure Shell) is a protocol used to securely connect to a remote Linux system over a network. It encrypts all communication, protecting passwords and commands from eavesdropping.

    • ssh username@remotehost
    • username → the user account on the remote system

    • remotehost → the hostname or IP address of the remote system

For added security, you can use SSH keys instead of passwords (Click here for more details on SSH Keys):

    • ssh -i /path/to/private_key username@remotehost
      
    • -i /path/to/private_key → specifies your private key file

    • The matching public key must be added to the remote user’s ~/.ssh/authorized_keys

Host Verification

The first time you connect to a remote host, SSH may prompt:

    • The authenticity of host 'remotehost (IP)' can't be established. Are you sure you want to continue connecting (yes/no)?
    • Enter yes to accept the host key and save it for future connections.

Security Tip

  • Never share your private key.
  • Use chmod 600 mykey.pem to restrict access to your key file.

Logout

To safely end your session, type:
exit
or press Ctrl + D.

💡 Pro Tip: Using SSH keys is highly recommended for servers and cloud instances, especially for RHCSA exam practice and real-world setups.

Basic Linux commands and Shortcuts

This section introduces some of the most commonly used Linux commands and Bash shortcuts that every user should know.

Common Commands

  • whoami → Displays the current logged-in username
  • command1; command2 → Executes multiple commands sequentially
  • date → Displays the current date and time
  • date +%R → Displays the time in HH:MM format (+%R is a string formatter)
  • date +%x → Displays the current date in MM/DD/YYYY format (+%x is a string formatter)
  • passwd → Changes or sets the user’s password
  • file <file_name>/<directory_name> → Determines and displays the type of file or directory

Viewing File Contents

  • cat <file_name> → Displays the content of a file
  • cat <file_name1> <file_name2> → Displays the contents of multiple files sequentially
  • less <file_name> → Views long files page by page (use ↑ / ↓ keys to scroll, and Q to exit)
  • head <file_name> → By default, displays the first 10 lines of a file
  • head -n 15 <file_name> → Displays the first 15 lines of a file. The number 15 can be replaced with any number
  • tail <file_name> → By default, displays the last 10 lines of a file
  • tail -n 20 <file_name> → Displays the last 20 lines of a file. The number 20 can be replaced with any number

Counting File Data

  • wc <file_name> → Counts lines, words, and characters in a file
  • wc -l <file_name> → Counts only the number of lines
  • wc -w <file_name> → Counts only the number of words
  • wc -c <file_name> → Counts only the number of characters

Command History and Continuation

  • history → Displays a list of previously executed commands
  • !ls → Repeats the most recent command starting with “ls”
  • !<number> → Executes the command corresponding to that number from the history (e.g., !25)

Command Continuation

When a command is too long to fit on one line, you can use a backslash (\) at the end of the line to continue typing on the next line.

This improves readability and organization in scripts or complex commands.

Always make sure there’s no space after the backslash, or the continuation won’t work.

    • head -n 3 \
      > /usr/share/dict/words \
      > /usr/share/dict/linux.words

Other Useful Commands

  • man -k <keyword/command> → Searches the manual (man) pages for a given keyword or command
  • mkdir -p Thesis/Chapter1 Thesis/Chapter2 Thesis/Chapter3 → Creates multiple parent and subdirectories at once

Tab Completion

Tab completion helps you quickly complete commands or file names by pressing the Tab key.

    • Press Tab once → Auto-completes if the command or file name is unique.
    • Press Tab twice → Shows all possible matches.

Useful Command-line Editing Shortcuts

Shortcut Description
Ctrl + A Jump to the beginning of the command line.
Ctrl + E Jump to the end of the command line.
Ctrl + U Clear from the cursor to the beginning of the command line.
Ctrl + K Clear from the cursor to the end of the command line.
Ctrl + ← (Left Arrow) Jump to the beginning of the previous word on the command line.
Ctrl + → (Right Arrow) Jump to the end of the next word on the command line.
Ctrl + R Search the history list of commands for a matching pattern.

SSH Key-Based Authentication

SSH key-based authentication is a more secure and convenient way to log in to remote systems without using passwords.

Instead of typing your password each time, a pair of cryptographic keys (a public key and a private key) is used to establish trust between the client and the server.

  • The private key acts as your authentication credential and must be kept secret and secure, just like a password.

  • The public key is copied to the remote system you want to access and is used to verify the private key. It does not need to be confidential.

SSH_Connection_explained

Generating SSH Keys

To create a private key and matching public key for authentication, use the ssh-keygen command.

  • [user@host ~]$ ssh-keygen
    Generating public/private rsa key pair.
    Enter file in which to save the key (/home/user/.ssh/id_rsa): Enter
    Enter passphrase (empty for no passphrase): Enter
    Enter same passphrase again: Enter
    Your identification has been saved in /home/user/.ssh/id_rsa.
    Your public key has been saved in /home/user/.ssh/id_rsa.pub.
  • ~/.ssh/id_rsa → Private key

  • ~/.ssh/id_rsa.pub → Public key

If you set a passphrase, you’ll need to enter it when using the key. Else, anyone with your private key file could use it.
Example: Custom Key Name with Passphrase

  • [user@host ~]$ ssh-keygen -f ~/.ssh/key-with-pass
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase):
    Enter same passphrase again:
    Your identification has been saved in ~/.ssh/key-with-pass
    Your public key has been saved in ~/.ssh/key-with-pass.pub
  • The -f option lets you specify a custom filename.

  • The example above creates a passphrase-protected key pair:

    • ~/.ssh/key-with-pass → Private key

    • ~/.ssh/key-with-pass.pub → Public key

Sharing the Public Key

The ssh-copy-id command copies the public key of the SSH keypair to the destination system.
  • ssh-copy-id -i .ssh/key-with-pass.pub user@remotehost → Copies the specified public key to the remote host.
  • ssh-copy-id user@remotehost → Copies the default public key (~/.ssh/id_rsa.pub) to the remote host.
  • ssh -i .ssh/key-with-pass user@remotehost → Uses the specified private key to connect.
  • ssh user@remotehost → Uses the default private key (~/.ssh/id_rsa) to connect.

SSH-agent

When using SSH keys protected with a passphrase, you normally need to enter it each time you connect.
To avoid this, you can use ssh-agent, which securely stores your private key’s passphrase in memory, allowing you to enter it only once per session.

  • eval "$(ssh-agent -s)" → Start the agent
  • ssh-add ~/.ssh/id_rsa → Add your key (enter passphrase once)
  • ssh user@remotehost → Login without re-entering it

Identifying Remote Users

[user01@remotehost ~]$ w
16:13:38 up 36 min, 1 user, load average: 0.00, 0.00, 0.00
USER    TTY     FROM            LOGIN@   IDLE   JCPU   PCPU   WHAT
user02  pts/0   172.25.250.10   16:13    7:30   0.01s  0.01s  -bash
user01  pts/1   172.25.250.10   16:24    3.00s  0.01s  0.00s  w

Column descriptions:

  • USER: Logged-in username

  • FROM: Remote IP address

  • IDLE: Idle time

  • WHAT: Current command being executed

SSH Host Keys

When connecting to a server:

  • The client checks the server’s public key against its local known hosts file.

  • If the key is unknown or changed, the user is prompted for confirmation.

  • Once accepted, the key is stored in ~/.ssh/known_hosts.

Example:

[user01@host ~]$ ssh newhost
The authenticity of host 'newhost (172.25.250.12)' can't be established.
ECDSA key fingerprint is SHA256:qaS0PToLrqlCO2XGklA0iY7CaP7aPKimerDoaUkv720.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'newhost,172.25.250.12' (ECDSA) to the list of known hosts.

SSH Known Hosts File

Public keys of remote servers are saved in:

  • System-wide: /etc/ssh/ssh_known_hosts

  • User-specific: ~/.ssh/known_hosts

Each entry includes:

<hostname> <key_algo> <public_key>

Example entry from ~/.ssh/known_hosts:

remotehost,172.25.250.11 ecdsa-sha2-nistp256 AAAAE2VjZH...

If a server’s key changes (due to reinstall or rotation), remove its old entry from this file to avoid SSH warnings.

Configuring the OpenSSH Server

The OpenSSH server is managed by the sshd daemon. Its main configuration file is:

/etc/ssh/sshd_config

It’s generally used with secure defaults, but two common security enhancements are:

  1. Prohibit Remote root Login
    • Reason to disable root SSH login:
      • Reduces attack surface (root is a known username).
      • Avoids misuse of root’s unrestricted privileges.
      • Improves accountability (users must log in as themselves first).
    • To disable root login:
      • Edit /etc/ssh/sshd_config:
        • PermitRootLogin no
      • To allow only key-based root login (optional):
        • PermitRootLogin without-password
      • PermitRootLogin without-password
        • sudo systemctl reload sshd
  2. Disable Password-Based Authentication
    • Benefits of key-based authentication:

      • Prevents brute-force password attacks.

      • Safer if private keys are passphrase-protected.

      • Can use ssh-agent for convenience.

    • To disable password authentication:
      • In /etc/ssh/sshd_config:
        • PasswordAuthentication no
      • Then reload SSH:

        • sudo systemctl reload sshd

💡 Pro Tips: 

The permission modes must be 600 on the Private Key, 644 on the Public Key, and 600 for Authorized Keys

  • chmod 600 ~/.ssh/id_rsa  →  Private Key Permission
  • chmod 600 ~/.ssh/authorized_keys →  Authorized Keys Permission
  • chmod 644~/.ssh/id_rsa.pub → Public Key Permission

When you run the ssh-keygen command again without changing the filename of the existing keys, the old keys are overwritten with new ones. As a result:

  • The old public key previously shared with a server is no longer valid.
  • You will not be able to log in to that server using the new private key.
  • To fix this, you must copy the new public key again to the remote server using the ssh-copy-id command

Before disabling password-based authentication, ensure that every user already has their public key added to the server’s ~/.ssh/authorized_keys file, otherwise they will be locked out of SSH access.

Managing File Systems

On Linux, all files are organized in a single inverted tree called the file-system hierarchy, with / as the root directory.
Subdirectories like /etc and /boot help organize files by type and purpose.
Files and directories are referenced using / as a separator, e.g., /etc/issue refers to the issue file inside /etc.

LocationPurpose
/usrInstalled software, libraries, include files, and read-only program data.
Important subdirs: /usr/bin (user commands), /usr/sbin (admin commands), /usr/local (local software).
/etcSystem-specific configuration files.
/varVariable data that persists across boots, e.g., databases, logs, cache, and website content.
/runRuntime data for processes since last boot, including PID and lock files. Recreated on reboot.
/homeHome directories for regular users’ personal data and configs.
/rootHome directory for the administrative superuser, root.
/tmpTemporary files. Auto-deleted if not used for 10 days. /var/tmp retains files for 30 days.
/bootFiles required for system boot.
/devSpecial device files used to access hardware.

Basic Linux Commands You Should Know

  • pwd → Prints current directory.
  • ls → Lists all files and directories in the current directory.

Note: All ls variations (-l, -la, -R) support specifying one or more directories, e.g., ls /etc /var.

    • ls -l → Shows files in long listing format with details like permissions, owner, size, and modification date.
    • ls -la → Lists all files including hidden files (those starting with .).
    • ls -R → Recursively lists all files in the current directory and its subdirectories.
  • cd <directory_path> → Changes the current directory.
  • cd .. → Moves up one level to the parent directory.
  • cd - → Changes back to the previous directory.
  • touch <file_name> → Updates a file’s timestamp to the current date/time or creates an empty file if it doesn’t exist.
Command-line File Management

To manage files and directories effectively, you can use various commands to create, remove, copy, move, and organize them.

Creating Directories

  • mkdir <directory1> <directory2> → Creates one or more directories.

  • mkdir -p <directory1> <directory2> → Creates parent directories if they don’t already exist.

  • Example:
    • mkdir Videos/Watched
    • mkdir -p Thesis/Chapter1 Thesis/Chapter2 Thesis/Chapter3

Copying Files

  • cp <filename> <new-filename> → Copies a file and creates a duplicate with a new name.

  • cp -r <directory> <new-directory> → Copies an entire directory recursively (all files and subdirectories).

  • If the destination already exists, it will be overwritten.

  • Example:
    • cp blockbuster1.ogg blockbuster3.ogg
    • cp -r Thesis ProjectX

 Moving Files

  • mv <filename> <new-filename> → Moves or renames a file.

  • mv <directory> <new-directory> → Moves or renames a directory.

  • Example:
    • mv thesis_chapter2.txt thesis_chapter2_updated.txt
    • mv Chapter1 Thesis/Chapter1_updated

 Removing Files and Directories

  • rm <filename1> <filename2> → Removes one or more files.

  • rm -r <directory1> <directory2> → Removes directories and their contents recursively.

    • Use -i for confirmation before each file.

    • Use -f to force deletion without prompts.

  • rmdir <directory1> <directory2> → Removes empty directories.

  • Example:
    • rm thesis_chapter2_updated.txt
    • rm -rf Chapter1_updated
    • rmdir Chapter1
Managing Links Between Files

It’s possible to create multiple names that point to the same file through Hard Links and Soft (Symbolic) Links.

Hard Links

  • A Hard Link is another name that points directly to the same file data.

  • Even if the original file is deleted, its contents remain available through the hard link.

  • Hard links cannot be created for directories.

  • Hard links must be on the same file system.

  • ln newfile.txt /tmp/newfile-hlink2.txt → Command to create hard link
    • ln → Command used to create a hard link

    • newfile.txt → Original file

    • /tmp/newfile-hlink2.txt → Hard link name

  • To verify both files point to the same data:

    • [user@host ~]$ ls -il newfile.txt /tmp/newfile-hlink2.txt
      8924107 -rw-rw-r--. 2 user user 12 Mar 11 19:19 newfile.txt
      8924107 -rw-rw-r--. 2 user user 12 Mar 11 19:19 /tmp/newfile-hlink2.txt
    • The same inode number confirms both are hard links to the same file.

  • When to use:
    • You want multiple filenames for the same file on the same file system.

    • You need backup-like access without extra storage.

Soft (Symbolic) Links

  • A Soft Link (also called a Symbolic Link) is a special type of file that points to another file or directory.

  • Can link files across different file systems.

  • Can link to directories or special files, not just regular files.

  • If the original file is deleted, the soft link remains but becomes a “dangling link” (A Soft link pointing to a missing file).

  • ln -s /home/user/newfile-link2.txt /tmp/newfile-symlink.txt → Command to create soft link
    • ln -s → Command used to create a soft (symbolic) link

    • /home/user/newfile-link2.txt → Original file

    • /tmp/newfile-symlink.txt → Soft link name

  • When to use:
    • You want a shortcut to another location.

    • You’re linking across partitions or to a directory.

    • You frequently manage system files, logs, or scripts from one place.

Command-Line Expansions

The Bash shell supports several kinds of expansions that simplify command-line operations. These include pattern matching (globbing), home directory expansion, string and variable expansion, and command substitution.

Pattern Matching (Globbing)

  • Globbing expands wildcard patterns into matching file or path names. These metacharacters help you perform operations on multiple files efficiently.
PatternExamplesExplanation
*ls a* → matches able, alfa
ls *a* → matches able, baker, charlie
Matches any string of zero or more characters.
?ls ?.txt → matches a.txt, b.txt
ls a? → matches ab, ax
Matches exactly one single character.
[abc…]ls [ab]* → matches able, baker
ls [ch]* → matches charlie, henry
Matches any one character from the specified set inside brackets.
[!abc…] or [^abc…]ls [!a]* → matches everything except files starting with a
ls [^b]* → matches all files not starting with b
Matches any one character not in the specified set.
[[:alpha:]]ls [[:alpha:]]* → matches able, charlie
ls *[[:alpha:]] → matches filea, testB
Matches alphabetic characters only (A–Z, a–z).
[[:lower:]]ls [[:lower:]]* → matches able, baker
ls *[[:lower:]] → matches filea, datax
Matches lowercase letters only.
[[:upper:]]ls [[:upper:]]* → matches File1, Test
ls *[[:upper:]] → matches fileA, dataX
Matches uppercase letters only.
[[:alnum:]]ls [[:alnum:]]* → matches file1, test
ls *[[:alnum:]] → matches data1, x9
Matches letters and digits (A–Z, a–z, 0–9).
[[:punct:]]ls [[:punct:]]* → matches _file, -data
ls *[[:punct:]]* → matches data-file, name_test
Matches punctuation or symbols, not spaces or alphanumeric characters.
[[:digit:]]ls [[:digit:]]* → matches 1file, 2025.txt
ls *[[:digit:]] → matches file1, log9
Matches digits only (0–9).
[[:space:]]ls *[[:space:]]* → matches “my file.txt”, “test data.csv”
ls *[[:space:]] → matches “data file”
Matches whitespace characters (space, tab, newline, etc.).

Tilde Expansion (~)

  • The tilde (~) represents the home directory of the current or specified user.
  • Example:
    • [user@host home]$ ls ~root
      /root
    • [user@host home]$ echo ~/home
      /home/user/home

Brace Expansion ({})

  • Used to generate multiple strings in one command. Braces contain:

    • A comma-separated list of strings, or

    • A sequence expression using ...

  • Example:
    • [user@host home]$ echo {Sunday,Monday,Tuesday,Wednesday}.log
      Sunday.log Monday.log Tuesday.log Wednesday.log
    • [user@host home]$ echo file{1..3}.txt
      file1.txt file2.txt file3.txt
    • [user@host home]$ echo file{a..c}.txt
      filea.txt fileb.txt filec.txt
    • [user@host home]$ echo file{a,b}{1,2}.txt
      filea1.txt filea2.txt fileb1.txt fileb2.txt
    • [user@host home]$ echo file{a{1,2},b,c}.txt
      filea1.txt filea2.txt fileb.txt filec.txt

Note: You can replace echo with other commands like mkdir, touch, cat, less, etc., to perform actions on multiple files or directories at once.

Variable Expansion ($VARIABLE)

  • Variables store values that can be expanded (substituted) in commands.
  • Syntax:
    • VARIABLENAME=value
      echo $VARIABLENAME
  • Example:
    • [user@host ~]$ USERNAME=operator
      [user@host ~]$ echo $USERNAME
      operator
    • [user@host ~]$ echo ${USERNAME}
      operator

Command Substitution ($(command))

  • Replaces a command with its output.

  • Example:
    • [user@host glob]$ echo The time is $(date +%M) minutes past $(date +%l%p).
      The time is 26 minutes past 11AM.

Protecting Arguments from Expansion

  • To prevent unwanted shell expansions, you can use escaping or quoting.
  • Escaping: Use \ (backslash) to protect the next character from expansion
  • Example:
    • [user@host glob]$ echo The value of \$HOME is your home directory.
      The value of $HOME is your home directory.
  • Quoting: Controls how the shell interprets special characters.
    • Single Quotes ' ' → Prevents all expansions.
    • Double Quotes " " → Prevents most expansions, but allows variable and command substitution.
  • Example:
    • [user@host glob]$ myhost=$(hostname -s); echo $myhost
      host
    • [user@host glob]$ echo "***** hostname is ${myhost} *****"
      ***** hostname is host *****
    • [user@host glob]$ echo "Will variable $myhost evaluate to $(hostname -s)?"
      Will variable host evaluate to host?
    • [user@host glob]$ echo 'Will variable $myhost evaluate to $(hostname -s)?'
      Will variable $myhost evaluate to $(hostname -s)?

Redirecting Output to a File or Program

You can send a command’s output to a file or another program instead of the terminal using redirection (>, >>) and pipelines (|). This helps save results or pass data seamlessly between commands.

Standard Input, Standard Output, and Standard Error

Every running program (process) interacts with three standard data streams called file descriptors:

File DescriptorNameDescription
0Standard Input (stdin)Reads input (usually from the keyboard).
1Standard Output (stdout)Sends normal output to the terminal.
2Standard Error (stderr)Sends error messages to the terminal.

Redirection allows these streams to be sent to or read from files instead.

Redirecting Output to a File

I/O redirection changes how a process reads or writes data. Instead of showing output on the terminal, it can be saved to a file or discarded.

  • If the file doesn’t exist → it’s created.

  • If the file exists → it’s overwritten unless using >> (append).

  • To discard unwanted data, redirect it to /dev/null.

Operator / CommandExplanationExample
>Redirects stdout (normal output) to a file, overwriting any existing content.ls > files.txt
>>Redirects stdout and appends output to a file (does not overwrite).echo "done" >> log.txt
2>Redirects stderr (error messages) to a file, overwriting existing content.ls /root 2> errors.log
2>>Redirects stderr and appends to a file.ls /root 2>> errors.log
2> /dev/nullDiscards error messages completely.ls /root 2> /dev/null
> file 2>&1Redirects both stdout and stderr to the same file (overwrite mode).ls /root > all.log 2>&1
>> file 2>&1Redirects both stdout and stderr to the same file (append mode).ls /root >> all.log 2>&1
&> fileBash shortcut: redirects both stdout and stderr (overwrite mode).ls &> output.log
&>> fileBash shortcut: redirects both stdout and stderr (append mode).ls &>> output.log
< fileRedirects stdin (input) from a file.sort < names.txt

Constructing Pipelines

A pipeline is a sequence of one or more commands separated by the pipe symbol (|).

It connects the stdout of one command to the stdin of the next.

Itsend output from one process directly into another.

Example:

  • ls -t | head -n 10 > /tmp/ten-last-changed-files → List the 10 most recently modified files and save to a file.

tee combine redirection with a pipeline, it copies its stdin to both stdout and one or more files

Example:

  • ls -t | head -n 10 | tee /tmp/ten-last-changed-files → Save final pipeline output and also show it on screen.

💡 Pro Tip: The order matters when redirecting both output and errors. the correct order is first stdout and then stderr.

Editing Text Files

Vim is one of the most powerful and widely used text editors in Linux and UNIX systems. It’s fast, efficient, and ideal for editing configuration files directly from the terminal even on remote servers. Knowing Vim ensures you can manage files without a graphical interface, making it an essential skill for every Linux user.

Vim can be accessed in two ways:

  • vi filename → Lightweight version available with the vi command (core editing features only)
  • vim filename → Full version with advanced features, syntax highlighting, and help system.

Basic Vim Workflow

  • Open a file:
    • vim filename
  • Press i to enter insert mode and start editing

  • Press Esc to return to command mode

  • Save your changes with :w or save and quit with :wq

  • Exit without saving using :q!

  • Display absolute line numbers :set number
  • Undo the last change with u

  • Delete a single character with x

Changing the Shell Environment

You can customize your shell environment by setting shell variables and environment variables. These variables can store values, simplify commands, and modify the behavior of the shell or programs run from it.

Shell Variables

  • Shell variables are local to a particular shell session.

  • Assign values using:

    • VARIABLENAME=value
  • Example:
    • COUNT=40
    • first_name=John
  • Accessing variable values:
    • echo $COUNT
    • echo ${COUNT}x

Environment Variables

  • Environment variables are exported from the shell so programs can access them.
  • Export a variable:

    • export EDITOR=vim
  • Common environment variables:

    • PATH → directories searched for executable programs

    • HOME → user’s home directory

    • LANG → locale and language settings

  • Example:
    • export PATH=${PATH}:/home/user/sbin
    • export LANG=fr_FR.UTF-8

Automatic Variable Setup

  • To set variables automatically at shell startup, edit Bash startup scripts like ~/.bashrc:

    • vim ~/.bashrc
    • PATH="$HOME/.local/bin:$HOME/bin:$PATH"
      export PATH
      export EDITOR=vim

Unsetting and Unexporting Variables

  • Remove a variable entirely:

    • unset PS1
  • Remove export without unsetting:

    • export -n PS1

Managing Users and Groups

Users

  • A user represents an account on the system that can log in and access resources.

  • Each user has a unique username and a user ID (UID).

  • Users can have different levels of privileges:

    • Root user (UID 0) → Superuser with full system control (UID 0).

    • Regular users → Created for normal activities, with limited access.

    • System User → Used for system processes and services (non-login accounts).
  • You can use the id command to show information about the currently logged-in user, also you can pass the username to the id command as an argument to information about another user
  • Example:
    • [user01@host ~]$ id
      uid=1000(user01) gid=1000(user01) groups=1000(user01) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
    • [user01@host]$ id user02
      uid=1002(user02) gid=1001(user02) groups=1001(user02) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  • All user account information are stored in /etc/passwd file, where each line represents one user, with fields separated by colons (:)
    • username:password:UID:GID:GECOS:home_directory:shell → Syntax of /etc/passwd
    • alice:x:1001:1001:Alice Smith:/home/alice:/bin/bash → entry in /etc/passwd
  • getent passwd username → Displays user info from /etc/passwd.
FieldDescription
usernameLogin name
xPlaceholder for password (actual passwords are stored in /etc/shadow)
UIDUser ID number
GIDPrimary group ID number
GECOSUser information (full name, contact, etc.)
home_directoryPath to the user’s home folder
shellDefault shell for the user (e.g., /bin/bash)

Groups

  • A group is a collection of users. Groups are used to manage permissions collectively.

  • Each group has a group name and a group ID (GID).

  • A user can belong to one primary group and multiple secondary groups.

  • implifies file permission management.

  • Allows multiple users to share access to files and directories without giving them full system access.

  • groups alice → Lists all groups user ‘alice’ belongs to
  • All group information are stored in /etc/group
    file, where each line represents one group, with fields separated by colons (:)
    • group_name:password:GID:user_list → Syntax of /etc/group
    • devteam:x:1002:alice,bob,charlie → entry in /etc/group
  • getent group groupname → Displays group info from /etc/group.
FieldDescription
group_nameName of the group
xPlaceholder for group password (rarely used)
GIDGroup ID number
user_listComma-separated list of users in this group
Superuser Access
  • The Superuser (Root) user has complete control over a Linux system including files, users, and devices.

  • Normal users have limited access; for example, they can manage USB devices but cannot modify system files.

  • The root account is equivalent to the Administrator account in Windows.

  • For security reasons, it’s recommended not to log in directly as root. Instead, log in as a normal user and use commands like su or sudo when administrative privileges are needed.

  • Two common ways to start a root shell:
    • sudo -i → Starts an interactive root shell with login scripts.
    • sudo su - → Starts a full root login shell.
  • Both achieve similar results, but sudo -i is generally preferred in Red Hat systems.

Switching Users

  • The su (substitute user) command allows switching to another user account.

  • su - username → Syntax

  • Example:
    • [user1@host ~]$ su - user2
      Password:
      [user2@host ~]$
    • su - → switches to root

Running Commands with sudo

  • The sudo command allows a permitted user to run commands as another user (usually root).

  • Unlike su, it asks for the user’s own password, not the root password.

  • Example:

    • [user01@host ~]$ sudo usermod -L user02
      [sudo] password for user01:
  • Every sudo action is recorded in /var/log/secure.

Configuring Sudo Access

  • The sudo command allows users to run commands with the privileges of another user, typically the root user. Proper configuration ensures secure and controlled administrative access.

  • The main configuration file for sudo is /etc/sudoers. Always edit with visudo to prevent syntax errors.

  • %wheel ALL=(ALL) ALL
    • %wheel → applies to the wheel group.

    • ALL=(ALL) → can run commands as any user on any host.

    • Final ALL → can run any command.

  • Files in /etc/sudoers.d/ are automatically included by /etc/sudoers. The permission for those files should be 440

  • To grants sudo to a specific user, you would create a file /etc/sudoers.d/user01  with the following content:
    • user01 ALL=(ALL) ALL
  • To grants sudo to a group, you would create a file /etc/sudoers.d/group01 with the following content:
    • %group01 ALL=(ALL) ALL
  • ansible ALL=(ALL) NOPASSWD:ALL → To allow a user to run commands without a password (commonly used in automation or cloud setups)
Managing Users
  • The useradd and usermod commands in Linux are used to create and manage user accounts.
  • They allow administrators to define user details such as home directories, shells, group memberships, and account permissions efficiently.
  • When a user is added, a home directory is usually created, a primary group with the same name is assigned, and any additional groups the user belongs to are called supplementary groups.
CommandOptionDescription
useradd, usermod-c "comment"Add or update the user’s description or comment field (real name, etc.).
useradd, usermod-d /path/to/homeSpecify a custom home directory for the user account.
useradd, usermod-mCreate the home directory if it doesn’t exist (useradd) or move it to a new location
with usermod -d.
useradd, usermod-s /bin/bashSet or change the user’s login shell.
useradd-u UIDAssign a specific User ID number.
useradd, usermod-g groupAssign a primary group for the user account.
useradd, usermod-G group1,group2Add or set additional (supplementary) groups for the user.
usermod-aAppend the user to supplementary groups instead of replacing existing ones (used with
-G).
useradd-e YYYY-MM-DDSet an account expiration date.
useradd-p passwordAssign an encrypted password for the user account.
usermod-LLock the user account (disables login).
usermod-UUnlock a previously locked user account.
  • Example:
    • useradd user01
    • useradd -m -c "Dev User" -s /bin/bash -G devteam john
    • usermod -aG docker john → -aG command adds user to a supplementary group
    • usermod -g group01 user02 → -g option here with usermod command create a different primary group for the user
  • The passwd command is used to set the password for the user,  Only root can change other users’ passwords.
  • Example:
    • passwd user01 → This will prompt the user to enter the password for user01
  • The userdel command is used to delete a user account from the system. It should be used with the -r option to ensure that the user’s home directory and mail spool are also removed.
  • Example:
    • userdel user01 → Deletes the user, but the home directory remains.

    • userdel -r john → Deletes the user and their home directory.

  • Red Hat Enterprise Linux uses specific UID numbers and ranges for different purposes:
    • UID 0 → Always assigned to the superuser account (root).

    • UID 1–200 → “System users” assigned statically to system processes by Red Hat.

    • UID 201–999 → “System users” used by processes that do not own files; typically assigned dynamically when software is installed. These unprivileged users have limited access to system resources.

    • UID 1000+ → Available for assignment to regular users.

Managing Groups
  • A group must exist before a user can be added to that group.
  • Groups help manage permissions and access control for multiple users efficiently.
  • The groupadd command is used to create new group in the system.
CommandOptionDescription
groupadd-g GIDAssign a specific Group ID.
groupadd-rCreate a system group (typically with a GID < 1000).
  • Example:
    • groupadd developers
    • groupadd -g 1050 admins
    • groupadd -r group02
  • The groupmod is used to change the group details, such as name of GID
CommandOptionDescription
groupmod-g GIDChange the group ID.
groupmod-n new_name old_nameRename the group.
  • Example:
    • groupmod -g 1200 developers
    • groupmod -n devteam developers
  • The groupdel command is used to remove the group from the system.
  • A group cannot be deleted if it is the primary group of any existing user.
  • You must modify or delete the user first before removing the group.
  • Example:
    • groupdel devteam
Managing User Passwords
  • User password management in Linux is critical for security and access control. Passwords, aging policies, and account restrictions are managed through files like /etc/shadow and commands such as passwd, chage, and usermod.
  • The passwords stored in /etc/shadow are encrypted and accessible only by root.
  • Example: Entry of /etc/shadow file
    • user01:$6$CSsXcYG1L/4ZfHr/$2W6evvJahUfzfHpc9X.45Jc6H30E...:19500:0:90:7:14:20000:
  • Each line in /etc/shadow contains nine colon-separated fields, including:
Field NameExample ValueDescription
Usernameuser01The account name.
Encrypted Password$6$CSsXcYG1L/4ZfHr/$2W6evvJahUfzfHpc9X.45Jc6H30E...Hashed password using SHA-512.
Last Password Change19500Days since 1970-01-01 when the password was last changed.
Minimum Days0Minimum number of days before the password can be changed again.
Maximum Days90Maximum number of days before the password must be changed.
Warning Period7Number of days before expiration that the user is warned.
Inactivity Period14Days after password expiry before the account is disabled.
Account Expiration Date20000Date (in days since 1970-01-01) when the account will expire.
Reserved Field(empty)Reserved for future use; usually left blank.
  • An encrypted password entry looks like:

    • $6$CSsXcYG1L/4ZfHr/$2W6evvJahUfzfHpc9X.45Jc6H30E...
    • $6$ → SHA-512 algorithm

    • CSsXcYG1L/4ZfHr/ → Salt (random data to strengthen security)

    • Remainder → Encrypted password hash

  • You can manage password aging with the chage command:

Command ExampleDescription
sudo chage -m 0 -M 90 -W 7 -I 14 user01Set minimum (0), maximum (90), warning (7), and inactivity (14) days.
sudo chage -d 0 user01Force user to change password at next login.
sudo chage -E 2025-12-31 user01Expire account on a specific date.
sudo chage -l user01Display password aging information.
  • Default password aging rules are set in /etc/login.defs using:
    • PASS_MAX_DAYS → Max password age
    • PASS_MIN_DAYS → Min password age
    • PASS_WARN_AGE → Warning period before expiration
  • Restricting account access (locking) is preferred over deletion when temporarily disabling a user, such as during employee offboarding.
CommandDescription
sudo usermod -L usernameLock user account (disable password login).
sudo usermod -U usernameUnlock user account.
sudo usermod -L -e 2025-12-31 usernameLock and expire the account simultaneously.
  • For accounts that should not log in interactively (like service accounts), assign the nologin shell:
    • sudo usermod -s /sbin/nologin username
  • This enhances security while still allowing background processes (like mail or services) to use the account.

Controlling Access to Files

Linux permissions determine what users can do with files and directories. Permissions are divided into three types: read (r), write (w), and execute (x), and apply to owner, group, and others.

Permission Effect on Files Effect on Directories
r Can read the file contents Can list file names in the directory
w Can modify the file contents Can create or delete files in the directory
x Can execute the file as a command Can access directory contents and traverse it if file permissions allow

The ls -l command shows detailed information about files and directories:

  • [user@host ~]$ ls -l test
    -rw-rw-r-- 1 student student 0 Feb 8 17:36 test
  • [user@host ~]$ ls -ld /home
    drwxr-xr-x 5 root root 4096 Jan 31 22:00 /home

Below is a breakdown of the ls -l command output to help you understand what each part represents.

  • First character: File type
    • - → Regular file

    • d → Directory

    • l → Symbolic link

    • b/c → Block/character device

    • p/s → Special-purpose files

  • Next nine characters: Permissions
    • 1st set of 3 characters → Owner

    • 2nd set of 3 characters→ Group

    • 3rd set of 3 characters→ Others

    • r = read, w = write, x = execute

    • - = permission not granted

  • Number: Number of hard links
  • Owner and group: File ownership
  • Example:
    • -rw-rw-r-- 1 student student
      • Owner → read & write

      • Group → read & write

      • Others → read only

    • drwxr-xr-x 5 root root
      • Owner → read, write, execute

      • Group → read & execute

      • Others → read & execute

Special Permission Flag displayed as the first character in ls -l output (_ in _rwxrwxrwx), can vary depending on file type or special flags. Numeric Permissions
  • Each permission has a numeric value:
    • r = 4 → Read
    • w = 2 → Write
    • x = 1 → Execute
  • Numeric permission calculation:
    • Example: rwx → 4 + 2 + 1 = 7
    • Example: rw- → 4 + 2 + 0 = 6
    • Example: r-- → 4 + 0 + 0 = 4
    • Example: r-x → 4 + 0 + 1 = 5
File Permissions and Ownership

The chmod command is used to change file and directory permissions. It stands for “change mode”, since permissions are also known as the mode of a file.

The command accepts a permission instruction followed by one or more files or directories.

Permissions can be changed in two ways:

  • Symbolic method

  • Numeric (octal) method

Symbolic Method

chmod [Who][What][Which] file|directory
Part Meaning Values
Who Whose permissions to change u = user (owner), g = group, o = others, a = all
What Action to perform + = add, - = remove, = = set exactly
Which Which permissions r = read, w = write, x = execute

You can modify one or more existing permissions without resetting all of them.
Use:

  • + to add

  • - to remove

  • = to set exact permissions

Example:
  • chmod go-rw file1 → Remove read and write permission for group and others on file1
  • chmod a+x file2 → Add execute permission for everyone on file2

Using an uppercase X instead of lowercase x adds execute permission only if the file is a directory or already executable for user, group, or others.

The -R option applies changes recursively to all files and subdirectories.

Example:

  • chmod -R g+rwX demodir
  • Adds read and write permissions for the group on demodir and all its contents.

  • Adds execute permission only to directories or files that already have execute permission.

Numeric(Octal) Method

chmod ### file|directory

Each digit represents permissions for user, group, and others, in that order.

Level Permissions Calculation Value
User rwx 4+2+1 7
Group r-x 4+0+1 5
Others --- 0+0+0 0

Numeric code: 750

chmod 750 filename

Example:

  • chmod 644 samplefile → User: read/write, Group: read, Others: read
  • chmod 750 sampledir → User: read/write/execute, Group: read/execute, Others: none

Changing File and Directory Ownership

When a file is created, it is owned by:

  • The user who created it.

  • The user’s primary group (usually a private group for that user).

Sometimes, ownership must be changed to grant access to another user or group.

The chown command is used to changed the ownership of files and directories

chown [OPTION] OWNER:GROUP FILE|DIRECTORY
  • Only root can change file ownership.

  • Both root and file owner can change group ownership (if the owner is a member of that group).

  • We can mention just the Owner or Group or Both
Examples:
  • chown student test_file → Changes owner of test_file to user student
  • chown -R student test_dir → Recursively changes ownership of test_dir and its contents to student
  • chown :admins test_dir → Changes the group of test_dir to admins
  • chown visitor:guests test_dir → Changes both owner to visitor and group to guests

Alternatively, group ownership can be changed using chgrp command

  • chgrp groupname file|directory
  • chgrp admins test_dir
Special Permissions in Linux

Special permissions are advanced access features that extend beyond basic user, group, and other permissions. They modify how files and directories behave when accessed or executed.

Special Permission Effect on Files Effect on Directories
u+s (setuid) File executes as the file owner, not the user running it. No effect.
g+s (setgid) File executes as the file’s group, not the user’s group. Files created inside inherit the directory’s group ownership.
o+t (sticky bit) No effect. Users can only delete their own files even if they have write access to the directory.
The special permissions on files or directories can be identified by running the ls -l command and examining the output. Refer to the table below for examples of how special permission bits appear in listings.
Example Meaning
-rwsr-xr-xs replaces x in owner field setuid active (e.g., /usr/bin/passwd)
drwxr-sr-xs replaces x in group field setgid active (e.g., /run/log/journal)
drwxrwxrwtt replaces x in others field sticky bit active (e.g., /tmp)
Special Permissions can be set in 2 ways:
  • Symbolic
    • u+s, g+s, o+t → Syntax
    • chmod g+s directory → Example

  • Numeric (4th digit)
    • 4 = setuid, 2 = setgid, 1 = sticky → Syntax
    • chmod 2770 directory → Example

Default Permissions & umask

When a file or directory is created, it’s assigned default permissions determined by two factors:

  1. Type of item (file or directory)

  2. User’s umask (user file-creation mode mask)

The default permission before applying umask for file is 0666 (-rw-rw-rw-) and for directory is 0777 (drwxrwxrwx)

Execute permission isn’t granted automatically to new files for security reasons.

umask defines which permission bits should be removed (masked) from the default permission set when new files or directories are created.

Example:

  • [user@host ~]$ umask
    0002
  • This clears the write bit for others, resulting in:

    • New file → -rw-rw-r--

    • New directory → drwxrwxr-x

Umask Examples:
umask File Permissions Directory Permissions Description
0002 -rw-rw-r-- drwxrwxr-x Default for collaborative environments
0000 -rw-rw-rw- drwxrwxrwx Everyone has full access
007 -rw-rw---- drwxrwx--- Restricts access to others
027 -rw-r----- drwxr-x--- Secure default; no access for others
To set a new umask for the current session, use the command umask 027, where 027 represents the permission mask value and can be changed to any valid octal value as needed. To make the umask configuration persistent, modify the global settings in /etc/profile or /etc/bashrc. For user-specific overrides, make changes in the ~/.bashrc or ~/.bash_profile files. You must log out and back in for global umask changes to take effect.

Access Control List (ACL)

Standard Linux file permissions work well when files are used by a single owner and one group.
However, when files must be accessed by multiple users or groups with different permission sets, Access Control Lists (ACLs) come into play.

ACLs allow administrators to grant permissions to multiple named users or groups (by username, group name, UID, or GID) using the same permission flags as standard file permissions:

  • r – read
  • w – write
  • x – execute

Named users and groups are not visible in a simple ls -l output, they are stored within the ACL structure.

Who Can Set ACLs

  • File owners can set ACLs on their own files or directories.

  • Privileged users with the CAP_FOWNER capability can set ACLs on any file or directory.

  • Inheritance: New files and subdirectories inherit ACLs from their parent directory’s default ACL, if one exists.

Note: The parent directory must have the execute (search) permission set for named users/groups to access the contents.

File-System ACL Support

File systems must have ACL support enabled.

  • XFS: ACLs are built-in.

  • ext3/ext4 (RHEL 8 and later): ACL option enabled by default.

  • Older systems: Verify ACL support manually.

You can enable ACL support by mounting the filesystem with the acl option:

  • mount -o acl /dev/sdX /mountpoint

Or, persist it in /etc/fstab:

  • UUID=<id> /data ext4 defaults,acl 0 2

Viewing and Interpreting ACL Permissions

The ls -l command gives a minimal hint of ACLs:

  • [user@host content]$ ls -l reports.txt
    -rwxrw----+ 1 user operators 130 Mar 19 23:56 reports.txt

The + at the end of the permission string means extended ACLs exist.

FieldMeaning
user:User ACL (same as file owner permissions)
group:Current ACL mask, not group owner permissions
other:Same as standard “other” file permissions

Viewing File ACLs

Use getfacl to display ACLs:

  • [user@host content]$ getfacl reports.txt
    # file: reports.txt
    # owner: user
    # group: operators
    user::rwx
    user:consultant3:---
    user:1005:rwx #effective:rw-
    group::rwx #effective:rw-
    group:consultant1:r--
    group:2210:rwx #effective:rw-
    mask::rw-
    other::---

Breakdown:

  • Commented Entries
    • # file: File name

    • # owner: File owner

    • # group: Group owner

  • User Entries
    • user::rwx → File owner permissions

    • user:consultant3:--- → Named user (no permissions)

    • user:1005:rwx #effective:rw- → Named user limited by mask

  • Group Entries
    • group::rwx #effective:rw- → Group owner limited by mask

    • group:consultant1:r-- → Named group (read-only)

    • group:2210:rwx #effective:rw- → Named group limited by mask

  • Mask Entry
    • mask::rw- → Maximum allowed permissions for named users/groups

  • Other Entry
    • other::--- → No permissions for anyone else

Viewing Directory ACLs

Use getfacl to display ACLs:

  • [user@host content]$ getfacl .
    # file: .
    # owner: user
    # group: operators
    # flags: -s-
    user::rwx
    user:consultant3:---
    group::rwx
    group:consultant1:r-x
    mask::rwx
    other::---
    default:user::rwx
    default:group::rwx
    default:mask::rwx
    default:other::---
  • The execute (x) permission allows directory traversal/search.

  • Default ACLs determine permissions for newly created files or subdirectories.

Breakdown:

  • default:user::rwx → Default owner permissions

  • default:user:name:rx → Default named user permissions

  • default:group::rwx → Default group permissions

  • default:mask::rwx → Maximum default permissions

  • default:other::--- → No permissions for others

Default ACLs do not grant access to the directory itself, they define inheritance rules for new files/subdirectories.

ACL Mask

The ACL mask defines the maximum permissions possible for:

  • Named users

  • The group owner

  • Named groups

It does not affect the file owner or “others”.

  • View mask: getfacl file

  • Set mask: setfacl -m m::perms file

When ACLs change, the mask is recalculated automatically unless you use the -n flag or explicitly redefine it.

ACL Permission Precedence

When a process accesses a file:

  • If user = owner → use file owner ACL

  • If user matches named user entry → use that entry (limited by mask)

  • If group matches group owner or named group → use that group’s ACL (limited by mask)

  • Else → apply the other ACL

Changing ACL Permissions

The setfacl command is used to add, modify, or remove ACLs.

CommandPurpose
setfacl -m u:name:rX fileAdd or modify a user ACL
setfacl -m g:name:rw fileAdd or modify a group ACL
setfacl -m o::- fileModify other permissions
setfacl -m u::rwx,g:consultants:rX,o::- fileCombine multiple entries in one command
getfacl file-A | setfacl --set-file=- file-BUse getfacl output as input to copy ACLs between files
setfacl -m m::r fileSet explicit ACL mask (restrict named users and groups to read-only)
setfacl -R -m u:name:rX directoryApply ACL recursively; uppercase X sets execute only on directories
setfacl -x u:name,g:name fileRemove specific ACL entries
setfacl -b fileRemove all ACLs from a file
setfacl -m d:u:name:rx directorySet default ACLs on directories (files inherit permissions; directories get execute if x included)
setfacl -x d:u:name directoryDelete a specific default ACL entry
setfacl -k directoryDelete all default ACLs on a directory
getfacl fileView ACLs
setfacl -mModify/add ACLs
setfacl -xDelete specific ACL entries
setfacl -bRemove all ACLs
setfacl -kRemove all default ACLs
setfacl -RApply changes recursively
mount -o aclEnable ACL support on mount

Monitoring and Managing Linux Processes

Linux Process

A process is a running instance of a program. When you launch an executable, Linux creates a process for it.

A process includes:

  • Allocated memory space

  • Security details (user, group, privileges)

  • One or more execution threads

  • A unique Process ID (PID)

Every process is started by another process, called its parent, identified by the Parent Process ID (PPID).

The first process on a Linux system is systemd, and all others are its descendants.

When a new process is created, the parent duplicates itself using fork(), and the new child may replace its program using exec().

After finishing, the child exits, and the parent removes its record from the process table.

Process States

In a multitasking OS, each CPU runs only one process at a time.

Linux assigns every process a state based on what it’s doing.

StateFlagDescription
RunningRThe process is currently running or ready to run.
SleepingSWaiting for an event, resource, or signal.
Uninterruptible SleepDWaiting for hardware or I/O; cannot be interrupted.
StoppedTSuspended (for debugging or via signal like Ctrl+Z).
ZombieZProcess finished but not yet removed from the process table.

You can view process states in the S column of top or the STAT column of ps

Viewing Processes in Linux

The ps command (Process Status) displays details about currently running processes which includes user, PID, parent process, CPU/memory usage, state, and command name.

CommandDescription
ps auxBSD-style full listing (shows all users and processes).
ps -efUNIX/POSIX-style full listing of all processes.
ps --forestDisplays processes in a tree view (parent → child relationships).
ps -eo pid,user,%cpu,%mem,cmdShows custom columns (script-friendly).
--sortSorts output (e.g., --sort=-%mem for top memory consumers).
pstreeDisplays all running processes in a tree-like hierarchical structure.
topDisplays real-time, dynamic process information including CPU and memory usage.

Example:

  • $ ps -ef
    UID        PID  PPID  C STIME TTY      TIME CMD
    root        1     0  0 17:45 ?        0:03 /usr/lib/systemd/systemd
    root        2     0  0 17:45 ?        0:00 [kthreadd]
    root     2149     1  0 18:07 pts/0    0:00 bash
    user     2205  2149  0 18:08 pts/0    0:00 ps -ef
    
    • UNIX/POSIX-style with UID, PID, PPID, STIME, CMD columns.
  • $ ps aux
    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root         1  0.0  0.1  51648  7504 ?        Ss   17:45   0:03 /usr/lib/systemd/systemd
    root         2  0.0  0.0      0     0 ?        S    17:45   0:00 [kthreadd]
    student   2149  0.0  0.2 266904 3836 pts/0    R+   18:07   0:00 ps aux
    
    • BSD-style format with %CPU, %MEM, VSZ/RSS columns.
  • $ ps --forest
    PID    TTY      STAT   TIME COMMAND
    2149   pts/0    Ss     0:00 bash
    2205   pts/0    R+     0:00 \_ ps --forest
    
    • Shows hierarchical (parent → child) relationships.

  • $ pstree
    systemd─┬─NetworkManager
            ├─sshd───bash───ps
            └─cron
    
    • Displays process hierarchy as a tree.

  • $ ps -eo pid,user,%mem,cmd --sort=-%mem | head -n 10
    • Shows the top 10 memory-consuming processes.

Jobs and Sessions

Job control is a feature of the shell that allows a single shell instance to run and manage multiple commands.

What is a Job?

  • A job is associated with each pipeline entered at a shell prompt.

  • All processes in that pipeline belong to the same process group.

  • A single command is treated as a minimal pipeline, creating a job with only one member.

Foreground vs Background Processes

  • Only one job can read input and keyboard-generated signals from a terminal at a time.

  • Processes in this job are foreground processes of that terminal.

  • Background processes:

    • Cannot read input from the terminal.

    • May still write output to the terminal.

    • Can be running or stopped (suspended).

  • A background process attempting to read input will automatically be suspended.

Sessions

  • Each terminal is its own session with:

    • A foreground process.

    • Any number of background processes.

  • A job belongs to exactly one session (its controlling terminal).

  • Processes started by the system (e.g., daemons) have no controlling terminal. In ps, they show ? in the TTY column.

Running Jobs in the Background

  • Append an ampersand & to run a command or pipeline in the background:

  • [user@host ~]$ sleep 10000 & [1] 5947
    [user@host ~]$

Listing Jobs

  • Use the jobs command to see jobs being tracked by Bash:
  • [user@host ~]$ jobs
    [1]+ Running sleep 10000
    [user@host ~]$

Foreground a background job

  • [user@host ~]$ fg %1
    sleep 10000

Suspend a foreground process

  • Press Ctrl+Z
  • sleep 10000
    ^Z
    [1]+ Stopped sleep 10000
  • The shell warns users who try to exit a terminal with suspended jobs. Exiting again kills suspended jobs.

Resume suspended process in background

  • [user@host ~]$ bg %1
    [1]+ sleep 10000 &

Viewing Jobs

  • ps j command shows process, job, and session info
  • [user@host ~]$ ps j
    PPID  PID   PGID  SID   TTY    TPGID STAT  UID  TIME  COMMAND
    2764  2768  2768  2768  pts/0  6377  Ss    1000 0:00 /bin/bash
    2768  5947  5947  2768  pts/0  6377  T     1000 0:00 sleep 10000
    2768  6377  6377  2768  pts/0  6377  R+    1000 0:00 ps j
    
FieldMeaning
PIDProcess ID
PPIDParent Process ID
PGIDProcess Group ID (job leader)
SIDSession ID (usually the interactive shell)
STATProcess state (e.g., T = stopped)
Killing Processes

A signal is a software interrupt delivered to a process, reporting events such as errors, external events (I/O requests, expired timers), or explicit commands/keyboard sequences.

Signal NoShort NameDefinition / Purpose
1HUPHangup; report termination of the controlling process of a terminal or request process reinitialization (e.g., config reload).
2INTKeyboard interrupt; causes program termination. Sent via Ctrl+C.
3QUITKeyboard quit; similar to SIGINT but generates a core dump. Sent via Ctrl+\.
9KILLUnblockable; causes abrupt program termination. Cannot be blocked, ignored, or handled.
15TERMDefault terminate; polite way to ask a program to exit. Can be blocked or handled by the process.
18CONTContinue; resume a stopped process. Cannot be blocked.
19STOPStop; unblockable suspend of a process.
20TSTPKeyboard stop; similar to STOP but can be blocked or handled. Sent via Ctrl+Z.

Default Signal Actions

  • Term – terminate process immediately.

  • Core – terminate process and save memory image (core dump).

  • Stop – suspend process, wait to continue (resume).

Sending Signals to Processes using Keyboard

  • Ctrl+C – SIGINT

  • Ctrl+Z – SIGTSTP (suspend)

  • Ctrl+\ – SIGQUIT (core dump)

Sending Signals to Processes using Commands

  • kill – send a signal to a process by PID.

  • [user@host ~]$ kill -l
     1) SIGHUP   2) SIGINT   3) SIGQUIT   4) SIGILL   5) SIGTRAP
     6) SIGABRT  7) SIGBUS   8) SIGFPE    9) SIGKILL 10) SIGUSR1
    11) SIGSEGV 12) SIGUSR2 13) SIGPIPE  14) SIGALRM 15) SIGTERM
    16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP

Example

  • [user@host ~]$ ps aux | grep job
    5194  0.0  0.1  222448  2980 pts/1  S  16:39  0:00  /bin/bash control job1
    5199  0.0  0.1  222448  3132 pts/1  S  16:39  0:00  /bin/bash control job2
    5205  0.0  0.1  222448  3124 pts/1  S  16:39  0:00  /bin/bash control job3
    
    [user@host ~]$ kill 5194
    [1] Terminated control job1
    
    [user@host ~]$ kill -9 5199
    [2]- Killed control job2
    
    [user@host ~]$ kill -SIGTERM 5205
    [3]+ Terminated control job3
    
  • killall – signal multiple processes by command name.

    • killall control → This is an example command, here control is the command name
  • pkill – signal processes based on command name, UID, GID, terminal, parent PID, etc.

    • [user@host ~]$ pkill control
      [1] Terminated control pkill1
      [2]- Terminated control pkill2
      [3]+ Terminated control pkill3
      

Logging Users Out Administratively

  • Identify login sessions with w:

    • [user@host ~]$ w
      USER  TTY FROM             LOGIN@  IDLE  JCPU  PCPU  WHAT
      root  tty2                12:26   14:58  0.04s 0.04s -bash
      bob   tty3                12:28   14:42  0.02s 0.02s -bash
      user  pts/1  desk.example.com 12:41  2.00s 0.03s 0.03s w
  • Terminate processes by user:

    • [root@host ~]# pgrep -l -u bob
      6964 bash
      6998 sleep
      6999 sleep
      [root@host ~]# pkill -SIGKILL -u bob
      [root@host ~]# pgrep -l -u bob
      # No processes remain
      
  • Terminate processes by terminal:

    • [root@host ~]# pkill -t tty3
      [root@host ~]# pkill -SIGKILL -t tty3
      
  • Terminate child processes using parent PID:
    • [root@host ~]# pstree -p bob
      bash(8391)─┬─sleep(8425)
                 ├─sleep(8426)
                 └─sleep(8427)
      [root@host ~]# pkill -P 8391      # Kill all children of bash
      [root@host ~]# pkill -SIGKILL -P 8391
      
Monitoring Process Activity

Load average is a measurement provided by the Linux kernel that represents the perceived system load over time. It gives a rough gauge of how many system resource requests are pending and whether system load is increasing or decreasing.

Every five seconds, the kernel collects the current load number based on the number of processes in runnable (R) and uninterruptible (D) states.

This number is then reported as an exponential moving average over the most recent 1, 5, and 15 minutes.

Commands That Show Load Average

  • uptime

  • w

  • top

Load Average Calculation

  • The load average represents how many processes are ready to run or waiting for I/O (disk/network).

  • The value includes:

    • Processes waiting for CPU (state R)

    • Processes waiting for I/O completion (state D)

  • If load averages are high while CPU activity is low, check for heavy disk or network activity.

  • You can view the current load average using the uptime command:

    • [user@host ~]$ uptime
      15:29:03 up 14 min, 2 users, load average: 2.92, 4.48, 5.20
      
  • The three numbers represent the load over the last 1, 5, and 15 minutes.

Per-CPU Load

  • If load mainly comes from CPU-bound processes, divide the load average by the number of logical CPUs to check whether the system is overloaded.
  • Use lscpu to determine CPU count:
    • [user@host ~]$ lscpu
      Architecture:           x86_64
      CPU op-mode(s):         32-bit, 64-bit
      Byte Order:             Little Endian
      CPU(s):                 4
      On-line CPU(s) list:    0-3
      Thread(s) per core:     2
      Core(s) per socket:     2
      Socket(s):              1
      NUMA node(s):           1
      ...output omitted...
      
  • This is a 4 logical CPU system (2 cores × 2 threads).
  • Now divide the load average by 4:
    • Load average: 2.92, 4.48, 5.20
    • Number of logical CPUs: 4
    • Per-CPU load (Load average ÷ CPUs): 0.73, 1.12, 1.30
  • Interpretation:
    • – 0.73 (1 min): CPUs ~73% utilized, normal.
    • – 1.12 (5 min): ~112% utilized, ~12%overloaded.
    • – 1.30 (15 min): ~130% utilized, ~30%overloaded.
  • A load value of 0 = idle CPU queue (no waiting processes).

  • A load value of 1 = one process actively using a CPU (no wait).

  • Load increases as more processes wait for CPU or I/O.

  • Processes waiting for I/O also increase the load average, even if CPU usage is low, since they represent blocked tasks.
  • A load average below 1 (per CPU) means the system is performing efficiently.
  • Once utilization approaches 100%, new processes must wait, and load numbers climb above 1.

Real-Time Process Monitoring

  • The top program provides a continuously updating view of active processes.
  • Unlike ps, top updates dynamically at a configurable interval.
ColumnDescription
PIDProcess ID
USEROwner of the process
VIRTTotal virtual memory used (includes code, data, shared libs, and swapped pages), same as VSZ in ps
RESPhysical resident memory (same as RSS in ps)
SProcess state:
• D = Uninterruptible sleep
• R = Running
• S = Sleeping
• T = Stopped/Traced
• Z = Zombie
TIMETotal CPU time used since process start
COMMANDProcess command name

Fundamental Keystrokes in top

KeyPurpose
? or hHelp for interactive keystrokes
l, t, mToggle load, threads, or memory header lines
1Show individual CPU stats or a combined summary
sChange refresh rate (e.g., 0.5, 1, 5 seconds)
bToggle reverse highlight for running processes
Shift + bEnable bold display for header and running processes
Shift + hToggle between processes and threads view
u, Shift + uFilter by user name
Shift + mSort by memory usage (descending)
Shift + pSort by CPU usage (descending)
kKill a process (prompt for PID and signal) (not available in secure mode)
rRenice a process (prompt for PID and nice value) (not available in secure mode)
Shift + wSave display configuration for next run
qQuit top
fManage columns (enable/disable fields and change sort order)
Process Scheduling

Different processes have different levels of importance.

  • Scheduling policies: Most processes run under SCHED_OTHER (or SCHED_NORMAL).

  • Nice value: Determines relative priority.

Nice level range:

  • -20 → highest priority

  • 0 → default

  • 19 → lowest priority

Rules:

  • Higher nice level → less CPU priority (process gives up CPU easily).

  • Lower nice level → higher CPU priority.

  • If there are fewer processes than CPUs, even high nice level processes get full CPU time.

Nice Levels

  • Only root may reduce a process nice level.

  • Unprivileged users can only increase the nice level of their own processes(max 19.

  • Reporting Nice Levels Using top
    • The NI column → process nice value
    • The PR column → scheduled priority
    •  Example:
      • Nice -20 → PR 0
      • Nice 19 → PR 39
  • Reporting Nice Levels Using ps
  • [user@host ~]$ ps axo pid,comm,nice,cls --sort=-nice
    PID COMMAND       NI CLS
    30  khugepaged    19 TS
    29  ksmd          5  TS
    1   systemd       0  TS
    2   kthreadd      0  TS
    9   ksoftirqd/0   0  TS
    10  rcu_sched     0  TS
    11  migration/0   -  FF
    12  watchdog/0    -  FF
    
  • TS → SCHED_NORMAL

  • → other scheduling policies

Starting Processes with Different Nice Levels

  • Inherit nice level from shell
    • [user@host ~]$ sha1sum /dev/zero &
      [1] 3480
      [user@host ~]$ ps -o pid,comm,nice 3480
      PID COMMAND NI
      3480 sha1sum 0
  • Using nice command (default 10)
    • [user@host ~]$ nice sha1sum /dev/zero &
      [1] 3517
      [user@host ~]$ ps -o pid,comm,nice 3517
      PID COMMAND NI
      3517 sha1sum 10
  • Using nice -n for custom nice level
    • [user@host ~]$ nice -n 15 sha1sum &
      [1] 3521
      [user@host ~]$ ps -o pid,comm,nice 3521
      PID COMMAND NI
      3521 sha1sum 15
  • Changing the Nice Level of an Existing Process Using renice
    • [user@host ~]$ renice -n 19 3521
      3521 (process ID) old priority 15, new priority 19

Controlling Services and Daemons

Introduction To Systemd
  • systemd manages startup and services in Linux, including activation of system resources, daemons, and processes.

  • Daemons run in the background, usually starting automatically at boot.

  • Many daemon names end with ‘d’ (e.g., sshd, crond).

  • A service in systemd may be a daemon or a one-time action (called oneshot).

Unit TypeExtensionDescription
Service.serviceRepresents a system service or daemon managed by systemd.
Socket.socketMonitors an IPC socket and automatically starts the corresponding service when a connection request arrives.
Path.pathStarts a service when a specific file or directory is created, modified, or deleted.
  • To view available unit types:
    • systemctl -t help

Listing Services

  • List all loaded and active services
    • [root@host ~]# systemctl list-units --type=service
      UNIT                      LOAD   ACTIVE SUB     DESCRIPTION
      atd.service               loaded active running Job spooling tools
      auditd.service            loaded active running Security Auditing Service
      chronyd.service           loaded active running NTP client/server
      crond.service             loaded active running Command Scheduler
      dbus.service              loaded active running D-Bus System Message Bus
      getty@tty1.service        loaded active running Getty on tty1
      NetworkManager.service    loaded active running Network Manager
      systemd-journald.service  loaded active running Journal Service
      systemd-logind.service    loaded active running Login Service
      systemd-udevd.service     loaded active running Rule-based Manager for Device Events and Files
      ...output truncated...
      
    • UNIT – Service unit name

    • LOAD – Whether systemd loaded it into memory

    • ACTIVE – High-level activation state

    • SUB – Detailed low-level state

    • DESCRIPTION – Short explanation of the service

  • List all services including inactive
    • systemctl list-units --type=service --all
  • List installed service unit files and their enablement state
    • [root@host ~]# systemctl list-unit-files --type=service
      UNIT FILE                     STATE
      arp-ethers.service            disabled
      atd.service                   enabled
      auditd.service                enabled
      auth-rpcgss-module.service    static
      autovt@.service               enabled
      blk-availability.service      disabled
      ...output omitted...
      
    • Common states in the STATE column:

      • enabled – Starts at boot

      • disabled – Doesn’t start automatically

      • static – Cannot be enabled; started by dependency

      • masked – Completely disabled

Viewing Service Status

  • To check the status of the specific service, systemctl status <service_name>
    • [root@host ~]# systemctl status sshd.service
      ● sshd.service - OpenSSH server daemon
         Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled)
         Active: active (running) since Fri 2025-10-24 12:07:45 IST; 2h 13min ago
       Main PID: 1073 (sshd)
          Tasks: 1 (limit: 2366)
         Memory: 3.4M
         CGroup: /system.slice/sshd.service
                 └─1073 /usr/sbin/sshd -D
      
      Oct 24 12:07:45 host.example.com systemd[1]: Started OpenSSH server daemon.
      Oct 24 12:07:45 host.example.com sshd[1073]: Server listening on 0.0.0.0 port 22.
      Oct 24 12:07:45 host.example.com sshd[1073]: Server listening on :: port 22.
      
    • Loaded: Whether the service unit file is parsed and loaded.

    • Active: Indicates if the service is running and for how long.

    • Main PID: Process ID of the main daemon.

    • Status Messages: Show recent service logs or events.

Status KeywordMeaning
loadedUnit configuration file processed.
active (running)Service is currently running.
active (exited)One-time task completed successfully.
inactiveService is not running.
enabledService is configured to start at boot.
disabledService is not configured to start at boot.
staticService is automatically started by another unit.

Verifying Service State

CommandDescriptionExample Output
systemctl is-active sshd.serviceCheck if service is runningactive
systemctl is-enabled sshd.serviceCheck if starts at bootenabled
systemctl is-failed sshd.serviceCheck if failed during startupactive / failed
systemctl --failed --type=serviceList all failed servicesDisplays failed unit names

Starting and Stopping Services

Services may need to be manually started or stopped for updates, configuration changes, or other administrative reasons.

  • Start a service:

    • [root@host ~]# systemctl start sshd.service
  • Stop a service:
    • [root@host ~]# systemctl stop sshd.service

Restarting and Reloading Services

  • Restart a service: stops and then starts the service (new PID assigned)
    • [root@host ~]# systemctl restart sshd.service
  • Reload a service: applies configuration changes without changing the PID
    • [root@host ~]# systemctl reload sshd.service
  • Reload or restart if reload not supported:
    • [root@host ~]# systemctl reload-or-restart sshd.service

Listing Unit Dependencies

Some services depend on others to function. Use the following commands:

  • List dependencies for a service:

    • [root@host ~]# systemctl list-dependencies sshd.service
      sshd.service
      ● ├─system.slice
      ● ├─sshd-keygen.target
      ● │ ├─sshd-keygen@ecdsa.service
      ● │ ├─sshd-keygen@ed25519.service
      ● │ └─sshd-keygen@rsa.service
      ● └─sysinit.target
  • List reverse dependencies:

    • [root@host ~]# systemctl list-dependencies --reverse sshd.service

Masking and Unmasking Services

Masking prevents a service from starting manually or automatically.

A disabled service can be started manually.

A masked service cannot start manually or automatically.

  • Mask a service:

    • [root@host ~]# systemctl unmask sendmail
      Removed /etc/systemd/system/sendmail.service.
  • Unmask a service:
    • [root@host ~]# systemctl unmask sendmail
      Removed /etc/systemd/system/sendmail.service.

Enabling and Disabling Services at Boot

  • Enable a service to start at boot:

    • [root@host ~]# systemctl enable sshd.service
      Created symlink /etc/systemd/system/multi-user.target.wants/sshd.service → /usr/lib/systemd/system/sshd.service
      
  • Disable a service from starting at boot:
    • [root@host ~]# systemctl disable sshd.service
      Removed /etc/systemd/system/multi-user.target.wants/sshd.service
      

Useful systemctl Commands

TaskCommand
View detailed unit statesystemctl status UNIT
Stop a servicesystemctl stop UNIT
Start a servicesystemctl start UNIT
Restart a servicesystemctl restart UNIT
Reload a service configurationsystemctl reload UNIT
Mask a service (disable manually and at boot)systemctl mask UNIT
Unmask a servicesystemctl unmask UNIT
Enable a service at bootsystemctl enable UNIT
Disable a service at bootsystemctl disable UNIT
List dependencies of a unitsystemctl list-dependencies UNIT
Adjusting Tuning Profiles

The tuned service optimizes system performance by applying predefined tuning profiles. These profiles adjust kernel parameters, CPU behavior, disk settings, and network tuning based on workload type.

Static Tuning

  • Applies predefined kernel and system settings.

  • Settings do not change based on system load.

  • Suitable for predictable workloads.

Dynamic Tuning

  • The tuned daemon monitors system activity.

  • Adjusts settings dynamically at runtime.

  • Useful when workloads vary (e.g., storage bursts, busy hours).

Installing and Enabling tuned

To install manually:

  • yum install tuned
    systemctl enable --now tuned

Check service status:

  • systemctl status tuned

Available Tuning Profiles

Tuned includes multiple profiles optimized for different workloads.

ProfilePurpose
balancedDefault. Good balance between performance & power saving.
desktopFaster response for interactive desktop workloads.
throughput-performanceMaximum I/O and CPU throughput.
latency-performanceLow-latency tuning for servers; higher power usage.
network-latencyLow latency for network workloads (derived from latency-performance).
network-throughputMaximum network throughput.
powersaveAggressive power saving.
oracleOptimized for Oracle databases.
virtual-guestOptimizes performance for virtual machines.
virtual-hostOptimizes systems acting as hypervisors.

Managing Tuning Profiles

  • View the active profile

    • [root@host ~]# tuned-adm active
      Current active profile: virtual-guest
  • List all available profiles

    • [root@host ~]# tuned-adm list
      Available profiles:
      - balanced
      - desktop
      - latency-performance
      - network-latency
      - network-throughput
      - powersave
      - sap
      - throughput-performance
      - virtual-guest
      - virtual-host
      Current active profile: virtual-guest
  • Switch to a different profile

    • [root@host ~]$ tuned-adm profile throughput-performance
      [root@host ~]$ tuned-adm active
      Current active profile: throughput-performance
  • Let tuned recommend the best profile

    • [root@host ~]$ tuned-adm recommend
      virtual-guest
  • Disable tuned

    • [root@host ~]$ tuned-adm off
      [root@host ~]$ tuned-adm active
      No current active profile.

Managing SELinux

SELinux (Security-Enhanced Linux) adds an extra layer of security by controlling access to files, directories, and ports at a granular level. Unlike standard file permissions, SELinux policies prevent processes from misusing resources even if a user has read/write access.

SELinux enforces rules through policies, which define what actions are allowed for each process and file.

Policies are enforced using labels (user, role, type, sensitivity).

SELinux Modes

SELinux can operate in three modes:

  • Enforcing: Access control rules are enforced (default).

  • Permissive: Rules are not enforced; violations are logged.

  • Disabled: SELinux is completely turned off (not recommended).

Check current mode:

  • [user@host ~]# getenforce
    Enforcing
    

Change mode temporarily:

  • [user@host ~]# setenforce 0    # Permissive
    [user@host ~]# setenforce 1    # Enforcing
    

Set default SELinux mode permanently in /etc/selinux/config:

  • SELINUX=enforcing        # options: enforcing, permissive, disabled
    SELINUXTYPE=targeted     # targeted processes are protected
    

SELinux Security Concepts

  • SELinux implements Mandatory Access Control (MAC), complementing traditional user/group permissions (Discretionary Access Control, DAC).

  • Every file, process, directory, and port has an SELinux context that determines access permissions.

  • The targeted policy is default in RHEL, enforcing rules primarily based on the type context.

Working with SELinux Contexts

Display SELinux contexts with the -Z option

Check all processes:

  • [user@host ~]# ps axZ
    LABEL                               PID TTY STAT TIME COMMAND
    system_u:system_r:init_t:s0          1 ? Ss 0:09 /usr/lib/systemd/...
    system_u:system_r:kernel_t:s0       2 ? S  0:00 [kthreadd]
    system_u:system_r:kernel_t:s0       3 ? S  0:00 [ksoftirqd/0]
    

Check Apache processes:

  • [user@host ~]# ps -ZC httpd
    LABEL                           PID TTY TIME CMD
    system_u:system_r:httpd_t:s0   1608 ? 00:00:05 httpd
    system_u:system_r:httpd_t:s0   1609 ? 00:00:00 httpd
    

Check SELinux labels on files:

  • [user@host ~]# ls -Z /var/www
    drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin
    drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
    drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 icons
    

SELinux File Context Example:

  • system_u:object_r:httpd_sys_content_t:s0 html
SELinux Context FieldValueDescription
SELinux Usersystem_uSystem-managed SELinux user; applied to system files and processes.
Roleobject_rRole of the object; determines which domains can access this object. Default for most files.
Type (Domain)httpd_sys_content_tType defines the kind of object; here it represents web server content files. Apache (httpd_t) can access it.
Level / Sensitivitys0Security level for MLS (mandatory access control). Default level in standard RHEL policies.
File/DirectoryhtmlThe actual file or directory being labeled.

Initial SELinux Context

  • All processes and files on SELinux-enabled systems are labeled with a SELinux context.

  • New files inherit the SELinux context from the parent directory.

  • Pitfalls:

    • Moving a file retains the context of the original directory.

    • Copying a file with cp -a preserves the original context.

  • Example:
    • # Files created in /tmp
      [root@host ~]# touch /tmp/file1 /tmp/file2
      [root@host ~]# ls -Z /tmp/file*
      unconfined_u:object_r:user_tmp_t:s0 /tmp/file1
      unconfined_u:object_r:user_tmp_t:s0 /tmp/file2
      
      # Move and copy to /var/www/html
      [root@host ~]# mv /tmp/file1 /var/www/html/
      [root@host ~]# cp /tmp/file2 /var/www/html/
      [root@host ~]# ls -Z /var/www/html/file*
      unconfined_u:object_r:user_tmp_t:s0 /var/www/html/file1   # moved file retains old context
      unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/file2  # copied file inherits directory context
      

Changing SELinux Context

  • chcon: Temporarily changes the context of a file (does not survive restorecon or relabeling).

  • restorecon: Resets file context to the default based on policy.

  • semanage fcontext: Defines default contexts for files and directories. Use with restorecon to apply.

  • Example:
    • # Create a directory
      [root@host ~]# mkdir /virtual
      [root@host ~]# ls -Zd /virtual
      drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /virtual
      
      # Change context temporarily
      [root@host ~]# chcon -t httpd_sys_content_t /virtual
      [root@host ~]# ls -Zd /virtual
      drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 /virtual
      
      # Restore default context
      [root@host ~]# restorecon -v /virtual
      Relabeled /virtual from unconfined_u:object_r:httpd_sys_content_t:s0 to unconfined_u:object_r:default_t:s0
      

Defining Default File Context Rules

  • semanage fcontext manages rules that restorecon uses.

  • Common syntax: /path(/.*)? → applies to the directory and everything inside recursively.

  • Basic Operations:

OptionDescription
-aAdd a new file context rule.
-dDelete a file context rule.
-lList existing file context rules.
  • Example: Applying Default Context to Files in /var/www/html

    • # Check current file contexts
      [root@host ~]# ls -Z /var/www/html/file*
      unconfined_u:object_r:user_tmp_t:s0 /var/www/html/file1
      unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/file2
      
      # List fcontext rules
      [root@host ~]# semanage fcontext -l
      /var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
      
      # Apply rules
      [root@host ~]# restorecon -Rv /var/www/
      Relabeled /var/www/html/file1 from unconfined_u:object_r:user_tmp_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0
      [root@host ~]# ls -Z /var/www/html/file*
      unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/file1
      unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/file2
      
  • Example: Adding a New Directory

    • [root@host ~]# mkdir /virtual
      [root@host ~]# touch /virtual/index.html
      [root@host ~]# ls -Zd /virtual/
      drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /virtual/
      [root@host ~]# semanage fcontext -a -t httpd_sys_content_t '/virtual(/.*)?'
      [root@host ~]# restorecon -RFvv /virtual
      [root@host ~]# ls -Zd /virtual/
      drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /virtual/
      [root@host ~]# ls -Z /virtual/
      -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html
      
SELinux Booleans

SELinux booleans are configurable switches that allow administrators to adjust how SELinux policies behave without rewriting the policies themselves.
They make it possible to enable or disable specific SELinux features dynamically.

CommandDescription
getsebool -aLists all SELinux booleans and their current states (on or off).
getsebool <boolean_name>Displays the state of a specific boolean.
setsebool <boolean_name> on/offTemporarily changes a boolean’s state (until reboot).
setsebool -P <boolean_name> on/offPermanently changes a boolean’s state (persists across reboots).
semanage boolean -lLists all booleans with descriptions and persistence status.
semanage boolean -l -CLists only booleans whose current state differs from the default.

Example:

  • [user@host ~]$ getsebool httpd_enable_homedirs
    httpd_enable_homedirs --> off
    
    [user@host ~]$ sudo setsebool httpd_enable_homedirs on
    
    [user@host ~]$ sudo semanage boolean -l | grep httpd_enable_homedirs
    httpd_enable_homedirs (on , off) Allow httpd to enable homedirs
    
    [user@host ~]$ sudo setsebool -P httpd_enable_homedirs on
    
    [user@host ~]$ sudo semanage boolean -l | grep httpd_enable_homedirs
    httpd_enable_homedirs (on , on) Allow httpd to enable homedirs
    
    [user@host ~]$ sudo semanage boolean -l -C
    SELinux boolean              State       Default    Description
    cron_can_relabel             (off , on)  Allow cron to relabel
    
Troubleshooting SELinux Issues

When SELinux prevents access to files or services that should be accessible, follow these steps:

1. Verify Legitimate Denial

Before changing SELinux settings, confirm whether the denial is valid.
Example: If Apache (httpd) tries to access /home, SELinux may be correctly preventing access to user directories.

2. Check File Contexts

The most common issue is incorrect file labeling (context mismatch).
If a file was moved from one directory to another, its context might be wrong.

Fix using:

  • restorecon -Rv /path/to/file_or_directory

This command resets the context to the correct default.

3. Adjust SELinux Booleans

If access is still denied, you may need to enable a boolean that allows the desired behavior.
Example:

  • sudo setsebool -P ftpd_anon_write on

This enables anonymous FTP uploads.

4. Policy Bug (Rare)

If you suspect an SELinux policy bug is preventing legitimate access, contact Red Hat Support.

Using setroubleshoot

Install and use the setroubleshoot-server tool to analyze SELinux denials:

  • sudo dnf install setroubleshoot-server

This service monitors /var/log/audit/audit.log and sends summaries to /var/log/messages.

CommandDescription
sealert -l <UUID>View detailed info for a specific SELinux violation.
sealert -a /var/log/audit/audit.logAnalyze all audit logs for SELinux issues.
ausearch -m AVC -ts recentSearch for recent SELinux denials.

Example Scenario

A file was moved into the web root, but Apache can’t access it:

  • [root@host ~]# touch /root/file3
    [root@host ~]# mv /root/file3 /var/www/html
    [root@host ~]# systemctl start httpd
    [root@host ~]# curl http://localhost/file3
    

    Result: 403 Forbidden

Inspect Audit Logs

  • [root@host ~]# tail /var/log/audit/audit.log
    ...output omitted...
    type=AVC msg=audit: avc: denied { getattr } for pid=1609 comm="httpd" path="/var/www/html/file3"
    scontext=system_u:system_r:httpd_t:s0
    tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file
    ...output omitted...
    

Check Human-Readable Message

  • [root@host ~]# tail /var/log/messages
    ...output omitted...
    host setroubleshoot: SELinux is preventing /usr/sbin/httpd
    from getattr access on the file . For complete SELinux messages. run
    sealert -l 613ca624-248d-48a2-a7d9-d28f5bbe2763
    

Analyze with sealert

  • [root@host ~]# sealert -l 613ca624-248d-48a2-a7d9-d28f5bbe2763
    

Output suggests generating a local policy module or restoring context.

Fix the file context:

  • [root@host ~]# restorecon /var/www/html/file3
    

Or recursively:

  • [root@host ~]# restorecon -R /var/www/
    

Analyzing and Storing Logs

Linux records important system and application events as logs. These logs help in auditing, monitoring, and troubleshooting.

RHEL uses systemd-journald and rsyslog together:

  • systemd-journald is a central logging service which collects logs from Kernel, Boot process, Daemon stdout/stderr and Syslog messages. It stores logs in a structured journal, which by default does not persist across reboots.

  • rsyslog reads syslog messages from journald. It sorts and writes persistent logs under /var/log. It routes logs to files based on Facility (type of program) and Priority (error level).

Some applications create their own logs directly under /var/log/<appname>/.

Example: Apache writes logs in /var/log/httpd/

Log FilePurpose
/var/log/messagesGeneral system messages (except auth, mail, cron).
/var/log/secureAuthentication & security-related messages.
/var/log/maillogMail server logs.
/var/log/cronScheduled job execution logs.
/var/log/boot.logBoot-time console messages.
Reviewing Syslog Files

Syslog messages have priorities (severity levels) from 0 to 7:

CodePriorityMeaning
0emergSystem is unusable
1alertImmediate action required
2critCritical condition
3errError condition
4warningWarning
5noticeSignificant normal event
6infoInformational
7debugDebugging messages

How rsyslog Handles Logs

  • rsyslog receives messages from systemd-journald.

  • Messages are sorted based on:

    • Facility (auth, cron, mail, etc.)

    • Priority (emerg–debug)

  • Rules stored in:
    • /etc/rsyslog.conf → The main rsyslog configuration file that defines core logging rules and global settings.
    • /etc/rsyslog.d/*.conf → A directory for additional module-based or service-specific logging rules. Files here override or extend the main configuration.
  • Each rule has:
    • facility.priority   action

Common rsyslog Rules:

#### RULES ####
# Log anything (except mail) with level info or higher.
# Don't log authentication or cron messages here.
*.info;mail.none;authpriv.none;cron.none    /var/log/messages

# Authentication logs (restricted access)
authpriv.*                                    /var/log/secure

# Mail server logs
mail.*                                        -/var/log/maillog

# Cron logs
cron.*                                        /var/log/cron

# Emergency messages → all logged-in users
*.emerg                                       :omusrmsg:*

# News/spooler critical messages
uucp,news.crit                                /var/log/spooler

# Boot messages
local7.*                                      /var/log/boot.log

These rules determine where different system logs are stored.

Log Rotation

logrotate manages rotating and compressing log files to save space.

  • Old logs are renamed (e.g., /var/log/messages-20240101)
  • New log file is created
  • Oldest logs are removed after a set number of rotations
  • Runs daily via a scheduled job

Understanding a Syslog Entry

Example from /var/log/secure:

Feb 11 20:11:48 localhost sshd[1433]: Failed password for student from 172.25.0.10 port 59344 ssh2
ComponentMeaning
Feb 11 20:11:48Timestamp
localhostHostname
sshd[1433]Program name & PID
Failed password…Actual log message

Monitoring Logs in Real Time

Use tail -f to view new log entries as they appear:

tail -f /var/log/secure

Useful for watching ssh logins, failed attempts, cron jobs, etc.

Sending Manual Syslog Messages

Use the logger command to generate log entries (useful for testing):

Example: send a message to /var/log/boot.log

logger -p local7.notice "Log entry created on host"
Systemd-journald & Journalctl

systemd-journald

  • systemd-journald stores logs in structured, indexed binary files called journals.

  • For syslog messages, extra metadata is stored (facility, priority, etc.).

  • Default RHEL  journal location: /run/log

    • This directory is cleared on reboot.

    • You can configure persistent logging later.

Viewing Logs with journalctl

FeatureDescriptionExample Command
View all logsShows entire system journaljournalctl
Show last 10 logsDefault tail-like viewjournalctl -n
Show last N logsSpecify number of linesjournalctl -n 5
Follow logsLive log streaming (Ctrl+C to stop)journalctl -f
Filter by priorityShow logs at a priority (debug, info, notice, warning, err, crit, alert, emerg) and abovejournalctl -p err
Logs since todayShow all logs from today’s datejournalctl --since today
Since specific date/timeFormat: “YYYY-MM-DD HH:MM:SS”journalctl --since "2019-02-10 20:30:00"
Until specific date/timeLimits the end timejournalctl --until "2019-02-13 12:00:00"
Relative timeTime expressions like last 1 hourjournalctl --since "-1 hour"
Verbose outputShow detailed journal metadatajournalctl -o verbose
Filter by command name_COMM = process namejournalctl _COMM=sshd
Filter by executable path_EXE = full path to binaryjournalctl _EXE=/usr/sbin/sshd
Filter by PID_PID = process IDjournalctl _PID=1182
Filter by UID_UID = user IDjournalctl _UID=0
Filter by systemd unit_SYSTEMD_UNIT = unit namejournalctl _SYSTEMD_UNIT=sshd.service
Combine filtersUse multiple fields for granular searchjournalctl _SYSTEMD_UNIT=sshd.service _PID=1182
Preserving the System Journal

By default, RHEL stores system journals in /run/log/journal.  This directory is volatil, where logs are cleared on reboot.

To make system journal entries persistent, modify the systemd-journald configuration.

Configuring Persistent Journals

Edit /etc/systemd/journald.conf and modify the Storage= parameter:

Storage OptionBehavior
persistentStores journals in /var/log/journal (survive reboot). Creates the directory if missing.
volatileStores journals in /run/log/journal (lost on reboot).
autoDefault. Uses persistent storage only if /var/log/journal exists.
noneNo local journal storage; logs only forwarded.
  1. Edit the config:
    • vim /etc/systemd/journald.conf
      [Journal]
      Storage=persistent
  2. Restart the service:

    • systemctl restart systemd-journald
  3. After restart, persistent journal files appear in:

    • /var/log/journal/[machine-id]/

Journal Size Limits

  • Journals rotate automatically (monthly).
  • Journals cannot exceed:
    • 10% of filesystem size, or
    • Reduce free space below 15%.
  • Limits configurable in:
    • /etc/systemd/journald.conf
  • Current limits can be checked with:
    • journalctl | grep -E 'Runtime|System journal'

Viewing Logs from Specific Boots

Only meaningful if the system has been rebooted multiple times.

Limit journalctl output by boot ID:

PurposeCommand
Show logs from current bootjournalctl -b
Show logs from first bootjournalctl -b 1
Show logs from second bootjournalctl -b 2
Maintaining Time Zones and Clocks

Accurate and synchronized time is essential for:

  • Log correlation between systems

  • Scheduled tasks

  • Security auditing

Systems typically sync time using NTP (Network Time Protocol) from public NTP servers or internal NTP servers.

NTP Synchronization controls the chronyd service. It can be Enabled and Disabled using the below command:

  • timedatectl set-ntp true
  • timedatectl set-ntp false

Checking Time and Time Zones

  • The timedatectl command shows an overview of the current time-related system settings, including current time, time zone, and NTP synchronization settings of the system.
    • [user@host ~]$ timedatectl
                     Local time: Mon 2025-03-10 14:25:32 IST
                 Universal time: Mon 2025-03-10 08:55:32 UTC
                       RTC time: Mon 2025-03-10 08:55:29
                      Time zone: Asia/Kolkata (IST, +0530)
      System clock synchronized: yes
                    NTP service: active
                RTC in local TZ: no
  • The timedatectl list-timezones command list all the time zones. If usure use tzselect this shows the correct time zone but does not change system settings.
    • [user@host ~]$ timedatectl list-timezones
      Africa/Abidjan
      Africa/Accra
      Africa/Addis_Ababa
      Africa/Algiers
      Africa/Asmara
      Africa/Bamako
      ...

Changing Time Zone

  • The timedatectl set-timezone <ZoneName> command is used to set the time zone
  • Example:
    • timedatectl set-timezone Africa/Accra
  • To set UTC:
    • timedatectl set-timezone UTC
  • The system time can be changed manually using the command timedatectl set-time "YYYY-MM-DD HH:MM:SS"
  • Example:
    • timedatectl set-time 09:00:00

Chronyd

chronyd is the daemon responsible for:

  • Syncing the system clock with NTP servers

  • Adjusting hardware clock drift

  • Maintaining accurate time when offline

NTP servers in chrony is configured using the configuration file /etc/chrony.conf

  • In /etc/chrony.conf:

    • server ntppool.example.com iburst
  • iburst enables fast initial synchronization.

  • Restart chronyd:

    • systemctl restart chronyd

NTP synchronization can be verified using the command chronyc sources or chronyc sources -v

Archiving and Transferring Files

Compressed TAR Archives

The tar command is used to:

  • Archive multiple files/directories into a single file.

  • Compress archives using gzip, bzip2, or xz.

  • List or extract the contents of archives.

A tar archive contains File data, Metadata, and Index allowing selective extraction

TAR Command Options

Operations and General Options

OptionDescription
-c, --createCreate a new archive.
-x, --extractExtract files from an archive.
-t, --listList the contents of an archive.
-v, --verboseShow processed files (verbose output).
-f, --file=<name>Specify archive file name.
-p, --preserve-permissionsPreserve permissions when extracting.

Compression Options

OptionDescription
-c, --createCreate a new archive.
-x, --extractExtract files from an archive.
-t, --listList the contents of an archive.
-v, --verboseShow processed files (verbose output).
-f, --file=<name>Specify archive file name.
-p, --preserve-permissionsPreserve permissions when extracting.

Creating, Listing and Extracting TAR Archives

Command / PatternDescription
tar -cf archive.tar file1 dir1 ...Basic format to create a TAR archive containing multiple files or directories.
tar -cf /root/etc.tar /etcArchiving system directories that may require root access (e.g., /etc).
tar --xattrs -cf archive.tar directory/Includes extended attributes such as ACLs and SELinux labels in the archive.
tar -tf archive.tarLists the contents of a TAR archive.
mkdir /root/etcbackup
cd /root/etcbackup
tar -xf /root/etc.tar
Extracts a TAR archive into a specific directory.
tar -xpf archive.tarExtracts files while preserving original permissions.

Creating, Listing and Extracting Compressed TAR Archives

Command / PatternDescription
tar -czf /root/etcbackup.tar.gz /etcCreates a gzip-compressed TAR archive.
tar -cjf /root/logbackup.tar.bz2 /var/logCreates a bzip2-compressed TAR archive.
tar -cJf /root/sshconfig.tar.xz /etc/sshCreates an xz-compressed TAR archive.
tar -tf archive.tar.gzLists contents of any compressed TAR archive (.gz, .bz2, .xz).
mkdir /tmp/etcbackup
cd /tmp/etcbackup
tar -xzf /root/etcbackup.tar.gz
Extracts a gzip compressed archive.
mkdir /tmp/logbackup
cd /tmp/logbackup
tar -xjf /root/logbackup.tar.bz2
Extracts a bzip2 compressed archive.
mkdir /tmp/sshbackup
cd /tmp/sshbackup
tar -xJf /root/sshbackup.tar.xz
Extracts an xz compressed archive.
Secure File Transfer Between Systems

Secure file transfer in Linux is commonly performed using:

  • scp (Secure Copy)

  • sftp (Secure File Transfer Program)

Both use SSH for authentication and Encrypted data transfer

Transferring Files Using scp

  • Copy files from local to remote

    • scp /etc/yum.conf /etc/hosts remoteuser@remotehost:/home/remoteuser
  • Copy file from remote to local

    • scp remoteuser@remotehost:/etc/hostname /home/user
  • Copy directories recursively

    • scp -r root@remotehost:/var/log /tmp

Transferring Files Using sftp

  • Start an SFTP session:
    • sftp remoteuser@remotehost
  • You will get a prompt:
    • sftp>
  • Common SFTP Commands

CommandDescription
lsList remote directory
cdChange remote directory
mkdirCreate remote directory
pwdShow remote working directory
put <file>Upload file to remote
get <file>Download file from remote
exitQuit session
  • Example: Uploading a File in sftp

    • Create a directory and upload /etc/hosts

    • sftp> mkdir hostbackup
      sftp> cd hostbackup
      sftp> put /etc/hosts
      
  • Example: Downloading a File in sftp
    • Download /etc/yum.conf from remote to local
    • sftp> get /etc/yum.conf
      sftp> exit
      
Secure File Synchronization Between Systems

rsync is a powerful and efficient tool for synchronizing files and directories between:

  • Local ↔ Local

  • Local ↔ Remote

  • Remote ↔ Local

Advantages:

  • Transfers only differences between source and destination.

  • Uses SSH for secure authentication and encrypted transfer.

  • Faster updates after the first copy.

Important rsync Options

OptionMeaning / Description
-nDry Run Shows what changes would occur without actually executing them.
-vVerbose Output Displays detailed progress.
-aArchive Mode Enables many important options (recursive, preserve metadata, etc.).
-rRecursive directory copy (part of -a)
-lCopy symlinks (part of -a)
-pPreserve permissions (part of -a)
-tPreserve timestamps (part of -a)
-gPreserve group (part of -a)
-oPreserve owner (part of -a)
-DPreserve device files (part of -a)
-APreserve ACLs
-XPreserve SELinux contexts
-HPreserve hard links

Synchronizing Local Directories

  • rsync -av /var/log /tmp
  • This creates /tmp/log containing /var/log contents.

  • Sync contents only (no log directory created)

    • rsync -av /var/log/ /tmp
  • Trailing slash (/) affects behavior:

    • No slash → copy directory itself

    • Slash → copy only directory contents

Synchronizing with Remote Systems

  • To preserve file ownership on the destination, run rsync as root on the destination system.

  • Local → Remote

    • rsync -av /var/log remotehost:/tmp
  • Remote → Local

    • rsync -av remotehost:/var/log /tmp

Installing and Updating Software Packages

Red Hat Subscription Management

Red Hat Subscription Management enables you to:

  • Register systems to your Red Hat account

  • Attach software subscriptions

  • Enable repositories

  • Track consumed and available entitlements

Tools like yum, dnf, and PackageKit rely on these subscriptions to access Red Hat’s software repositories and updates.

TaskDescription
Register systemAssociates a machine with a Red Hat account.
Attach subscriptionsGrants access to updates & support services.
Enable repositoriesAllows package installation from supported repos.
Review entitlementsCheck subscriptions in use or available.

Registering a System

The subscription-manager utility is used to register a system with Red Hat Customer Portal.

  • Register system
    • subscription-manager register --username=yourusername --password=yourpassword
  • List available subscriptions
    • subscription-manager list --available | less
  • Auto-attach the best subscription
    • subscription-manager attach --auto
  • Attach a specific subscription (pool ID)
    • subscription-manager attach --pool=poolID
  • List consumed subscriptions
    • subscription-manager list --consumed
  • Unregister system
    • subscription-manager unregister

Entitlement Certificates

Once a system is registered, entitlement data is stored in:

DirectoryPurpose
/etc/pki/productCertificates for installed Red Hat products.
/etc/pki/consumerIdentifies the Red Hat account the system is registered to.
/etc/pki/entitlementCertificates for attached subscriptions.

Certificates can be inspected with rct, but subscription-manager is recommended for easier management.

RPM Software Packages

RPM (Red Hat Package Manager) provides:

  • A standard method for distributing software.

  • Tracking of installed files.

  • Metadata for dependencies, licensing, changelogs, scripts, etc.

  • A local database storing all installed package information.

All Red Hat packages are delivered as RPM files.

An RPM filename uses the format name-version-release.architecture.rpm

Example:

coreutils-8.30-4.el8.x86_64.rpm
PartMeaning
NAMESoftware name (coreutils)
VERSIONUpstream version (8.30)
RELEASEBuild release number (4.el8)
ARCHCPU architecture (x86_64, aarch64, noarch)

RPM Package Components

Every RPM includes:

  • Installed files

  • Metadata (version, summary, dependencies, changelog, license, etc.)

  • Scripts that run during install/update/removal

RPMs are usually digitally signed (GPG) so package integrity can be verified.

Updating Software with RPM

  • Installing an update RPM replaces the old version.

  • Only one version of most packages can be installed at a time.

  • Kernel packages are an exception (multiple versions allowed).

Examining RPM Packages

The rpm command is used for querying installed packages or package files.

CommandPurposeExample
rpm -qaList all installed packagesrpm -qa
rpm -q NAMEShow installed version of a packagerpm -q yum
rpm -qi NAMEDisplay detailed package informationrpm -qi openssh-server
rpm -ql NAMEList all files installed by a packagerpm -ql bash
rpm -qc NAMEList only configuration filesrpm -qc ssh
rpm -qd NAMEList documentation filesrpm -qd coreutils
rpm -q --changelog NAMEShow change history of a packagerpm -q --changelog audit
rpm -q --scripts NAMEShow install/uninstall scripts inside the RPMrpm -q --scripts httpd
rpm -qf FILEShow which installed package owns a filerpm -qf /etc/yum.repos.d
rpm -qlp FILE.rpmList files contained in an RPM file (not installed)rpm -qlp vim-8.0.rpm
rpm -ivh package.rpmInstall a local RPM packagerpm -ivh docker.rpm
rpm2cpio file.rpm | cpio -idExtract all files from an RPM without installingrpm2cpio app.rpm | cpio -id
rpm2cpio file.rpm | cpio -id "<pattern>"Extract only files matching a pattern from an RPMrpm2cpio sample.rpm | cpio -id "*.conf"
Managing Software Packages with Yum

rpm handles individual packages, but does not resolve dependencies or use repositories.

yum provides:

  • Automatic dependency resolution

  • Access to multiple repositories

  • Install/update/remove operations

  • Search and info features

  • Transaction history

Finding Software with Yum

Command / PatternPurpose
yum helpDisplay help and general usage information for yum.
yum listList all installed and available packages.
yum list 'http*'List installed/available packages matching a pattern.
yum search KEYWORDSearch for packages related to a keyword.
yum search all "web server"Search package names and descriptions for the phrase “web server”.
yum info httpdShow detailed information about the httpd package.
yum provides /path/fileFind which package provides the specified file or path.
yum historyShow transaction history
yum history undo <ID>Undo a transaction

Installing & Removing Software

ActionCommandExample
Install a packageyum install PACKAGENAMEyum install httpd
Update a specific packageyum update PACKAGENAMEyum update nginx
Update kernelyum update kernelyum update kernel
Update all packagessudo yum updatesudo yum update
Remove a packageyum remove PACKAGENAMEyum remove git

Removing a package may also remove packages depending on it.

Managing Kernels with Yum

Yum installs new kernels alongside existing ones so you can boot back into an older version if needed.

List installed and available kernels

  • yum list kernel

Check currently running kernel

  • uname -r
  • uname -a

Software Groups

Two types of groups:

  • Environment groups (e.g., Server with GUI)

  • Regular groups (e.g., RPM Development Tools)

ActionCommandExample
List groupsyum group listyum group list
List hidden groupsyum group list hiddenyum group list hidden
Get information about a groupyum group info "GROUPNAME"yum group info "RPM Development Tools"
Install a groupyum group install "GROUPNAME"yum group install "RPM Development Tools"
Mark a group as installedyum group mark install GROUPNAMEyum group mark install "RPM Development Tools"
Enabling Yum Software Repositories
  • Registering a system to Red Hat Subscription Management normally configures access to Red Hat repositories automatically.

  • Third-party repositories (e.g., EPEL, Adobe) can be added and enabled as needed.

  • Repo definitions live under:

    • /etc/yum.repos.d/*.repo
  • Each repo file can contain one or more repository stanzas (each stanza starts with [name]).

  • Repo files must end in .repo.

  • A single .repo file may contain multiple [repo-id] stanzas (e.g., epel, epel-debuginfo, epel-source).

Command SyntaxExplanationExample
yum repolist allShows all enabled/disabled repositories and package countsyum repolist all
yum config-manager --enable REPO_NAMEPermanently enables a repository in the system repo configyum config-manager --enable rhel-8-server-debug-rpms
yum config-manager --disable REPO_NAMEPermanently disables a repositoryyum config-manager --disable rhel-8-server-debug-rpms
yum --enablerepo=REPO install PACKAGEEnables a repository for a single Yum commandyum --enablerepo=epel install htop
yum --disablerepo=REPO updateDisables a repository for a single Yum commandyum --disablerepo=rhel-* update
rpm --import URL_TO_KEYImports the GPG key needed to verify packagesrpm --import http://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8
yum install URL_TO_REPO_RPMInstalls repository configuration and keysyum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm

Create / Add a Third-Party Repo

  • Use yum config-manager --add-repo, This creates a file under /etc/yum.repos.d/
    • yum config-manager --add-repo="https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/"
  • Edit the created .repo file to set name, baseurl, enabled, gpgcheck, and gpgkey.
  • Import the RPM GPG key before installing signed packages so yum can verify signatures.
  • Use gpgkey=file:///path/to/key to point to a locally stored GPG key.

Example repo stanza (EPEL)

  • [epel]
    name=Extra Packages for Enterprise Linux $releasever - $basearch
    baseurl=https://dl.fedoraproject.org/pub/epel/$releasever/Everything/$basearch
    enabled=1
    gpgcheck=1
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
    
  • To keep a repo defined but not searched by default, set enabled=0

Managing Package Module Streams

Application Streams allows multiple versions of user-space applications to be installed and also independent lifecycle updates separate from the BaseOS.

Two main repositories:

  • BaseOS → Core OS packages; long-term stability
  • AppStream → User-space apps via Modules or traditional RPMs

Modules

A module is a set of related RPM packages (app + libraries + docs + tools).

A module contains:

Module Streams

  • Different versions of the software.

  • Only one stream can be enabled at a time.

Module Profiles

  • Predefined package sets for use cases (e.g., common, minimal, server, development).

  • Installing a module installs a profile.

  • Default profile applies if none is specified.

Command SyntaxExplanationExample
yum module listShows all available modules and streamsyum module list
yum module list MODULEShows available streams for a moduleyum module list perl
yum module info MODULEDisplays stream, profiles, summary, and packagesyum module info perl
yum module info --profile MODULE:STREAMShows packages included in a specific profileyum module info --profile perl:5.24
yum module enable MODULE:STREAMEnables a specific module streamsudo yum module enable perl:5.26
yum module install MODULEInstalls module and its profile packagessudo yum module install perl
yum install @MODULEEquivalent method to install module groupssudo yum install @perl
yum module list MODULEShows whether the module is enabled or installedyum module list perl
yum module remove MODULERemoves installed profile packages of the modulesudo yum module remove perl
yum module disable MODULEDisables a module so it cannot be installedsudo yum module disable perl
yum module info MODULEUsed to identify packages in the current streamyum module info postgresql | grep module+el8
yum module remove MODULERequired before resetting or switching module streamssudo yum module remove postgresql
yum module reset MODULEClears enabled or disabled state of the modulesudo yum module reset postgresql
yum module install MODULE:STREAMEnables and installs a new module streamsudo yum module install postgresql:10
yum distro-syncAligns installed packages with the selected streamsudo yum distro-sync
yum remove PACKAGERemoves leftover packages from old streamssudo yum remove <package>

Managing Networking

Linux networking is managed using tools that configure IP addresses, network interfaces, routing, DNS, and services. Commands like ip, ifconfig, nmcli, and systemctl help control how the system connects to other networks and the internet.

Gather network interface information

  • ip link show command list all interfaces and their MAC addresses. Useful to map names (ens3, ens4) to physical/virtual ports.
  • [user@host ~]$ ip link show
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
        link/ether 52:54:00:00:00:0a brd ff:ff:ff:ff:ff:ff
    3: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
        link/ether 52:54:00:00:00:1e brd ff:ff:ff:ff:ff:ff
    

Display IP addresses

  • ip addr show <interface> command shows configured IPv4/IPv6 addresses, prefix lengths, and whether addresses are link/global scope.
  • [user@host ~]$ ip addr show ens3
    2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500
        link/ether 52:54:00:00:00:0b brd ff:ff:ff:ff:ff:ff
        inet 192.0.2.2/24 brd 192.0.2.255 scope global ens3
        inet6 2001:db8:0:1:5054:ff:fe00:b/64 scope global
        inet6 fe80::5054:ff:fe00:b/64 scope link
    

Display interface performance statistics

  • ip -s link show <interface> command prints packet/byte counts and error/dropped counters useful for diagnosing link issues.
  • Look for non-zero errors or dropped counters to detect physical or driver problems.
  • [user@host ~]$ ip -s link show ens3
    RX: bytes packets errors dropped overrun mcast
    269850 2931    0      0      0       0
    TX: bytes packets errors dropped carrier collsns
    300556 3250    0      0      0       0
    

Check connectivity between hosts

ping verifies reachability and measures round-trip time; specify interface scope for IPv6 link-local addresses.

  • ping -c <count> <destination> command tests latency and packet loss for IPv4

    • [user@host ~]$ ping -c 3 192.0.2.254
      3 packets transmitted, 3 received, 0% packet loss
      rtt min/avg/max/mdev = 3.485/4.885/6.837/1.424 ms
      
  • ping6 -c <count> <destination> command tests latency and packet loss for IPv6
    • [user@host ~]$ ping6 -c 3 2001:db8:0:1::1
      PING 2001:db8:0:1::1(2001:db8:0:1::1) 56 data bytes
      64 bytes from 2001:db8:0:1::1: icmp_seq=1 ttl=64 time=18.4 ms
      64 bytes from 2001:db8:0:1::1: icmp_seq=2 ttl=64 time=0.178 ms
      64 bytes from 2001:db8:0:1::1: icmp_seq=3 ttl=64 time=0.180 ms
      
      --- 2001:db8:0:1::1 ping statistics ---
      3 packets transmitted, 3 received, 0% packet loss, time 2001ms
      rtt min/avg/max/mdev = 0.178/6.272/18.458/8.616 ms
      
  • When pinging link-local addresses, append the interface scope: fe80::...%ens3

    • [user@host ~]$ ping6 -c 1 fe80::f482:dbff:fe25:6a9f%ens4
      PING fe80::f482:dbff:fe25:6a9f%ens4(fe80::f482:dbff:fe25:6a9f) 56 data bytes
      64 bytes from fe80::f482:dbff:fe25:6a9f: icmp_seq=1 ttl=64 time=22.9 ms
      
      --- fe80::f482:dbff:fe25:6a9f%ens4 ping statistics ---
      1 packets transmitted, 1 received, 0% packet loss, time 0ms
      rtt min/avg/max/mdev = 22.903/22.903/22.903/0.000 ms
      

Inspect routing table

Routing table entries map destination prefixes to interfaces and next-hop routers; longest-prefix match is used.

  • Show IPv4 routes
    • [user@host ~]$ ip route
      default via 192.0.2.254 dev ens3 proto static metric 1024
      192.0.2.0/24 dev ens3 proto kernel scope link src 192.0.2.2
      10.0.0.0/8 dev ens4 proto kernel scope link src 10.0.0.11
      
  • Show IPv6 routes
    • [user@host ~]$ ip -6 route
      2001:db8:0:1::/64 dev ens3 proto kernel metric 256
      fe80::/64 dev ens3 proto kernel metric 256
      default via 2001:db8:0:1::ffff dev ens3 proto static metric 1024
      

Trace path taken by packets

tracepath/traceroute reveal each hop and latency so you can identify where latency or packet loss occurs.

  • Trace IPv4 path

    • [user@host ~]$ tracepath access.redhat.com
      ...output omitted...
       4:  71-32-28-145.rcmt.qwest.net                48.853ms   asymm 5
       5:  dcp-brdr-04.inet.qwest.net                100.732ms   asymm 7
       6:  206.111.0.153.ptr.us.xo.net                96.245ms   asymm 7
       7:  207.88.14.162.ptr.us.xo.net                85.270ms   asymm 8
       8:  ae1d0.cir1.atlanta6-ga.us.xo.net           64.160ms   asymm 7
       9:  216.156.108.98.ptr.us.xo.net              108.652ms
      10:  bu-ether13.atlngamq46w-bcr00.tbone.rr.com 107.286ms   asymm 12
      ...output omitted...
      
  • Trace IPv6 path

    • [user@host ~]$ tracepath6 2001:db8:0:2::451
      1?: [LOCALHOST] 0.091ms pmtu 1500
      1: 2001:db8:0:1::ba 0.214ms
      2: 2001:db8:0:1::1 0.512ms
      3: 2001:db8:0:2::451 0.559ms reached
      

Troubleshoot ports and services

  • ss or netstat shows which services are listening, on which interfaces/ports, and any established connections.
  • [user@host ~]$ ss -ta
    State    Recv-Q Send-Q   Local Address:Port        Peer Address:Port
    LISTEN        0    128   *:sunrpc                  *:*
    LISTEN        0    128   *:ssh                     *:*
    LISTEN        0    100   127.0.0.1:smtp            *:*
    LISTEN        0    128   *:36889                   *:*
    ESTAB         0      0   172.25.250.10:ssh         172.25.254.254:59392
    LISTEN        0    128   :::sunrpc                 :::*
    LISTEN        0    128   :::ssh                    :::*
    LISTEN        0    100   ::1:smtp                  :::*
    LISTEN        0    128   :::34946                  :::*
    
  • The SSH port is listening on all IPv4 addresses, shown by the * wildcard for IPv4.

  • The SMTP service is listening only on the 127.0.0.1 IPv4 loopback address.

  • The ESTABLISHED SSH connection shows the server using 172.25.250.10 and the client coming from 172.25.254.254.

  • For IPv6, the SSH service is listening on all IPv6 interfaces, represented by ::.

  • The SMTP IPv6 listener is bound to the IPv6 loopback interface ::1.

OptionMeaning (one line)
-nShow numeric addresses/ports (no name resolution).
-tShow TCP sockets.
-uShow UDP sockets.
-lShow only listening sockets.
-aShow all sockets (listening + established).
-pShow process using the socket (requires privileges).
-A inetShow IPv4/IPv6 network sockets (exclude UNIX).
  • Combine these to narrow output (e.g., ss -tunlp shows numeric TCP/UDP listening sockets and their processes).
Configuring Networking from the Command Line

NetworkManager is the service responsible for managing network interfaces on RHEL/CentOS systems. It:

    • Monitors network devices

    • Activates and manages connections

    • Applies IP/DNS settings

    • Writes configuration files to:

    • /etc/sysconfig/network-scripts/ifcfg-*>/re>

Tools like nmcli, nmtui, and the GNOME network settings dialog all communicate with NetworkManager.

The nmcli tool allows you to configure and control network settings directly from the command line.

    • A device is a physical or virtual network interface (e.g., ens3, wlp2s0).

    • Connection is a set of network settings applied to a device. A device can have multiple connections, but only one active at a time.
    • Connection ID is a human-readable name used to identify a connection.

Viewing Network Information

  • The nmcli dev status command displays the status of all network devices:
    • [user@host ~]$ nmcli dev status
      DEVICE   TYPE      STATE        CONNECTION
      eno1     ethernet  connected    eno1
      ens3     ethernet  connected    static-ens3
      eno2     ethernet  disconnected --
      lo       loopback  unmanaged    --
      
  • The nmcli con show command displays a list of all connections. To list only the active connections, add the --active option.
    • [user@host ~]$ nmcli con show
      NAME          UUID                                  TYPE              DEVICE
      eno2          ff9f7d69-db83-4fed-9f32-939f8b5f81cd   802-3-ethernet    --
      static-ens3   72ca57a2-f780-40da-b146-99f71c431e2b   802-3-ethernet    ens3
      eno1          87b53c56-1f5d-4a29-a869-8a7bdaf56dfa   802-3-ethernet    eno1
      [user@host ~]$ nmcli con show --active
      NAME          UUID                                  TYPE              DEVICE
      static-ens3   72ca57a2-f780-40da-b146-99f71c431e2b   802-3-ethernet    ens3
      eno1          87b53c56-1f5d-4a29-a869-8a7bdaf56dfa   802-3-ethernet    eno1
      

Adding a New Connection

The nmcli con add command is used to add new network connections.

  • Connection with auto IPv4 with DHCP and auto IPv6
    • nmcli con add con-name eno2 type ethernet ifname eno2
  • The eno2 is the interface name (connection name) and it create /etc/sysconfig/network-scripts/ifcfg-eno2 file which contains all the details of this particular interface/connection.
  • Connection with static IPv4 address with it’s gateway and subnet
    • nmcli con add con-name eno2 type ethernet ifname eno2 \
      ipv4.address 192.168.0.5/24 ipv4.gateway 192.168.0.254
      
  • Connection with static IPv4 and IPv6 address with it’s gateway and subnet
    • nmcli con add con-name eno2 type ethernet ifname eno2 \
      ipv6.address 2001:db8:0:1::c000:207/64 ipv6.gateway 2001:db8:0:1::1 \
      ipv4.address 192.0.2.7/24          ipv4.gateway 192.0.2.1
      

Activating & Deactivating Connections

  • Activate (bring up) a connection using the command nmcli con up <connection-name>

    • nmcli con up static-ens3
  • Deactivate a device using the command nmcli dev dis <connection-name> it’s Best method to bring down an interface.

    • nmcli dev dis ens3

Viewing Connection Settings

  • The details of a particular connection can be seen by command nmcli <connection-name>
  • It shows Static properties (editable) and Active properties (from DHCP/SLAAC)
    • [user@host ~]$ nmcli con show static-ens3
      connection.id: static-ens3
      802-3-ethernet.mac-address: CA:9D:E9:2A:CE:F0
      ipv4.method: manual
      ipv4.addresses: 192.168.0.2/24
      ipv4.gateway: 192.168.0.254
      ipv6.method: manual
      ipv6.addresses: 2001:db8:0:1::7/64
      

Modifying Connection Settings

The nmcli con mod command is used to modify the existing connections

  • Changing IPv4 settings
    • nmcli con mod static-ens3 ipv4.address 192.0.2.2/24 \
      ipv4.gateway 192.0.2.254
  • Changing IPv6 settings
    • nmcli con mod static-ens3 ipv6.address 2001:db8:0:1::a00:1/64 \
      ipv6.gateway 2001:db8:0:1::1
  • If switching from DHCP to static config:

    • ipv4.method auto   → manual  
      ipv6.method auto   → manual
      

Reload Connection Files

This will be useful if you edited /etc/sysconfig/network-scripts/ifcfg-* manually

  • nmcli con reload
 

Delete a Connection

The nmcli con del command deletes the particular connection and also it’s config file

  • nmcli con del static-ens3

Who Can Modify Network Settings?

  • root: Full control

  • Local logged-in users (physical console): Allowed to manage connections

  • SSH users: Must become root

  • To check current permissions:
    • nmcli gen permissions
CommandPurpose
nmcli dev statusShow device status
nmcli con showList all connections
nmcli con show <name>View settings for a connection
nmcli con add ...Create a new connection
nmcli con mod ...Modify a connection
nmcli con up <name>Activate a connection
nmcli dev dis <dev>Disable a device
nmcli con del <name>Delete a connection
nmcli con reloadReload configuration files
Editing Network Configuration Files

Network configuration on RHEL-based systems can be modified in two ways:

  1. Using nmcli commands
  2. Editing the connection files in /etc/sysconfig/network-scripts/

NetworkManager loads these files automatically. If you edit them manually, run nmcli con reload to apply changes.

Connection Configuration Files (ifcfg Files)

When you modify a connection using nmcli con mod <name> ... NetworkManager saves these settings to /etc/sysconfig/network-scripts/ifcfg-<name>

These files use older ifcfg syntax, so some settings differ from the nmcli version.
Below is a mapping of nmcli settings → ifcfg directives → effect.

nmcli Settingifcfg DirectiveMeaning / Effect
ipv4.method manualBOOTPROTO=noneUse static IPv4 configuration.
ipv4.method autoBOOTPROTO=dhcpGet IPv4 settings via DHCP.
ipv4.addresses 192.0.2.1/24IPADDR=192.0.2.1
PREFIX=24
Sets static IPv4 address. Multiple addresses use IPADDR1, PREFIX1, etc.
ipv4.gateway 192.0.2.254GATEWAY=192.0.2.254Sets default IPv4 gateway.
ipv4.dns 8.8.8.8DNS1=8.8.8.8Adds DNS server.
ipv4.dns-search example.comDOMAIN=example.comAdds DNS search domain.
ipv4.ignore-auto-dns truePEERDNS=noIgnore DNS info from DHCP.
ipv6.method manualIPV6_AUTOCONF=noStatic IPv6 configuration.
ipv6.method autoIPV6_AUTOCONF=yesEnable IPv6 SLAAC.
ipv6.method dhcpIPV6_AUTOCONF=no + DHCPV6C=yesUse DHCPv6 only.
ipv6.addresses 2001:db8::a/64IPV6ADDR=2001:db8::a/64Sets static IPv6 address. Additional addresses use IPV6ADDR_SECONDARIES.
ipv6.gateway 2001:db8::1IPV6_DEFAULTGW=2001:db8::1Sets IPv6 default gateway.
connection.autoconnect yesONBOOT=yesBring connection up at boot.
connection.id ens3NAME=ens3Name of the connection.
connection.interface-name ens3DEVICE=ens3Binds connection to device.
802-3-ethernet.mac-addressHWADDR=xx:xx:xx...Bind connection to a MAC address.

Editing ifcfg Files Manually

Connection config files live here

  • /etc/sysconfig/network-scripts/ifcfg-<name>

Example: Static IPv4 Configuration

BOOTPROTO=none
IPADDR0=172.25.250.10
PREFIX0=24
GATEWAY0=172.25.250.254
DEFROUTE=yes
DNS1=172.25.254.254
DEVICE=ens3
NAME="static-ens3"
ONBOOT=yes

Example: DHCP IPv4 Configuration

BOOTPROTO=dhcp
DEVICE=ens3
NAME="dhcp-ens3"
ONBOOT=yes

After modifying an ifcfg file, for the changes to reflect follow the below steps:

  • nmcli con reload
    nmcli con down "static-ens3"
    nmcli con up "static-ens3"
    

This reloads the config and restarts the connection.

Configuring Host Names and DNS Resolution

The hostname command is used to check the current hostname

The permanent hostname is stored in the /etc/hostname file. The hostnamectl set-hostname command is used to set the permanent hostname and it can be verified using hostnamectl status command.

[root@host ~]# hostname
host.example.com

[root@host ~]# hostnamectl set-hostname host.example.com

[root@host ~]# hostnamectl status
 Static hostname: host.example.com
       Icon name: computer-vm
         Chassis: vm
      Machine ID: f874df04639f474cb0a9881041f4f7d4
         Boot ID: 6a0abe03ef0b4a97bcb8afb7b281e4d3
  Virtualization: kvm
Operating System: Red Hat Enterprise Linux 8.2 (Ootpa)
     CPE OS Name: cpe:/o:redhat:enterprise_linux:8.2:GA
          Kernel: Linux 4.18.0-193.el8.x86_64
    Architecture: x86-64

[root@host ~]# cat /etc/hostname
host.example.com

Local Name Resolution

The system first checks /etc/hosts for hostname → IP mappings.

[root@host ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
172.25.254.254   classroom.example.com
172.25.254.254   content.example.com

The getent hosts <hostname> command can be used to test host name resolution using the /etc/hosts file.

DNS Resolution

If a hostname is not found in /etc/hosts, the system queries DNS servers defined in /etc/resolv.conf

  • [root@host ~]# cat /etc/resolv.conf
    # Generated by NetworkManager
    domain example.com
    search example.com
    nameserver 172.25.254.254
    
  • search: a list of domain names to try with a short host name.
  • nameserver: the IP address of a nameserver to query.

NetworkManager overwrites this file using connection settings.

Setting DNS Servers with nmcli

CommandPurpose
nmcli con mod <ID> ipv4.dns "8.8.8.8 1.1.1.1"Replace existing DNS servers with new ones.
nmcli con mod <ID> +ipv4.dns 8.8.4.4Add/append an additional IPv4 DNS server.
nmcli con mod static-ens3 +ipv6.dns 2001:4860:4860::8888Add an IPv6 DNS server.
nmcli con down <ID>Bring the connection down (apply changes).
nmcli con up <ID>Bring the connection back up.
nmcli con mod "static-ens3" ipv4.ignore-auto-dns yesPrevent DHCP from replacing DNS settings.

Testing DNS Name Resolution

The host <hostname> command can be used to test DNS server connectivity.

[root@host ~]# host sample.example.com
sample.example.com has address 172.25.254.254

[root@host ~]# host 172.25.254.254
254.254.25.172.in-addr.arpa domain name pointer sample.example.com.

Scheduling Future Tasks

Scheduling Deferred User Jobs

Deferred jobs are commands scheduled to run once at a specific point in the future. These jobs persist after a reboot
They’re useful for tasks like:

  • Running a script later

  • Resetting firewall rules after 10 minutes

  • Sending a reminder or email

  • Running maintenance tasks at a specific time

Linux provides the at utility for this purpose. The atd daemon runs jobs in the background.

Scheduling a Task with at

The basic syntax for this command is at TIMESPEC After running the command type the commands you want executed and press Ctrl + D to save & exit

  • Examples of valid TIMESPEC formats
    • now + 5 min
      noon + 4 days
      5pm august 3 2026
      teatime tomorrow   # 16:00
      02:30pm
      15:45
      
  • Example:

    • echo "echo 'Backup done'" | at now + 5 min
    • at now + 10 min < myscript.sh

Viewing Scheduled Jobs

Use atq (or at -l) to list pending jobs for the current user.

  • [user@host ~]$ atq
    28  Mon Feb 2 05:13:00 2025 a user
    29  Mon Feb 3 16:00:00 2025 a user
    27  Tue Feb 4 12:00:00 2025 a user
    
  • Fields:
    • Job ID (e.g., 28)

    • Scheduled date & time

    • Queue (default = a)

    • User who owns the job

Regular users see only their jobs. root can see & manage all jobs.

To view the job contents run the command at -c <Job-ID>This shows the environment + the exact commands scheduled.

To remove the scheduled job run the command atrm <Job-ID>

Scheduling Recurring User Jobs

Recurring tasks in Linux are handled by the crond daemon (from the cronie package).

Users schedule repeated jobs using their personal crontab file, managed via the crontab command.

When a cron job runs, any output (STDOUT/STDERR) is sent to the user via local email unless redirected.

Managing User Cron Jobs

CommandDescription
crontab -lList current user’s cron jobs
crontab -rRemove all cron jobs for current user
crontab -eEdit cron jobs (opens editor)
crontab filenameReplace user’s crontab with jobs from a file

Root can manage another user’s cron jobs using the command  crontab -u username -e

Crontab File Format

A crontab entry contains six fields MIN HOUR DOM MON DOW COMMAND

  • Field Meanings:
FieldMeaning
MIN0–59
HOUR0–23
DOM (Day of Month)1–31
MON1–12 or Jan–Dec
DOW (Day of Week)0–7 (0/7 = Sunday) or Mon–Sun
COMMANDCommand or script to run
  • Syntax Options:

SyntaxMeaning
*Every value
5Specific minute/hour/day
1-5Range
1,3,7List of specific values
*/10Every 10 units

If Day of Month (DOM) and Day of Week (DOW) are both non-*, the job runs when either field matches.

Examples of Recurring Jobs

  • Run a backup every year on Feb 2 at 9:00 AM
    • 0 9 2 2 * /usr/local/bin/yearly_backup
  • Run every 5 minutes from 9 AM to 5 PM on Fridays in July
    • */5 9-16 * Jul 5 echo "Chime"
  • Run a report at 23:58 on weekdays
    • 58 23 * * 1-5 /usr/local/bin/daily_report
  • Send an email every weekday at 9 AM
    • 0 9 * * 1-5 mutt -s "Checking in" boss@example.com % Hi there boss, just checking in.
Scheduling Recurring System Jobs

System administrators often schedule jobs that must run repeatedly at the system level.
Instead of using user crontabs, system jobs should be placed in system-wide cron files.

System Cron Locations

Recurring system jobs are defined in:

1. /etc/crontab (System Crontab)

  • This file allows scheduling tasks with an additional field specifying the user.
  • Syntax:
    • # ┌──────── minute (0 - 59)
      # │ ┌────── hour (0 - 23)
      # │ │ ┌──── day of month (1 - 31)
      # │ │ │ ┌── month (1 - 12)
      # │ │ │ │ ┌ day of week (0 - 7)
      # │ │ │ │ │
      # * * * * * user command
      

2. /etc/cron.d/ (Recommended for custom system jobs)

  • Create your own cron files here.

  • Safer than modifying /etc/crontab, which may be overwritten during updates.

  • Packages also place their cron definitions here.

Cron Script Directories

These directories contain executable scripts run at fixed intervals:

DirectoryRuns
/etc/cron.hourly/Every hour
/etc/cron.daily/Daily
/etc/cron.weekly/Weekly
/etc/cron.monthly/Monthly

Any script which is added here should be executable, make them executable using chmod +x <filename> command

Understanding /etc/anacrontab

anacron (now integrated into crond) ensures important jobs run even if the system was powered off during their scheduled time.

Purpose

  • Guarantee daily/weekly/monthly jobs run at least once in the required interval.
  • Track last run time via files in /var/spool/anacron/.

Entry Format (4 Fields)

period  delay  job-id  command
FieldMeaning
periodDays between runs (1, 7, 30, or @daily, @weekly, etc.)
delayMinutes to wait before starting
job-idIdentifier logged in system logs
commandScript or command to run

systemd Timer Units

It’s a modern alternative to cron, systemd timers provide a newer, more flexible way to run scheduled jobs.
A timer unit triggers a corresponding service unit.

Example timer:

  • /usr/lib/systemd/system/sysstat-collect.timer
  • [Unit]
    Description=Run system activity accounting tool every 10 minutes
    
    [Timer]
    OnCalendar=*:00/10
    
    [Install]
    WantedBy=sysstat.service
    
    • This runs every 10 minutes.

  • OnCalendar=2024-03-* 12:35,37,39:16
    • Runs at 12:35:16, 12:37:16, and 12:39:16 every day in March 2024.

  • OnUnitActiveSec=15min
    • Trigger 15 minutes after last activation.

Never edit files in /usr/lib/systemd/system/. Instead, copy the unit into /etc/systemd/system/ then edit the copy

After modifying a timer:

  • systemctl daemon-reload
    systemctl enable --now mytimer.timer
    
Managing Temporary Files

Modern Linux systems create and store many temporary files under:

  • /tmp → general temporary files

  • /run → volatile runtime files (stored in RAM, cleared on reboot)

To automate the creation, cleanup, and permission management of temporary files, Red Hat Enterprise Linux (RHEL) uses systemd-tmpfiles, this creates required temp directories at boot, cleans up old temporary files, and ensures correct permissions/ownership.

It reads configuration from:

  • /usr/lib/tmpfiles.d/*.conf ← Vendor defaults
  • /run/tmpfiles.d/*.conf ← Runtime (volatile)
  • /etc/tmpfiles.d/*.conf ← Admin/custom settings (highest priority)

Systemd manages temporary files at boot, the service systemd-tmpfiles-setup.service runs systemd-tmpfiles --create --remove this creates directories/files specified in tmpfiles configuration, fixes permissions, deletes items marked for removal.

Automatic Cleaning with systemd Timer

Temporary file cleanup happens using this timer systemd-tmpfiles-clean.timer

View the timer configuration:

  • [user@host ~]$ systemctl cat systemd-tmpfiles-clean.timer
    [Unit]
    Description=Daily Cleanup of Temporary Directories
    
    [Timer]
    OnBootSec=15min
    OnUnitActiveSec=1d
    
  • OnBootSec=15min → run cleanup 15 minutes after boot

  • OnUnitActiveSec=1d → run cleanup every 1 day afterwards

If changes in done in the frequency reload systemctl daemon-reload and enable systemctl enable --now systemd-tmpfiles-clean.timer

Cleaning Temporary Files Manually

To run cleanup immediately, run the command systemd-tmpfiles --clean. This deletes files older than the configured Age parameter in tmpfiles configuration files.

The basic syntax of systemd-tmpfiles consists of seven columns: Type, Path, Mode, UID, GID, Age, and Argument.

TypeMeaningExample Entry
dCreate directory if missingd /run/systemd/seats 0755 root root -
DCreate directory and remove existing contentsD /home/student 0700 student student 1d
LCreate symbolic linkL /run/fstablink - root root - /etc/fstab
ZReset SELinux permissions recursivelyZ /some/path - - - (example placeholder)

Configuration File Precedence

When files share the same name:

  • /etc/tmpfiles.d/ → highest priority (admin overrides)
  • /run/tmpfiles.d/ → runtime/volatile
  • /usr/lib/tmpfiles.d/ → vendor defaults (lowest priority)

This ensures:

  1. Your custom changes in /etc/tmpfiles.d/ override system defaults safely.
  2. Package updates do not overwrite admin-managed temp file rules.

Accessing Linux File Systems

Linux presents all data through a single unified file-system hierarchy. Even though your system may have multiple disks, partitions, or logical volumes, they all appear as directories under /.

To make a storage device accessible, its file system must be mounted on a directory called a mount point. Once mounted, the directory shows the contents of that file system.

Block Devices and Naming

Low-level access to storage in Linux is provided through block device files, found under /dev.

These device files are created automatically by the OS and represent entire disks or partitioned sections of disks.

Storage TypeExample NamesDescription
SATA/SAS/SCSI/USB Drives/dev/sda, /dev/sdbEach letter represents a whole disk.
virtio-blk Disks/dev/vda, /dev/vdbUsed in VMs (paravirtualized storage).
NVMe SSDs/dev/nvme0, /dev/nvme1High-speed NVMe devices.
SD/MMC/eMMC/dev/mmcblk0, /dev/mmcblk1SD card / embedded storage.

Partitions

Partitions slice a disk into smaller usable sections.

Typical partition naming:

  • SATA/SAS/SCSI/USB:

    • /dev/sda1, /dev/sda2

  • NVMe:

    • /dev/nvme0p1, /dev/nvme0p2

Example block device listing:

  • [root@host ~]$ ls -l /dev/sda1
    brw-rw----. 1 root disk 8, 1 Feb 22 08:00 /dev/sda1
    
  • b indicates a block device.

Logical Volumes (LVM)

LVM allows multiple physical devices to be grouped into a Volume Group (VG). Within a VG, storage is allocated to Logical Volumes (LVs).

Physical Volumes → Volume Group → Logical Volumes

LV device naming:

  • /dev/<VG_name>/<LV_name>
  • Example:
    • /dev/myvg/mylv

These are actually symbolic links pointing to the underlying device-mapper entries.

Viewing File Systems and Disk Usage

  • Use df to view mounted filesystems and available space:

    • [root@host ~]$ df -h
      Filesystem      Size  Used Avail Use% Mounted on
      devtmpfs        892M     0  892M   0% /dev
      tmpfs           915M     0  915M   0% /dev/shm
      tmpfs           915M   17M  899M   2% /run
      tmpfs           915M     0  915M   0% /sys/fs/cgroup
      /dev/vda3       8.0G  1.4G  6.7G  17% /
      /dev/vda1       1014M 166M  849M  17% /boot
      tmpfs           183M     0  183M   0% /run/user/1000
      
  • Use du to check usage per directory
    • [root@host ~]# du -h /var/log
      ...output omitted...
      176K   /usr/share/smartmontools
      184K   /usr/share/nano
      8.0K   /usr/share/cmake/bash-completion
      8.0K   /usr/share/cmake
      369M   /usr/share
      
  • Flags:

    • -h = human-readable (GiB, MiB)

    • -H = SI units (GB, MB)

Mounting and Unmounting File Systems

In Linux, a file system must be mounted before you can access its contents. Likewise, you must unmount it safely before removing the device.

Identifying Block Devices

Use lsblk to list available disks and partitions:

  • [root@host ~]$ lsblk
    NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    vda    253:0    0   12G  0 disk
    ├─vda1 253:1    0    1G  0 part /boot
    ├─vda2 253:2    0    1G  0 part [SWAP]
    └─vda3 253:3    0   11G  0 part /
    vdb    253:16   0   64G  0 disk
    └─vdb1 253:17   0   64G  0 part
    

If a new 64 GB storage device was just attached, /dev/vdb1 is likely the target partition.

Mounting a File System Manually

Mount a filesystem onto a directory using the command mount <device> <mountpoint>

The mount point must already exist. Files previously in that directory become hidden until unmounted.

Example:

  • mkdir -p /mnt/data
    mount /dev/vdb1 /mnt/data

Mounting Using UUID

This is the most reliable method, device names like /dev/vdb1 may change depending on detection order, but UUIDs remain constant.

List UUIDs:

  • [root@host ~]$ lsblk -fp
    NAME         FSTYPE LABEL UUID                                 MOUNTPOINT
    /dev/vda
    ├─/dev/vda1  xfs          23ea8803-a396-494a-8e95-1538a53b821c /boot
    ├─/dev/vda2  swap         cdf61ded-534c-4bd6-b458-cab18b1a72ea [SWAP]
    └─/dev/vda3  xfs          44330f15-2f9d-4745-ae2e-20844f22762d /
    /dev/vdb
    └─/dev/vdb1  xfs          46f543fd-78c9-4526-a857-244811be2d88
    

Mount using UUID:

  • [root@host ~]# mount UUID="46f543fd-78c9-4526-a857-244811be2d88" /mnt/data

Unmounting File Systems

To unmount safely use the command umount <mountpoint>

  • [root@host ~]# umount /mnt/data

Always unmount before disconnecting/removing the storage device.

Unmounting fails if processes are using the filesystem.

  • [root@host data]# umount /mnt/data
    umount: /mnt/data: target is busy.
    

Identify the process which is using the filesystem using the lsof command.

  • [root@host ~]$ lsof /mnt/data
    COMMAND   PID  USER   FD   TYPE DEVICE  SIZE/OFF NODE NAME
    bash     1593  root   cwd  DIR  253,17        6  128 /mnt/data
    lsof     2532  root   cwd  DIR  253,17       19  128 /mnt/data
    lsof     2533  root   cwd  DIR  253,17       19  128 /mnt/data
    
  • To fix:
    • Close the file(s)

    • Move out of the directory (cd ~)

    • Stop or kill the process if necessary

After fix it unmount again.

  • [root@host data]# umount /mnt/data
Locating Files on a Linux System

Searching for files is a common task for system administrators. Linux provides two primary tools:

  • locate – very fast; searches a prebuilt index (not real-time).

  • find – searches in real time; accurate but slower.

Finding Files Using locate

locate searches a database of filenames and paths. This database is updated daily, but you can update manually updatedb

locate only shows files in directories the user has permission to access.

CommandExplanation
locate passwdSearch for files whose name contains passwd
locate -i messagesCase-insensitive search for filenames containing messages
locate -n 5 snow.pngLimit results to the first 5 matches

Searching Files in Real Time with find

find walks the filesystem directly, making it accurate and flexible.

CommandExplanation
find / -name sshd_configSearch for a file by exact name
find / -name '*.txt'Search using wildcard patterns (must quote patterns)
find /etc -iname '*pass*'Case-insensitive name search
find /home/user -user userFiles owned by a specific user
find /home/user -group userFiles owned by a specific group
find /home/user -uid 1000Files owned by UID 1000
find /home/user -gid 1000Files owned by GID 1000
find / -user root -group mailFiles owned by root AND group mail
find /home -perm 764Files with exact permission 764
find /home -perm -324User has ≥ wx, group ≥ w, others ≥ r
find /home -perm /444Anyone has at least read access
find -perm -002Others have write access
find -size 10MFiles exactly 10 MB
find -size +10GFiles larger than 10 GB
find -size -10kFiles smaller than 10 KB
find / -mmin 120Modified exactly 120 minutes ago
find / -mmin +200Modified more than 200 minutes ago
find / -mmin -150Modified less than 150 minutes ago
find /etc -type dAll directories under /etc
find / -type lAll symbolic links
find /dev -type bAll block devices under /dev
find / -type f -links +1Files with more than one hard link

Managing Basic Storage

Disk partitioning divides a physical disk into logical sections. Common reasons:

  • Limit space for users or applications

  • Separate OS files from user data

  • Provide space for swap

  • Improve performance for tools like backups and images

Partitioning Schemes

  • MBR (Master Boot Record):

    • Old standard (BIOS systems) and Uses 32-bit addressing
    • Max disk size 2 TiB and Supports 4 primary partitions (or 3 primary + extended + logicals).

  • GPT (GUID Partition Table)

    • Modern standard (UEFI systems) and Provides corruption checking (CRC)

    • Supports 128 partitions and Max disk size 8 ZiB

    • Stores primary + backup partition table

Managing Partitions with parted

parted supports both MBR and GPT disks.

View Partition Table

  • [root@host ~]# parted /dev/vda print
    Model: Virtio Block Device (virtblk)
    Disk /dev/vda: 53.7 GB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    Disk Flags:
    Number  Start    End      Size     Type     File system  Flags
    1       1049kB   10.7GB   10.7GB   primary  xfs          boot
    2       10.7GB   53.7GB   42.9GB   primary  xfs
    
  • If you do not provide a subcommand print, parted opens an interactive session for issuing commands and there you can enter the subcommand and to exit from it, type quit and press enter.

Writing a Disk Label

Before creating partitions on a new disk we need to create a disk label.

  • MBR Label
    • [root@host ~]# parted /dev/vdb mklabel msdos
  • GPT Label
    • [root@host ~]# parted /dev/vdb mklabel gpt

mklabel erases existing partition tables along with the existing data

Creating MBR Partitions

  • Specify the disk device to create the partition on
  • Use the mkpart subcommand to create a new primary or extended partition
  • Choose the file-system type, such as xfs or ext4. To get the list of the supported file-system type, use the command parted /dev/vdb help mkpart
  • Specify the sector on the disk that the new partition starts on. You can also use the MiB, GiB, TiB, MB, GB,
    or TB suffixes. the default suffix is MB
  • Specify the disk sector where the new partition should end.
  • Size = End – Start
  • Exit parted
  • Run udevadm settle This command waits for the system to detect the new partition and to create the associated device file under the /dev directory. It only returns when it is done.
  • [root@host ~]# parted /dev/vdb
    (parted) mkpart
    Partition type? primary/extended? primary
    File system type? [ext2]? xfs
    Start? 2048s
    End? 1000MB
    (parted) quit
    Information: You may need to update /etc/fstab.
    [root@host ~]# udevadm settle
    [root@host ~]#
    
  • This partition can be created using a one line command
    • [root@host ~]# parted /dev/vdb mkpart primary xfs 2048s 1000MB

Creating GPT Partitions

  • Specify the disk device to create the partition on
  • Use the mkpart subcommand to create a new partition, With the GPT scheme, each partition is given a name.
  • Choose the file-system type, such as xfs or ext4. To get the list of the supported file-system type, use the command parted /dev/vdb help mkpart
  • Specify the sector on the disk that the new partition starts on. You can also use the MiB, GiB, TiB, MB, GB,
    or TB suffixes. the default suffix is MB
  • Specify the disk sector where the new partition should end.
  • Size = End – Start
  • Exit parted
  • Run udevadm settle This command waits for the system to detect the new partition and to create the associated device file under the /dev directory. It only returns when it is done.
  • [root@host ~]# parted /dev/vdb
    (parted) mkpart
    Partition name? []? usersdata
    File system type? [ext2]? xfs
    Start? 2048s
    End? 1000MB
    (parted) quit
    Information: You may need to update /etc/fstab.
    [root@host ~]# udevadm settle
    [root@host ~]#
    
  • This partition can be created using a one line command
    • [root@host ~]# parted /dev/vdb mkpart usersdata xfs 2048s 1000MB

Deleting Partitions (MBR or GPT)

  • Specify the disk that contains the partition to be removed.
  • Identify the partition number of the partition to delete.
  • Delete the partition.
  • Exit parted
  • [root@host ~]# parted /dev/vdb
    (parted) print
    Model: Virtio Block Device (virtblk)
    Disk /dev/vdb: 5369MB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Disk Flags:
    Number  Start    End      Size     File system  Name       Flags
    1       1049kB   1000MB   999MB    xfs          usersdata
    (parted) rm 1
    (parted) quit
    Information: You may need to update /etc/fstab.
    [root@host ~]#

Creating File Systems

After creating a partition, we need to format it by adding a file system to it. The two most commonly used file systems are xfs and ext4.

As root, use the mkfs.xfs command to apply an XFS file system to a block device. For ext4, use mkfs.ext4.

  • [root@host ~]# mkfs.xfs /dev/vdb1
  • [root@host ~]# mkfs.ext4 /dev/vdb1

Mounting File Systems

After you have added the file system, the last step is to mount the file system to a directory in the directory structure.

Temporary Mount

  • The mount <device> <mountpoint> command is used to temporarily mount the file system, this will not be present after restart.
    • [root@host ~]# mount /dev/vdb1 /mnt
  • The mounted file systems can be viewed using the same mount command
    • [root@host ~]# mount | grep vdb1
      /dev/vdb1 on /mnt type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
      

Persistent Mounts

To make sure that the system automatically mounts the file system at system boot, add an entry to the /etc/fstab file. This file systems persists even after the reboot.

  • Get UUID
    • [root@host ~]# lsblk --fs
      vdb1   xfs   7a20315d-ed8b-4e75-a5b6-24ff9e1f9838
      
  • Edit /etc/fstab and add the below entry
    • UUID=7a20315d-ed8b-4e75-a5b6-24ff9e1f9838  /data  xfs  defaults  0 0
  • Reload ssytemd, when you add or remove an entry in the /etc/fstab
    • [root@host ~]# systemctl daemon-reload
  • Test and validate fstab entry, If no error, then system is safe to reboot.
    • [root@host ~]# mount -a
    • [root@host ~]# findmnt --verify
      
  • Understanding /etc/fstab Fields
FieldDescription
1. DeviceUUID recommended (stable)
2. Mount pointDirectory must exist/swap
3. Filesystem typexfs/ext4/swap/others
4. Optionsdefaults for common settings
5. DumpUsually 0
6. fsck order1 for root ext4, 2 for others, 0 for XFS
Managing Swap Space

Swap space acts as an overflow area for RAM. When memory pressure increases:

  • Inactive pages are moved from RAM → swap

  • Active pages are accessed from swap → RAM

Swap is much slower than RAM.
It is only a fallback, not a replacement for insufficient memory.

Swap Space Sizing

RAM SizeRecommended SwapIf Using Hibernation
≤ 2 GiB2 × RAM3 × RAM
2–8 GiBSame as RAM2 × RAM
8–64 GiBAt least 4 GiB1.5 × RAM
> 64 GiBAt least 4 GiBHibernation not recommended

Steps to Create Swap Space

  • Use parted to create a partition and set its type to linux-swap.

  • [root@host ~]# parted /dev/vdb
    (parted) print
    Model: Virtio Block Device (virtblk)
    Disk /dev/vdb: 5369MB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Disk Flags:
    Number  Start    End      Size     File system  Name  Flags
    1       1049kB   1001MB   1000MB   data
    (parted) mkpart
    Partition name? []? swap1
    File system type? [ext2]? linux-swap
    Start? 1001MB
    End? 1257MB
    (parted) print
    Model: Virtio Block Device (virtblk)
    Disk /dev/vdb: 5369MB
    Sector size (logical/physical): 512B/512B
    Partition Table: gpt
    Disk Flags:
    Number  Start    End      Size     File system       Name    Flags
    1       1049kB   1001MB   1000MB   data
    2       1001MB   1257MB   256MB    linux-swap(v1)    swap1
    (parted) quit
    Information: You may need to update /etc/fsta
    [root@host ~]# udevadm settle
    
  • Format the partition using the mkswap command applies a swap signature to the device.
  • [root@host ~]# mkswap /dev/vdb2
    Setting up swapspace version 1, size = 244 MiB (255848448 bytes)
    no label, UUID=39e2667a-9458-42fe-9665-c5c854605881
    

Activating and Deactivating Swap Space

  • The swapon command with the device as a parameter is used to activate a particular swap space, or use swapon -a to activate all the swap spaces listed in the /etc/fstab file. Use the swapon --show and free commands to inspect the available swap spaces.
  • [root@host ~]# free
                  total        used        free      shared  buff/cache   available
    Mem:        1873036      134688     1536436       16748      201912     1576044
    Swap:             0           0           0
    [root@host ~]# swapon /dev/vdb2
    [root@host ~]# free
                  total        used        free      shared  buff/cache   available
    Mem:        1873036      135044     1536040       16748      201952     1575680
    Swap:        249852           0      249852
    
  • The swapoff command with the device as a parameter is used to deactivate a particular swap space.
  • [root@host ~]# swapoff /dev/vdb2

Activating Swap Space Persistently

  • To activate a swap space at every boot, place an entry in the /etc/fstab file.
  • Entry to add in /etc/fstab:
    • UUID=39e2667a-9458-42fe-9665-c5c854605881  swap  swap  defaults  0  0
  • After adding reload the systemd
    • [root@host ~]# systemctl daemon-reload

Setting Swap Priority

Linux chooses which swap space to use first based on priority.

  • Default priority: −2

  • Higher value = higher priority

Example /etc/fstab with priorities:

  • UUID=af30cbb0-3866-466a-825a-58889a49ef33  swap  swap  defaults  0  0
    UUID=39e2667a-9458-42fe-9665-c5c854605881  swap  swap  pri=4     0  0
    UUID=fbd7fa60-b781-44a8-961b-37ac3ef572bf  swap  swap  pri=10    0  0
    

Use swapon –show to display the swap space priorities.

Managing Logical Volumes

LVM easily resize filesystems, migrate extents to new disks, and manage flexible storage pools.

  • Physical devices: disks, partitions, RAID or SAN devices used by LVM.

  • Physical volumes (PVs): devices initialized for LVM (pvcreate).

  • Volume groups (VGs): pools of PV storage (vgcreate).

  • Logical volumes (LVs): block devices carved from VGs (lvcreate) and used like normal partitions.

Creating a Logical Volume

Prepare the physical device.

  • Use a whole disk (e.g. /dev/sdb) or create a partition and set its type to Linux LVM (MBR type 0x8e) with parted, gdisk, or fdisk.

  • Register partitions if required:

    [root@host ~]# parted -s /dev/vdb mkpart primary 1MiB 769MiB
    [root@host ~]# parted -s /dev/vdb set 1 lvm on
    [root@host ~]# partprobe 
    

Create a physical volume (PVs)

  • pvcreate prepares the device(s) for use by LVM. It label the devices as LVM physical volumes.
  • [root@host ~]# pvcreate /dev/vdb2 /dev/vdb1
  • This labels the devices /dev/vdb2 and /dev/vdb1 as PVs, ready for allocation into a volume group.

Create a Volume Group (VG)

  • vgcreate makes a pooled storage area (VG) for LVs. It creates a VG from one or more PVs
  • [root@host ~]# vgcreate vg01 /dev/vdb2 /dev/vdb1
  • This creates a VG called vg01 that is the combined size, in PE units, of the two PVs /dev/vdb2 and /dev/vdb1.

Create a Logical Volume (LV)

  • lvcreate makes a block device (/dev/vg01/lv01) you can format. It creates an LV from free space in a VG.
  • [root@host ~]# lvcreate -n lv01 -L 700M vg01
  • This creates an LV called lv01, 700 MiB in size, in the VG vg01.
  • -n sets LV name, -L sets size (e.g., 700M).

  • Use -l to specify size in extents instead of bytes.

Format and Mount the LV

  • Use mkfs to create an XFS file system on the new logical volume.
    • [root@host ~]# mkfs -t xfs /dev/vg01/lv01
  • Create a mount point directory
    • [root@host ~]# mkdir /mnt/data
  • Add an entry to /etc/fstab
    • /dev/vg01/lv01 /mnt/data xfs defaults 1 2
  • Run mount command to mount the file system added in /etc/fstab
    • [root@host ~]# mount /mnt/data

Removing a Logical Volume

  • Removing a logical volume destroys any data stored on the logical volume. Back up or move your data before you remove the logical volume.
  • Unmount and edit /etc/fstab to deleted the LV entry
    • [root@host ~]# umount /mnt/data
  • Remove LV:
    • [root@host ~]# lvremove /dev/vg01/lv01
  • Remove VG:
    • [root@host ~]# vgremove vg01
  • Remove PV(s):
    • [root@host ~]# pvremove /dev/vdb2 /dev/vdb1

Inspecting LVM Status

  • The pvdisplay command displays information about physical volumes. To list information about all physical volumes, use the command without arguments. To list information about a specific physical volume, pass that device name to the command.
  • [root@host ~]# pvdisplay /dev/vdb1
      --- Physical volume ---
      PV Name               /dev/vdb1
      VG Name               vg01
      PV Size               768.00 MiB / not usable 4.00 MiB
      Allocatable           yes
      PE Size               4.00 MiB
      Total PE              191
      Free PE               16
      Allocated PE          175
      PV UUID               JWzDpn-LG3e-n2oi-9Etd-VT2H-PMem-1ZXwP1
    
  • The vgdisplay command displays information about volume groups. To list information about all volume groups, use the command without arguments. To list information about a specific volume group, pass that VG name to the command.
  • [root@host ~]# vgdisplay vg01
      --- Volume group ---
      VG Name               vg01
      System ID
      Format                lvm2
      Metadata Areas        2
      Metadata Sequence No  2
      VG Access             read/write
      VG Status             resizable
      MAX LV                0
      Cur LV                1
      Open LV               1
      Max PV                0
      Cur PV                2
      Act PV                2
      VG Size               1016.00 MiB
      PE Size               4.00 MiB
      Total PE              254
      Alloc PE / Size       175 / 700.00 MiB
      Free PE / Size        79 / 316.00 MiB
      VG UUID               3snNw3-CF71-CcYG-Llk1-p6EY-rHEv-xfUSez
    
  • The lvdisplay command displays information about logical volumes. If you provide no argument to the command, it displays information about all LVs; if you provide an LV device name as an argument, the command displays information about that specific device.
  • [root@host ~]# lvdisplay /dev/vg01/lv01
      --- Logical volume ---
      LV Path                /dev/vg01/lv01
      LV Name                lv01
      VG Name                vg01
      LV UUID                5IyRea-W8Zw-xLHk-3h2a-IuVN-YaeZ-i3IRrN
      LV Write Access        read/write
      LV Creation host, time host.lab.example.com, 2019-03-28 17:17:47 -0400
      LV Status              available
      # open                 1
      LV Size                700 MiB
      Current LE             175
      Segments               1
      Allocation             inherit
      Read ahead sectors     auto
        - current set to     256
      Block device           252:0
    
  • Use these commands to check allocation, sizes, and free extents.
Extending Logical Volumes and File Systems

You can add more disk space to a volume group by adding additional physical volumes or You can remove unused physical volumes from a volume group.

Extending a Volume Group

  • Prepare the physical device and create the physical volume.
    • [root@host ~]# parted -s /dev/vdb mkpart primary 1027MiB 1539MiB
    • [root@host ~]# parted -s /dev/vdb set 3 lvm on
    • [root@host ~]# pvcreate /dev/vdb3
    • A PV only needs to be created if there are no PVs free to extend the VG.
  • vgextend increases the VG pool by the PV size. This extends the vg01 VG by the size of the /dev/vdb3 PV.

    • [root@host ~]# vgextend vg01 /dev/vdb3
  • Use vgdisplay to confirm the additional physical extents are available. Free PE / Size shows how much space is now available to allocate to LVs.
    • [root@host ~]# vgdisplay vg01
        --- Volume group ---
        VG Name               vg01
        ...output omitted...
        Free PE / Size        178 / 712.00 MiB
        ...output omitted...

Reducing a Volume Group

Before removing a PV from a VG, back up data stored on all logical volumes in the volume group.

  • pvmove migrates extents from the source physical volume to other physical volume in the VG.

    • [root@host ~]# pvmove /dev/vdb3
  • vgreduce removes a physical volume from volume group
    • [root@host ~]# vgreduce vg01 /dev/vdb3
  • pvremove can be used to permanently stop using the device as a PV

Extending a Logical Volume

  • vgdisplay verifies that there are sufficient physical extents available.
  • lvextend extends the logical volume to a new size.
    • [root@host ~]# lvextend -L +300M /dev/vg01/lv01
CommandResult / Meaning
lvextend -l 128 <LV>Resize the logical volume to exactly 128 extents.
lvextend -l +128 <LV>Add 128 extents to the current size of the logical volume.
lvextend -L 128M <LV>Resize the logical volume to exactly 128 MiB.
lvextend -L +128M <LV>Add 128 MiB to the current size of the logical volume.
lvextend -l +50%FREE <LV>Add 50% of the current free space in the VG to the logical volume.

Extend XFS file system

  • Use xfs_growfs mountpoint to expand the file system to occupy the extended LV.
  • XFS must be mounted while growing.
    • [root@host ~]# xfs_growfs /mnt/data
  • Verify the new size of the mounted file system.
    • [root@host ~]# df -h /mountpoint
  • Use lvextend -r to automatically resize filesystem after LV extension (works for many filesystems)
  • XFS cannot be reduced: you cannot shrink an XFS filesystem or its LV while data remains.

Extend ext4 file system

  • After lvextend run resize2fs.  Itoperates on the block device (LV), not the mount point. Use -p to show progress.

    • [root@host ~]# resize2fs /dev/vg01/lv01

Extend a logical volume and swap space

Ensure enough RAM or other swap before swapoff to avoid OOM

  • Use vgdisplay vgname to verify that a sufficient number of free physical extents are available.
    • [root@host ~]$ vgdisplay vg01
  • Use swapoff -v /dev/vgname/lvname to deactivate the swap space on the logical volume.
    • [root@host ~]$ swapoff -v /dev/vg01/lv_swap
  • lvextend -l +extents /dev/vgname/lvname extends the logical volume /dev/vgname/lvname by the extents value.
    • [root@host ~]$ lvextend -L +1G /dev/vg01/lv_swap
  • mkswap /dev/vgname/lvname formats the entire logical volume as swap space.
    • [root@host ~]$ mkswap /dev/vg01/lv_swap
  • Use swapon -va /dev/vgname/lvname to activate the swap space on the logical volume.
    • [root@host ~]$ swapon -va
  • Verify the changes
    • [root@host ~]$ free -h
      [root@host ~]$ swapon --show

Implementing Advanced Storage Features

Managing Layered Storage with Stratis
  • Stratis is a modern Linux storage-management solution that simplifies pooling block devices, creating flexible thin-provisioned filesystems, snapshots & layered storage.
  • Stratis is built on top of standard Linux technologies. It uses the Device Mapper framework (similar to how LVM works internally) and formats all its filesystems using XFS.

  • It also supports thin provisioning, meaning a filesystem can appear very large (such as 1 TiB) while consuming only the real physical storage it actually needs.

  • You can create multiple pools, up to 224 filesystems per pool.

Installing and Enabling Stratis

  • To manage file systems with the Stratis storage management solution, install the stratis-cli and stratisd packages.
    • [root@host ~]# yum install stratis-cli stratisd
  • Activate the stratisd service using the systemctl command.
    • [root@host ~]# systemctl enable --now stratisd

Creating and Managing Stratis Pools

  • Create pools of one or more block devices using the stratis pool create command.
    • [root@host ~]# stratis pool create pool1 /dev/vdb
  • Each pool is a subdirectory under the /stratis directory.
  • Use the stratis pool list command to view the list of available pools.
    • [root@host ~]# stratis pool list
      Name    Total Physical Size   Total Physical Used
      pool1   5 GiB                 52 MiB</pre
  • Monitor Total Physical Used,this is real allocated storage.

  • Use the stratis pool add-data command to add additional block devices to a pool.
    • [root@host ~]# stratis pool add-data pool1 /dev/vdc
  • Use the stratis blockdev list command to view the block devices of a pool.
    • [root@host ~]# stratis blockdev list pool1
      Pool Name   Device Node   Physical Size   State   Tier
      pool1       /dev/vdb       5 GiB           In-use  Data
      pool1       /dev/vdc       5 GiB           In-use  Data

Managing Stratis Filesystems

  • Use the stratis filesystem create command to create a file system from a pool.
    • [root@host ~]# stratis filesystem create pool1 fs1
  • The links to the Stratis file systems are in the /stratis/pool1 directory.
  • Use the stratis filesystem list command to view the list of available file systems.
    • [root@host ~]# stratis filesystem list
      Pool Name   Name   Used      Created                 Device                    UUID
      pool1       fs1    546 MiB   Sep 23 2020 13:11       /stratis/pool1/fs1        31b9363badd...
  • df will always show 1 TiB size for Stratis filesystems (thin provisioning). Always check real space with stratis pool list
  • You can create a snapshot of a Stratis-managed file system with the stratis filesystem snapshot command.
    • [root@host ~]# stratis filesystem snapshot pool1 fs1 snapshot1

Persistently Mounting Stratis Filesystems

  • The below command displays the UUID of the file system.
    • [root@host ~]# lsblk --output=UUID /stratis/pool1/fs1
      UUID
      31b9363b-add8-4b46-a4bf-c199cd478c55
  • Add the entry in the /etc/fstab file to persistently mount a Stratis file system.
    • UUID=31b9363b-add8-4b46-a4bf-c199cd478c55  /dir1  xfs  defaults,x-systemd.requires=stratisd.service  0 0
  • x-systemd.requires=stratisd.service ensures Stratis is started before mounting. Without it, system boot may fail.
Compressing and Deduplicating Storage with VDO
  • VDO (Virtual Data Optimizer) is a Linux device-mapper layer designed to reduce storage usage by automatically eliminating zero-filled blocks, removing duplicate blocks through UDS-based deduplication, and compressing data using the LZ4 compression engine provided by the kvdo module.
  • You place VDO on top of a block device (disk/RAID/LVM/etc.) and then put Filesystems, LVM, Encryption on top of the VDO volume, similar to a normal disk.
  • This reduces physical disk footprint while increasing space efficiency.

VDO processes data in 3 stages:

  • Zero-Block Elimination
    • Removes all-zero blocks and stores them only in metadata and Enables thin provisioning.

  • Deduplication (UDS Module)

    • Detects repeated blocks and Stores 1 original block, references it everywhere else.

  • Compression (kvdo Module)
    • Compresses data using LZ4 and Works in 4 KB block groups.

VDO Volumes

  • A VDO volume behaves like a disk, Format it with any filesystem (XFS/ext4/etc.), Mount it normally, and Can also be used as an LVM PV.
  • VDO supports thin provisioning, so logical size can be larger than physical size (e.g., 50G logical on a 10G disk). Monitor usage carefully.

Implementing VDO

  • Install the vdo and kmod-kvdo packages to enable VDO in the system.
    • [root@host ~]# yum install vdo kmod-kvdo
  • Create the VDO volume by running the vdo create command.
    • [root@host ~]# vdo create --name=vdo1 --device=/dev/vdd --vdoLogicalSize=50G
    • --device → underlying physical block device

    • --vdoLogicalSize → logical (visible) size for users

  • If logical size is omitted → VDO uses same size as physical device (best performance).
  • After creation, format it and mount it.
    • [root@host ~]# mkfs.xfs /dev/mapper/vdo1
      [root@host ~]# mkdir /mnt/vdo1
      [root@host ~]# mount /dev/mapper/vdo1 /mnt/vdo1
  • To analyze a VDO volume, run the vdo status command. Use the –name= option to specify the name of a particular volume.
    • [root@host ~]# vdo status
      [root@host ~]# vdo status --name=vdo1
  • The vdo list command displays the list of VDO volumes that are currently started.
    • [root@host ~]$ vdo list
  • The VDO volume can be stopped and started using the vdo start and vdo stop commands.
    • [root@host ~]$ vdo start --name=vdo1
      [root@host ~]$ vdo stop --name=vdo1
  • The physical usage is monitored using the vdostats command, especially when thin provisioning is used.
    • [root@host ~]$ vdostats --verbose

Accessing Network-Attached Storage

Mounting Network-Attached Storage with NFS

NFS (Network File System) allows Linux/UNIX systems to share directories over the network and mount them just like local filesystems.

Mounting NFS Shares

  • Identify Available NFS Shares. The NFS server admin may provide export details, or you can browse the server’s NFS root.

    • [user@host ~]$ sudo mkdir mountpoint
      [user@host ~]$ sudo mount serverb:/ mountpoint
      [user@host ~]$ sudo ls mountpoint
  • Create a mount point directory on the client system.

    • [user@host ~]$ mkdir -p mountpoint
  • Temporarily mounting the NFS share using the mount command. This mount does not survive reboot, it’s only ideal for testing.
    • [user@host ~]$ sudo mount -t nfs -o rw,sync serverb:/share mountpoint
  • -t nfs → filesystem type

  • rw,sync → read-write, synchronous writes

  • Persistently mounting the NFS share by adding an entry in the /etc/fstab and mount the NFS share.
    • [user@host ~]$ sudo vim /etc/fstab
      ...
      serverb:/share    /mountpoint    nfs    rw,soft    0 0
    • [user@host ~]$ sudo mount /mountpoint

Unmounting an NFS Share

  • As root (or using sudo), unmount an NFS share using the umount command.
    • [user@host ~]$ sudo umount mountpoint
  • Unmounting does not remove the /etc/fstab entry. If it remains, the NFS share will auto-mount again on the next boot.
Automounting Network-Attached Storage

The automounter (autofs) automatically mounts NFS shares on-demand and unmounts them when not in use. This reduces network load and removes the need for users to run mount or umount.

Benefits of Using the Automounter

  • No root privileges required by users.

  • Shares mount only when accessed → saves system & network resources.

  • Client-side configuration only; no changes needed on NFS server.

  • Supports direct and indirect maps, including wildcards.

  • Works with any filesystem supported by manual mount.

  • Automatically creates/removes mount directories for indirect maps.

Create an automount

  • Install the autofs package
    • [user@host ~]$ sudo yum install autofs
  • Create a Master Map File. It live in /etc/auto.master.d/ and must end with .autofs.

    • [user@host ~]$ sudo vim /etc/auto.master.d/demo.autofs
  • Add the master map entry in the .autofs file
    • /shares   /etc/auto.demo
    • /shares → base directory for indirect automounts

    • /etc/auto.demo → mapping file (must be created next)

  • Create the Mapping File. It define mount points, options, and NFS source paths.

    • [user@host ~]$ sudo vim /etc/auto.demo
      work   -rw,sync   serverb:/shares/work
  • Components:

    • Key (mount point): work → becomes /shares/work

    • Options: -rw,sync

    • Source: serverb:/shares/work

    The directory /shares/work is automatically created and removed by autofs.

  • Use systemctl to start and enable the autofs service.
    • [user@host ~]$ sudo systemctl enable --now autofs

Direct Maps

  • Used when mounting an NFS share to an existing absolute path.
  • To use directly mapped mount points, the master map file might appear as follows:
    • /- /etc/auto.direct
  • The content for the /etc/auto.direct file might appear as follows:
    • /mnt/docs -rw,sync serverb:/shares/docs
    • /mnt/docs is the exact mount point (absolute path).

    • /mnt must already exist.

Indirect Wildcard Maps

  • Use when the NFS server exports many subdirectories with the same options.

  • Example /etc/auto.demo entry:

    • * -rw,sync serverb:/shares/&
  • * → wildcard key (matches any directory name)

  • & → replaced by the actual key accessed

Controlling the Boot Process

Selecting the Boot Target

A modern RHEL system boots through the following major stages:

  1. System firmware (UEFI/BIOS) runs POST and initializes hardware.

  2. Firmware loads the bootloader (GRUB2) from the configured boot device.

  3. GRUB2 reads /boot/grub2/grub.cfg and lets you choose a kernel.

  4. GRUB2 loads the kernel + initramfs into memory.

  5. The kernel initializes hardware and runs /sbin/init → systemd.

  6. systemd runs units from initrd.target, then mounts the real root filesystem.

  7. Root switches from initramfs to real system.

  8. systemd loads the default target (graphical or multi-user) and starts required services.

Rebooting & Shutting Down

  • To power off or reboot a running system from the command line
  • systemctl poweroff or poweroff stops all running services, unmounts all file systems, and then powers down the system.
  • systemctl reboot or reboot stops all running services, unmounts all file systems, and then reboots the system.

Understanding systemd Targets

  • A target defines the system state (what services should run).

TargetPurpose
graphical.targetMulti-user + graphical login
multi-user.targetText-based multi-user mode
rescue.targetMinimal mode with root shell (sulogin)
emergency.targetVery minimal, root filesystem read-only
  • To list all the taegets
    • [user@host ~]$ systemctl list-units --type=target --all
  • To view the dependencies
    • [user@host ~]$ systemctl list-dependencies graphical.target

Selecting a Target at Runtime

  • On a running system, administrators can switch to a different target using the systemctl isolate command. It stops all the services not required by the target and starts the services which ware required.
    • [root@host ~]# systemctl isolate multi-user.target
  • Only targets with AllowIsolate=yes can be isolated. It can be checked by viewing the target.

    • [user@host ~]$ systemctl cat graphical.target

Setting a Default Target

  • When the system starts, systemd activates the default.target target. The get-default and set-default subcommands are used to view and set the default target.
    • [root@host ~]# systemctl get-default
      multi-user.target
      [root@host ~]# systemctl set-default graphical.target
      Removed /etc/systemd/system/default.target.
      Created symlink /etc/systemd/system/default.target -> /usr/lib/systemd/system/graphical.target.
      [root@host ~]# systemctl get-default
      graphical.target
      

Selecting a Different Target at Boot Time

  • Useful for troubleshooting or single-use changes. This affects only that boot.

  • Steps:
    • Boot or reboot the system.
    • Interrupt the boot loader menu countdown by pressing any key (except Enter which would initiate a normal boot).
    • Move the cursor to the kernel entry that you want to start.
    • Press e to edit the current entry.
    • Move the cursor to the line that starts with linux. This is the kernel command line.
    • Append systemd.unit=target.target. For example, systemd.unit=emergency.target
    • Press Ctrl+x to boot with these changes.
Resetting the Root Password

If the root password is lost and you cannot log in, you can reset it from the boot loader without using external media. RHEL  allows dropping into an initramfs debug shell using rd.break.

Resetting Root Password Using rd.break

The system will stop before switching to the real root filesystem and provide a root shell.

  1. Reboot the system.
  2. Interrupt the boot loader countdown by pressing any key, except Enter.
  3. Move the cursor to the kernel entry to boot.
  4. Press e to edit the selected entry.
  5. Move the cursor to the kernel command line (the line that starts with linux).
  6. Append rd.break
  7. Press Ctrl+x to boot with the changes.

Remount and Change Root Password

The real root filesystem is available at /sysroot but mounted read-only, so:

  1. Remount /sysroot as read/write.
    • switch_root:/# mount -o remount,rw /sysroot
  2. Switch into a chroot jail, where /sysroot is treated as the root of the file-system tree.
    • switch_root:/# chroot /sysroot
  3. Set a new root password.
    • sh-4.4# passwd root
  4. Make sure that all unlabeled files, including /etc/shadow at this point, get relabeled during boot.
    • sh-4.4# touch /.autorelabel
  5. Type exit twice. The first command exits the chroot jail, and the second command exits the initramfs debug shell.

The system will reboot, relabel all files for SELinux, and then apply the new password.

Inspecting Logs
  • By default, RHEL stores logs in /run/log/journal (cleared on reboot).
  • To persist logs across reboots, edit the journald.conf, make the stoage to persistent and restart the journald service.
    • [root@host ~]# vim /etc/systemd/journald.conf
      ...output omitted...
      [Journal]
      Storage=persistent
      ...output omitted...
      [root@host ~]# systemctl restart systemd-journald.service
  • View logs from the previous boot:

    • [root@host ~]# journalctl -b -1 -p err
Debugging Boot Problems
  • Enable Early Debug Shell

    • By enabling the debug-shell service with systemctl enable debug-shell.service, the system spawns a root shell on TTY9 (Ctrl+Alt+F9) early during the boot sequence.
    • Disable it after use, or anyone with console access can get root.
  • Emergency & Rescue Targets

    • By appending either systemd.unit=rescue.target or systemd.unit=emergency.target to the kernel command line from the boot loader, the system spawns into a rescue or emergency shell instead of starting normally.
    • Both requires the root password.
    • Emergency target → minimal environment, rootfs is read-only.

    • Rescue target → basic services running, logs available.

    • To remount root read-write execute mount -o remount,rw /

  • Checking Stuck systemd Jobs

    • If the system freezes during boot execute systemctl list-jobs It  shows running or waiting jobs that may block the boot sequence.

Repairing File System Issues at Boot

Problems in /etc/fstab or corrupted file systems can prevent a Linux system from booting. When this happens, systemd usually drops the system into an emergency shell, where the root password is required to perform repairs.

ProblemWhat Happens During Boot
Corrupted filesystemsystemd attempts automatic repair; if it fails, you get an emergency shell.
Wrong device/UUID in /etc/fstabsystemd waits for the device; on timeout, drops to emergency shell.
Mount point does not existsystemd drops to emergency shell immediately.
Invalid mount optionsystemd drops to emergency shell.

nofail Option

  • Adding nofail in /etc/fstab allows boot to continue even if the filesystem fails to mount.
  • Do NOT use nofail for critical filesystems, applications may start without their required storage, leading to data loss.

Managing Network Security

Managing Server Firewalls

Linux firewalls rely on netfilter, a kernel framework that allows packet filtering, NAT, and routing decisions.
RHEL enhances netfilter through nftables, providing:

  • Faster packet processing

  • Faster rule updates

  • Unified IPv4/IPv6 handling

  • A single management tool: nft

Older tools like iptables, ip6tables, arptables, and ebtables are deprecated.

What is firewalld?

firewalld is a dynamic firewall manager that uses nft under the hood. It organizes network traffic using zones, each representing a trust level. Each zone defines which services, ports, and protocols are allowed.

Firewalld selects a zone based on:

  1. Source IP

  2. Incoming network interface

  3. Default zone (if no other mapping applies)

The default zone is initially public.

Predefined Zones

ZoneDefault Behavior
trustedAllow all traffic
home / internalAllow common client services (ssh, mdns, samba-client, ipp-client, dhcpv6-client)
workAllow ssh, ipp-client, dhcpv6-client
public (default)Allow ssh, dhcpv6-client only
externalMasquerading enabled for IPv4; allow ssh
dmzAllow ssh
blockReject all incoming traffic
dropDrop all incoming traffic silently

Predefined Services

Firewalld includes built-in service definitions for common protocols.

ServicePorts
ssh22/tcp
dhcpv6-client546/udp
ipp-client631/udp
samba-client137/udp, 138/udp
mdns5353/udp

To list all the service execute the command firewall-cmd --get-services

Managing Firewalld from the Command Line

The firewall-cmd command interacts with the firewalld dynamic firewall manager.

CommandExplanation
firewall-cmd --get-default-zoneQuery the current default zone.
firewall-cmd --set-default-zone=ZONESet the default zone for both runtime and permanent configuration.
firewall-cmd --get-zonesList all available zones.
firewall-cmd --get-active-zonesList all zones currently in use (interfaces or sources assigned).
firewall-cmd --add-source=CIDR [--zone=ZONE]Route all traffic from a specific IP/network into the specified zone. If no zone is provided, the default zone is used.
firewall-cmd --remove-source=CIDR [--zone=ZONE]Remove a source-based zone assignment.
firewall-cmd --add-interface=INTERFACE [--zone=ZONE]Assign a network interface to a zone. If no zone is provided, the default zone is used.
firewall-cmd --change-interface=INTERFACE [--zone=ZONE]Move an interface to a different zone. If no zone is provided, the default zone is used.
firewall-cmd --list-all [--zone=ZONE]Show all settings for a zone (interfaces, sources, services, ports). If no zone is provided, the default zone is used.
firewall-cmd --list-all-zonesRetrieve configuration details for every zone.
firewall-cmd --add-service=SERVICE [--zone=ZONE]Allow traffic for a specific service. If no zone is provided, the default zone is used.
firewall-cmd --remove-service=SERVICE [--zone=ZONE]Remove an allowed service from a zone. If no zone is provided, the default zone is used.
firewall-cmd --add-port=PORT/PROTOCOL [--zone=ZONE]Allow traffic for a specific port/protocol. If no zone is provided, the default zone is used.
firewall-cmd --remove-port=PORT/PROTOCOL [--zone=ZONE]Remove an allowed port/protocol from a zone. If no zone is provided, the default zone is used.
firewall-cmd --reloadReload firewalld and apply permanent configuration.

Example:

  • These commands set the default firewalld zone to dmz, route all traffic from the 192.168.0.0/24 network to the internal zone, and enable the MySQL service within that zone.

  • [root@host ~]# firewall-cmd --set-default-zone=dmz
    [root@host ~]# firewall-cmd --permanent --zone=internal \
    --add-source=192.168.0.0/24
    [root@host ~]# firewall-cmd --permanent --zone=internal --add-service=mysql
    [root@host ~]# firewall-cmd --reload
Managing SELinux Port Labeling

SELinux not only controls files and processes, it also enforces rules on network ports.
Every port has an SELinux type label, and services are allowed to bind only to ports with permitted labels.

Example SELinux port labels:

  • ssh_port_t → ports 22/tcp

  • http_port_t → ports 80, 443, 8008, etc.

If a service tries to use a non-standard port, SELinux may block it unless you update the port label.

Viewing SELinux Port Labels

  • To get an overview of all the current port label assignments, run the semanage port -l command.
  • The output will consist of 3 columns. port_label_t, tcp|udp, and comma separated list of ports
    • [root@host ~]# semanage port -l
      ...output omitted...
      
      http_cache_port_t    tcp    8080, 8118, 8123, 10001-10010
      http_cache_port_t    udp    3130
      http_port_t          tcp    80, 81, 443, 488, 8008, 8009, 8443, 9000
      
      ...output omitted...
      
  • To refine the search, use the grep command

Adding a New SELinux Port Label

  • If you want a service to listen on a custom port, add the port to an existing SELinux type.
  • To add a port to an existing port label (type), use the following syntax. semanage port -a -t port_label -p tcp|udp PORTNUMBER The -a adds a new port label, the -t denotes the type, the -p denotes the protocol.
  • Example:
    • [root@host~]# semanage port -a -t gopher_port_t -p tcp 71
  • To list only custom changes:
    • [root@host~]# semanage port -l -C
      SELinux Port Type   Proto   Port Number
      gopher_port_t       tcp     71
      

Removing a Port Label

  • The syntax for removing a custom port label is the same as the syntax for adding a port label, but instead of using the -a option (for Add), use the -d option (for Delete).
  • Example, to remove the binding of port 71/TCP to gopher_port_t:
    • [root@host ~]# semanage port -d -t gopher_port_t -p tcp 71

Modifying an Existing Port Label

  • More efficient than deleting and re-adding.

  • Example: Change port 71/tcp from gopher_port_t → http_port_t

    • [root@server ~]# semanage port -m -t http_port_t -p tcp 71
  • view the modification using the semanage port -l -c command

Running Containers

Introducing Containers

Containers offer a lightweight, isolated way to package and deploy applications along with their required libraries and dependencies. They eliminate conflicts caused by differing software versions on a host system and make applications portable across environments.

Why Containers?

Traditional deployments install applications and required libraries directly on the OS, causing issues such as:

  • Conflicting software versions

  • Applications depending on outdated or incompatible libraries

  • Difficulty moving applications between environments

A container solves this by packaging the application with its runtime environment, isolating it from the host and other applications.

Containers vs Virtual Machines

Virtual Machines

  • Run multiple full operating systems on one physical system

  • Require a hypervisor

  • Each VM contains its own OS → heavier, slower to boot

Containers

  • Share the host OS kernel

  • Only package the application + dependencies

  • Lightweight, fast to start, low resource usage

  • Provide process, network, and filesystem isolation

Not all applications fit well in containers, especially those requiring very low-level hardware access.

How Containers Work

RHEL uses core Linux technologies:

  • cgroups → control and limit CPU, memory, I/O

  • namespaces → isolate process IDs, networking, mounts

  • SELinux & Seccomp → strong security boundaries

Container Images

Containers run from container images, which are:

  • Immutable templates bundling the application + dependencies

  • Built using standards such as OCI (Open Container Initiative)

  • Portable across compatible hosts

Images typically include Application code, Runtime (Python, Java, Node.js, etc.), Required libraries, Configuration files, and Metadata

Container Architecture Best Practices

Instead of placing all components in One large container with web server + database + messaging, keep Separate containers for each component

This improves maintainability, scalability, and security.

Tools for Managing Containers in RHEL

RHEL provides OCI-compatible tools:

ToolPurpose
podmanRun and manage containers/images (daemonless)
skopeoInspect, copy, delete, and sign container images
buildahBuild new container images

These tools replace Docker for most use cases and work without a background daemon.

Rootless Containers

Containers can be run:

  • As root → full privileges but less secure

  • As unprivileged users (rootless) → safer but cannot bind to ports <1024

  • A rootless container cannot expose port 80 unless mapped to a higher unprivileged port.

Containers at Scale

  • Kubernetes orchestrates large container environments, providing automated scaling, load balancing, self-healing, and controlled rollouts/rollbacks.

  • It manages containers across an entire cluster, ensuring reliability and efficient resource usage.

  • OpenShift, Red Hat’s enterprise Kubernetes platform, adds enhanced security, multi-tenancy, developer-friendly workflows, monitoring, and a web-based management interface.

  • Together, they provide a complete solution for deploying, managing, and scaling containerized applications in production.

Running a Basic Container

This section demonstrates how to install container tools and run a simple rootless container on Red Hat Enterprise Linux.

Installing Container Tools

  • Install the recommended container tools module:

    • [root@host ~]# yum module install container-tools
  • This installs the core utilities:

    • podman – run and manage containers

    • skopeo – inspect and copy container images

Understanding Container Registries

  • A container registry stores container images that can be pulled and run locally.
  • Red Hat provides trusted registries:
    • registry.redhat.io – Red Hat supported images

    • registry.connect.redhat.com – Certified third-party images

  • Always use trusted registries to avoid running unverified code.

Container Image Naming Format

  • Container images follow this fully qualified naming format:

    • registry_name/user_name/image_name:tag
  • registry_name: The container registry where the image is stored, usually a fully qualified domain name (for example, registry.redhat.io).

  • user_name: The user or organization namespace that owns the image.

  • image_name: The unique name of the image within the user or organization namespace.

  • tag: Identifies the image version. If no tag is specified, the latest tag is used by default.

Pulling a Container Image

  • Use Podman to pull an image from a registry.
  • The podman pull command pulls the image you specify from the registry and saves it locally
    • [user@host ~]$ podman pull registry.access.redhat.com/ubi8/ubi:latest
      Trying to pull registry.access.redhat.com/ubi8/ubi:latest...
      Getting image source signatures
      Copying blob 77c58f19bd6e: 70.54 MiB / 70.54 MiB [=========================] 10s
      Copying blob 47db82df7f3f: 1.68 KiB  / 1.68 KiB  [===========================] 10s
      Copying config a1f8c9699786: 4.26 KiB / 4.26 KiB [==========================] 0s
      Writing manifest to image destination
      Storing signatures
      a1f8c969978652a6d1b2dfb265ae0c6c346da69000160cd3ecd5f619e26fa9f3
  • Podman stores images locally and you can list them using the podman images command
    • [user@host ~]$ podman images
      REPOSITORY                                   TAG      IMAGE ID         CREATED        SIZE
      registry.access.redhat.com/ubi8/ubi          latest   a1f8c9699786     5 weeks ago    211 MB

Running an Interactive Container

  • The podman run command creates and starts a new container from the image.
  • Use the -it options to interact with the container if required. It allocates terminal to the container.
    • [user@host ~]$ podman run -it registry.access.redhat.com/ubi8/ubi:latest
      [root@8b032455db1a /]#
  • Type exit and press enter to exit from the container

Running a Named Container

  • Along with the podman run command use the –name option to provide a name to the container
    • [user@host ~]$ podman run -it --name=rhel8 registry.access.redhat.com/ubi8/ubi /bin/bash
      [root@c20631116955 /]# cat /etc/os-release
      NAME="Red Hat Enterprise Linux"
      VERSION="8.2 (Ootpa)"
      ID="rhel"
      ID_LIKE="fedora"
      VERSION_ID="8.2"
      PLATFORM_ID="platform:el8"
      PRETTY_NAME="Red Hat Enterprise Linux 8.2 (Ootpa)"
      ANSI_COLOR="0;31"
      CPE_NAME="cpe:/o:redhat:enterprise_linux:8.2:GA"
      HOME_URL="https://www.redhat.com/"
      BUG_REPORT_URL="https://bugzilla.redhat.com/"
      REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
      REDHAT_BUGZILLA_PRODUCT_VERSION="8.2"
      REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
      REDHAT_SUPPORT_PRODUCT_VERSION="8.2"
      [root@c20631116955 /]# exit
      exit
      [user@host ~]$

Running a One-Time Command

  • Run a quick command in a container without interacting with it, and automatically remove the container afterward.

    • [user@host ~]$ podman run --rm registry.access.redhat.com/ubi8/ubi cat /etc/osrelease

Important Podman Options

OptionDescription
-iInteractive input
-tAllocate terminal
-dRun container in background
--rmRemove container after exit
--nameAssign container name

Container Isolation Basics

  • Containers use Linux namespaces to isolate processes and users.

  • View the processes running inside the container:
    • [user@host ~]$ podman run -it registry.access.redhat.com/ubi7/ubi /bin/bash
      [root@ef2550ed815d /]# ps aux
      USER   PID  %CPU  %MEM   VSZ    RSS   TTY   STAT  START  TIME  COMMAND
      root     1  4.5   0.1  11840   2904  pts/0  Ss   22:10  0:00  /bin/bash
      root    15  0.0   0.1  51768   3388  pts/0  R+   22:10  0:00  ps aux
  • The user name and ID inside the container is different from the user name and ID on the host machine:
    • [root@ef2550ed815d /]# id
      uid=0(root) gid=0(root) groups=0(root)
      [root@ef2550ed815d /]# exit
      exit
      [user@host ~]$ id
      uid=1000(user) gid=1000(user) groups=1000(user),10(wheel)
  • The container runs as root inside, but the user remains unprivileged on the host.
Finding and Managing Container Images

Configuring Container Registries

  • Podman uses the registries.conf file to determine which container registries it can search and use.
  • System-wide configuration is present in /etc/containers/registries.conf and user-specific (rootless) configuration is present in ~/.config/containers/registries.conf

    • [user@host ~]$ cat /etc/containers/registries.conf
      [registries.search]
      registries = ['registry.redhat.io', 'quay.io', 'docker.io']
      [registries.insecure]
      registries = []
      [registries.block]
      registries = []
  • Key sections in the file:

    • registries.search → registries Podman searches by default

    • registries.insecure → registries without TLS (not recommended)

    • registries.block → blocked registries

  • Use podman info command to view the podman registry configuration

Registry Security

  • Secure registries use TLS encryption

  • Insecure registries use HTTP or invalid certificates and must be explicitly listed

  • Some registries require authentication

  • Login to a private registry using the command podman login registry.redhat.io

Searching for Container Images

  • Use podman search to find images in registries.

  • Example: Search for images related to RHEL 8
    • [user@host ~]$ podman search registry.redhat.io/rhel8
      INDEX      NAME                                         DESCRIPTION                                   STARS  OFFICIAL  AUTOMATED
      redhat.io  registry.redhat.io/openj9/openj9-8-rhel8     OpenJ9 1.8 OpenShift S2I image for Java Apps        0
      redhat.io  registry.redhat.io/openjdk/openjdk-11-rhel8  OpenJDK S2I image for Java Applications on UBI       0
      redhat.io  registry.redhat.io/rhel8/rust-toolset        Rust and Cargo build system                        0
      ...output omitted...
  • Run the same command with the –no-trunc option to see longer image descriptions:
    • [user@host ~]$ podman search --no-trunc registry.access.redhat.com/rhel8

Useful Search Options

OptionDescription
--limit NLimit results
--filter stars=NMinimum star rating
--filter is-official=trueOfficial images
--tls-verify=falseDisable TLS verification

Using Red Hat Container Catalog

Red Hat provides certified container images through the Red Hat Container Catalog https://access.redhat.com/containers

Benefits:

  • Trusted & tested images

  • Security updates and vulnerability fixes

  • Fully compatible with podman

Inspecting Container Images

  • Use skopeo to inspect a remote image without pulling it actually.
    • [user@host ~]$ skopeo inspect docker://registry.redhat.io/rhel8/python-36
    • This shows metadata such as Image name, Version, Summary, and Labels.

  • Use podman inspect command to image information which is present locally.
    • [user@host ~]$ podman inspect registry.redhat.io/rhel8/python-36
    • This provides detailed configuration, exposed ports, and runtime settings.

Removing Local Container Images

  • Container images are immutable. Updates require downloading a new image and replacing the old one.
  • To remove a locally stored image, use the podman rmi command.
    • [user@host ~]$ podman images
      REPOSITORY                                   TAG     IMAGE ID         CREATED        SIZE
      quay.io/generic/rhel7                        latest  1d3b6b7d01e4     3 weeks ago    688 MB
      registry.redhat.io/rhel8/python-36           latest  e55cd9a2e0ca     6 weeks ago    811 MB
      registry.redhat.io/ubi8/ubi                  latest  a1f8c9699786     6 weeks ago    211 MB
      [user@host ~]$ podman rmi registry.redhat.io/rhel8/python-36:latest
      e55cd9a2e0ca5f0f4e0249404d1abe3a69d4c6ffa5103d0512dd4263374063ad
      [user@host ~]$ podman images
      REPOSITORY                                   TAG     IMAGE ID         CREATED        SIZE
      quay.io/generic/rhel7                        latest  1d3b6b7d01e4     3 weeks ago    688 MB
      registry.redhat.io/ubi8/ubi                  latest  a1f8c9699786     6 weeks ago    211 MB
  • Removing unused images helps free disk space and ensures systems use updated images.
Advanced Container Management

Containers often require network access and runtime configuration. Podman allows this without modifying container images.

Mapping Host Ports to Containers

  • Port mapping allows external clients to access services running inside containers.
  • Use -p option in the podman run command to map the host port to container port
  • Syntax:
    • podman run -p HOST_PORT:CONTAINER_PORT IMAGE
  • Example: Map host port 8000 to container port 8080
    • [user@host ~]$ podman run -d -p 8000:8080 registry.redhat.io/rhel8/httpd-24
  • The container runs in detached mode (-d) and serves traffic via port 8000 on the host.
  • Use podman port -a to view the port mappings
  • Make sure that the host firewall must allow the mapped port
    • [root@host ~]# firewall-cmd --add-port=8000/tcp
  • Ports below 1024 cannot be mapped unless Podman is run as root

Passing Environment Variables to Containers

  • Containers are commonly configured using environment variables instead of modifying images.

  • Use the command podman inspect IMAGE to view the supported variables.
    • [user@host ~]$ podman inspect registry.redhat.io/rhel8/mariadb-103:1-102
  • Container images often document variables in the usage or labels section.

  • Example: Running MariaDB with Environment Variables

    • [user@host ~]$ podman run -d --name container_name \
        -e MYSQL_USER=user_name \
        -e MYSQL_PASSWORD=user_password \
        -e MYSQL_DATABASE=database_name \
        -e MYSQL_ROOT_PASSWORD=mysql_root_password \
        -p 3306:3306 \
        registry.redhat.io/rhel8/mariadb-103:1-102
    • This starts a MariaDB container configured at runtime.

Listing Containers

  • To list all the running containers use podsman ps command, to list including the stopped containers use podman ps -a command.
    • [user@host ~]$ podman ps
      CONTAINER ID    IMAGE                                            COMMAND        CREATED          STATUS          PORTS                     NAMES
      89dd9b6354ba    registry.redhat.io/rhel8/mariadb-103:1-102        run-mysqld     10 minutes ago   Up 10 seconds  0.0.0.0:3306->3306/tcp    my-database
      [user@host ~]$ podman ps -a
      CONTAINER ID    IMAGE                                            COMMAND        CREATED          STATUS                     PORTS    NAMES
      30b743973e98    registry.redhat.io/rhel8/httpd-24:1-105           /bin/bash      17 minutes ago   Exited (0) 18 minutes ago  80/tcp   my-httpd
  • This displays the details includes:
    • Container ID.
    • Image associated with the container.
    • Command executed when the container started.
    • Date and time the container was started.
    • Total container uptime, if still running, or time since terminated.
    • Exposed ports and port forwarding details.
    • Container name

Managing Container Lifecycle

ActionCommandExample
Stop a container (graceful)podman stop CONTAINERpodman stop my-database
Restart a containerpodman restart CONTAINERpodman restart my-database
Kill a container (immediate)podman kill CONTAINERpodman kill my-database
Kill container with specific signalpodman kill -s SIGNAL CONTAINERpodman kill -s SIGKILL my-database
Remove a stopped containerpodman rm CONTAINERpodman rm my-database
Force remove a running containerpodman rm -f CONTAINERpodman rm -f my-database
Remove all stopped containerspodman rm -apodman rm -a
Remove all unused containerspodman container prunepodman container prune
Remove unused imagespodman image prunepodman image prune
Remove unused containers, images, volumespodman system prunepodman system prune
  • Containers must be stopped before removal unless -f is used.
  • Images used by containers cannot be removed unless containers are deleted or force options are used.
  • prune commands permanently delete unused resources.

Running Commands Inside a Container

  • The podman exec command starts an additional process inside an already running container, which is used to execute the command inside the container.
    • [user@host ~]$ podman exec 7ed6e671a600 cat /etc/redhat-release
      Red Hat Enterprise Linux release 8.2 (Ootpa)
      [user@host ~]$
  • The above examples is for executing a single command inside the container.
  • To start an interactive shell, use the -it option
    • [user@host ~]$ podman exec -it my_webserver /bin/bash
      bash-4.4$ hostname
      7ed6e671a600
      bash-4.4$ exit
      [user@host ~]$
  • Podman remembers the last container used in any command. You can use the -l option to replace the former container ID or name in the latest Podman command.
    • [user@host ~]$ podman exec -l cat /etc/redhat-release
      Red Hat Enterprise Linux release 8.2 (Ootpa)
      [user@host ~]$

Automatic Container Cleanup

  • To remove a container automatically when it exits use the command podman run --rm IMAGE COMMAND

  • Useful for short-lived or test containers.

Attaching Persistent Storage to a Container
  • By default, container storage is ephemeral, meaning all data is lost when the container is removed.
  • For applications like databases, logs, or uploads, you must attach persistent storage.

Why Persistent Storage Is Needed

  • Containers are temporary by design

  • Data stored inside a container is deleted when it stops or is removed

  • Persistent storage ensures data survives container restarts or replacements

Providing Persistent Storage from the Host

  • Podman can mount a host directory into a container.
  • The mounted directory exists outside the container lifecycle, so its data remains intact.
  • Common use cases such as Database data, Application logs, and User uploads.

Preparing the Host Directory

  • Before mounting, ensure:
    • Correct permissions and ownership

    • Proper SELinux context

  • Podman applies the required SELinux label automatically when using the :Z option.

Mounting a Host Directory into a Container

  • To mount a host directory to a container, add the –volume (or -v) option to the podman run command, specifying the host directory path and the container storage path, separated by a colon.
  • Host-mounted storage persists beyond container life and Works for both root and rootless containers
  • Syntax:
    • podman run -v host_dir:container_dir:Z IMAGE
    • host_dir → Directory on the host

    • container_dir → Path inside the container

    • :Z → Applies container_file_t SELinux context

  • Example: MariaDB with Persistent Data

    • [user@host ~]$ podman run -d --name mydb \
      -v /home/user/dbfiles:/var/lib/mysql:Z \
      -e MYSQL_USER=user \
      -e MYSQL_PASSWORD=redhat \
      -e MYSQL_DATABASE=inventory \
      registry.redhat.io/rhel8/mariadb-103:1-102
      
    • Database data remains even if the container is removed
    • A new container can reuse the same directory
Managing Containers as Systemd Services

Containers running critical services (web servers, databases) usually need to start automatically at boot. Podman integrates with systemd, allowing containers to be managed like regular services.

Why Use Systemd for Containers

  • Start containers automatically at boot

  • Restart containers on failure

  • Manage containers using systemctl

  • Works with rootless containers for better security

Running Containers as User Services

  • Systemd can manage user-level services, allowing non-root users to control containers.

  • By default, user services start only when the user logs in. To start them at system boot, to enable it run loginctl enable-linger and to disable it run loginctl disable-linger

    • [user@host ~]$ loginctl enable-linger
      [user@host ~]$ loginctl show-user user
      ...output omitted...
      Linger=yes
      [user@host ~]$ loginctl disable-linger
      [user@host ~]$ loginctl show-user user
      ...output omitted...
      Linger=no

Creating Systemd Unit Files for Containers

  • Podman can automatically generate a systemd unit file from an existing container.

  • User service files are stored in ~/.config/systemd/user/ directory.
    • [user@host ~]$ ls ~/.config/systemd/user/
      myapp.service
      [user@host ~]$ systemctl --user daemon-reload
      [user@host ~]$ systemctl --user enable myapp.service
      [user@host ~]$ systemctl --user start myapp.service

Generating a systemd Service from a Container

  • Run a container first using the podman run command.
    • [user@host ~]$ podman run -d --name web \
      -v /home/user/www:/var/www:Z \
      registry.redhat.io/rhel8/httpd-24
  • Generate the systemd unit file using the podman generate systemd command.
    • [user@host ~]$ cd ~/.config/systemd/user/
      [user@host user]$ podman generate systemd --name web --files --new
      /home/user/.config/systemd/user/container-web.service
  • –new
    • Creates container on service start

    • Removes container on service stop

    • Ideal when using persistent storage

  • –files
    • Instructs Podman to generates the unit file in the current directory
  • Reload systemd and Enable the Service

    • [user@host ~]$ systemctl --user daemon-reload
      [user@host ~]$ systemctl --user enable container-web
      [user@host ~]$ systemctl --user start container-web

Managing Containers with systemctl

  • Use the systemctl command to control(Start/Stop/Status) your containers.
    • [user@host ~]$ systemctl --user start container-web
      [user@host ~]$ systemctl --user stop container-web
      [user@host ~]$ systemctl --user status container-web
  • Do not use podman start/stop once systemd manages the container, Always use systemctl.

Root vs Rootless Container Services

FeatureRootless ContainersRoot Containers
Service file location~/.config/systemd/user//etc/systemd/system/
PrivilegesNon-root userRoot
--user flagRequiredNot required
loginctl lingerRequiredNot required

When to Use Systemd vs Kubernetes

  • Systemd: Small setups, single host, few containers

  • Kubernetes / OpenShift: Production, scaling, high availability

Improving Command-Line Prductivity

Bash Script

A Bash script is a text file containing a sequence of Linux commands executed in order. Scripts help automate repetitive tasks, reduce errors, and improve efficiency, making them essential for system administrators.

Creating a Bash Script

  1. Create a new file using a text editor (vim, nano, etc.).

  2. Write commands line by line.

  3. Make the file executable.

Advanced editors like vim highlight syntax errors, making scripting easier.

Specifying the Interpreter

  • Every Bash script should start with a shebang, which tells the system which interpreter to use.
  • #!/bin/bash This ensures the script always runs using Bash.

Making the Script Executable

  • Grant execute permission before running the script chmod +x script.sh

  • Run it using ./script.sh
  • If the script is placed in a directory listed in $PATH (such as ~/bin), you can run it by name.

Quoting Special Characters

Some characters have special meaning in Bash. To use them literally, apply quoting.

  • Backslash (\): Escapes a single character.

  • Single Quotes (' '): Preserves text exactly as typed (no variable or command substitution).

  • Double Quotes (" "): Prevents globbing but allows variable and command substitution.

  • [user@host ~]$ echo # not a comment
    
    [user@host ~]$ echo \# not a comment
    # not a comment
    [user@host ~]$ echo # not a comment #
    
    [user@host ~]$ echo \# not a comment #
    # not a comment
    [user@host ~]$ echo \# not a comment \#
    # not a comment #
    [user@host ~]$ echo '# not a comment #'
    # not a comment #
    [user@host ~]$ var=$(hostname -s); echo $var
    host
    [user@host ~]$ echo "***** hostname is ${var} *****"
    ***** hostname is host *****
    [user@host ~]$ echo Your username variable is \$USER.
    Your username variable is $USER.
    [user@host ~]$ echo "Will variable $var evaluate to $(hostname -s)?"
    Will variable host evaluate to host?
    [user@host ~]$ echo 'Will variable $var evaluate to $(hostname -s)?'
    Will variable $var evaluate to $(hostname -s)?
    [user@host ~]$ echo "\"Hello, world\""
    "Hello, world"
    [user@host ~]$ echo '"Hello, world"'
    "Hello, world"

Sending Output to STDOUT and STDERR

  • By default, commands write to STDOUT. Use >&2 to write error messages to STDERR.
  • Best practice is to redirect the status message to STDOUT and error messages to STDERR
    • [user@host ~]$ cat ~/bin/hello
      #!/bin/bash
      echo "Hello, world"
      [user@host ~]$ hello
      Hello, world
    • [user@host ~]$ cat ~/bin/hello
      #!/bin/bash
      echo "Hello, world"
      echo "ERROR: Houston, we have a problem." >&2
      [user@host ~]$ hello 2> hello.log
      Hello, world
      [user@host ~]$ cat hello.log
      ERROR: Houston, we have a problem.

Why echo is Important in Scripts

  • Displays progress messages

  • Shows variable values for debugging

  • Helps identify where scripts fail

Adding simple echo statements is one of the easiest ways to debug scripts.

Running Commands More Efficiently Using Loops

Why Use Loops in Shell Scripts?

System administrators frequently perform repetitive tasks, such as:

  • Running a command on multiple systems

  • Processing multiple files

  • Repeating checks until a task completes

Bash loops help automate these repetitive actions cleanly and efficiently.

Using for Loops

  • A for loop executes commands once for each item in a list.
  • Syntax:
    • for VARIABLE in LIST; do
        COMMAND $VARIABLE
      done
  • Example:
    • [user@host ~]$ for HOST in host1 host2 host3; do echo $HOST; done
      host1
      host2
      host3
      [user@host ~]$ for HOST in host{1,2,3}; do echo $HOST; done
      host1
      host2
      host3
      [user@host ~]$ for HOST in host{1..3}; do echo $HOST; done
      host1
      host2
      host3
      [user@host ~]$ for FILE in file*; do ls $FILE; done
      filea
      fileb
      filec
      [user@host ~]$ for FILE in file{a..c}; do ls $FILE; done
      filea
      fileb
      filec
      [user@host ~]$ for EVEN in $(seq 2 2 10); do echo "$EVEN"; done
      2
      4
      6
      8
      10
  • Use double quotes around variables to avoid word-splitting issues.

Understanding Exit Codes

  • Every command returns an exit code:
    • 0 → success

    • Non-zero → failure

  • The exit code of the last command is stored in $?
  • [user@host bin]$ cat hello
    #!/bin/bash
    echo "Hello, world"
    exit 0
    [user@host bin]$ ./hello
    Hello, world
    [user@host bin]$ echo $?
    0

Testing Script Inputs

Bash provides test operators to validate numbers, strings, and variables.

  • Numeric Comparisons

Operator Meaning
-eq equal
-ne not equal
-gt greater than
-lt less than
-ge greater or equal
-le less or equal
    • [user@host ~]$ [ 1 -eq 1 ]; echo $?
      0
      [user@host ~]$ [ 2 -lt 2 ]; echo $?
      1
      
  • String Comparisons
    • [user@host ~]$ [ abc = abc ]; echo $?
      0
      [user@host ~]$ [ abc == def ]; echo $?
      1
      [user@host ~]$ [ abc != def ]; echo $?
      0
  • String Unary
    • [user@host ~]$ STRING=''; [ -z "$STRING" ]; echo $?
      0
      [user@host ~]$ STRING='abc'; [ -n "$STRING" ]; echo $?
      0

Conditional Structures

  • It allow a script to make decisions by executing different commands based on whether a specified condition is true or false.
  • Bash checks conditions top to bottom and executes the first match.
  • Syntax: if/then Statement
    • if <CONDITION>; then
          <STATEMENT>
          ...
          <STATEMENT>
      fi
  • Example:
    • [user@host ~]$ if [ -f /etc/passwd ]; then
      > echo "File exists"
      > fi
  • Syntax: if/then/else Statement
    • if <CONDITION>; then
          <STATEMENT>
          ...
          <STATEMENT>
      else
          <STATEMENT>
          ...
          <STATEMENT>
      fi
  • Example:
    • [user@host ~]$ if [ "$USER" = "root" ]; then
      > echo "Running as root"
      > else
      > echo "Running as regular user"
      > fi
  • Syntax: if/then/elif/then/else Statement
    • if <CONDITION>; then
          <STATEMENT>
          ...
          <STATEMENT>
      elif <CONDITION>; then
          <STATEMENT>
          ...
          <STATEMENT>
      else
          <STATEMENT>
          ...
          <STATEMENT>
      fi
  • Example:
    • [user@host ~]$ if systemctl is-active mariadb > /dev/null 2>&1; then
      > mysql
      > elif systemctl is-active postgresql > /dev/null 2>&1; then
      > psql
      > else
      > sqlite3
      > fi
Matching Text in Command Output with Regular Expressions

Regular expressions (regex) let you search and filter text using powerful patterns instead of fixed strings. Tools like grep, vim, and less all support regex for searching logs, config files, and command output.

Regular Expression

  • Exact Match
    • A simple regex is just plain text. It matches the same characters in the same order.
    • Example text:
      • cat
        dog
        concatenate
        category
        educated
        vindication
    • Regex: cat
      Matches: cat, concatenate, category, educated, vindication (because “cat” appears inside them).
  • Anchors: start and end of line
    • Use anchors to control where in the line the pattern must match.
      • ^ – beginning of line

      • $ – end of line

    • Examples (same text as above):
      • ^cat → matches lines starting with “cat”
      • dog$ → matches lines ending with “dog”
      • ^cat$ → matches a line that is exactly cat
  • Wildcards and character sets

    • . (dot): matches any single character (except newline).

      • c.t → matches cat, cot, cut, etc.

    • [ ... ]: character set; match one of the listed characters.

      • c[ao]t → matches cat or cot

      • c[aou]t → matches cat, cot, cut

Pattern Description Example
. Matches any single character. a.b matches abb, a-b.
? Makes the previous character or group optional (0 or 1 time). colou?r matches color and colour.
* Matches the previous item 0 or more times. ba* matches b, ba, baaa.
+ Matches the previous item 1 or more times. ba+ matches ba, baa, but not b.
{n} Matches the previous item exactly n times. a{3} matches aaa only.
{n,} Matches the previous item n or more times. a{2,} matches aa, aaa, aaaa
{,m} Matches the previous item at most m times. a{,2} matches "", a, aa.
{n,m} Matches the previous item between n and m times. a{2,4} matches aa, aaa, aaaa.
[[:alnum:]] Any letter or digit (a–z, A–Z, 0–9). [[:alnum:]] matches a, Z, 5.
[[:alpha:]] Any letter, upper or lower case. [[:alpha:]] matches a, Z, but not 5.
[[:blank:]] Space or tab character. [[:blank:]] matches a space or tab between words.
[[:cntrl:]] Control characters (non-printable, like newline). Used rarely; often avoided in simple text searches.
[[:digit:]] Any decimal digit 0–9. [[:digit:]] matches 3 in R3.
[[:graph:]] Any visible character (not space). Matches letters, digits, punctuation, but not space.
[[:lower:]] Any lowercase letter. [[:lower:]]+ matches hello but not Hello.
[[:print:]] Any printable character including space. Matches normal text characters you can see.
[[:punct:]] Any punctuation character. Matches !, ?, ., ,, etc.
[[:space:]] Any whitespace (space, tab, newline, etc.). [[:space:]]+ matches spaces and tabs between words.
[[:upper:]] Any uppercase letter. [[:upper:]] matches H in Hello.
[[:xdigit:]] Any hexadecimal digit (0–9, a–f, A–F). [[:xdigit:]] matches A in 0xA3.
\b Matches a word boundary (edge of a word). \bcat\b matches cat, but not concatenate.
\B Matches where there is no word boundary. \Bcat\B matches educate, not lone cat.
\< Matches the beginning of a word (in some tools). \<cat matches cat at the start of a word.
\> Matches the end of a word (in some tools). cat\> matches cat at the end of a word.
\w Matches word characters: letters, digits, and underscore. \w+ matches hello_123 as one word.
\W Matches non-word characters (not letters, digits, underscore). \W+ matches !, ?, spaces, etc.
\s Matches any whitespace (space, tab, newline). \s+ matches multiple spaces between words.
\S Matches any non-whitespace character. \S+ matches a block of non-space text.

Matching with grep

  • grep searches text for lines matching a regex. Basic usage grep 'PATTERN' FILE

  • Example: grep lines starting with “computer”
    • [user@host ~]$ grep '^computer' /usr/share/dict/words
      computer
      computerese
      computerise
  • The grep command can be used in conjunction with other commands using a pipe operator (|).
    • [root@host ~]# ps aux | grep chrony
      chrony 662 0.0 0.1 29440 2468 ? S 10:56 0:00 /usr/sbin/chronyd
  • grep Options
Option Description
-i Case-insensitive search
-v Invert match (show lines not matching the pattern)
-r Recursive search in directories
-A N Show N lines after each match
-B N Show N lines before each match
-e Add another pattern (logical OR with others)
  • Example: case-insensitive search.

    • Search for serverroot in Apache config, ignoring case

    • [root@host ~]$ grep -i 'serverroot' /etc/httpd/conf/httpd.conf
  • Example: show lines that do not match

    • Show all lines in /etc/hosts that do not contain server (case-insensitive)

    • [root@host ~]$ grep -vi 'server' /etc/hosts
  • Example: hide comment lines

    • Remove comment lines (starting with # or ;) from a file view

    • [root@host ~]$ grep -v '^[#;]' /etc/ethertypes
  • Example: multiple patterns with -e

    • Search /var/log/secure for any of these: pam_unix, user root, or Accepted publickey

    • [root@host ~]$ grep -e 'pam_unix' -e 'user root' -e 'Accepted publickey' /var/log/secure

Searching inside vim / less

Both vim and less support regex-style searching:

  • Press /, type your pattern, and press Enter

  • Press n to go to the next match, N for the previous

0 0 votes
Article Rating
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Thanks for your interest!

Content for this is getting ready and will be published soon.

0
Would love your thoughts, please comment.x
()
x