Learning Linux#

Linux has become essential in todays IT world as it the mostly used operating system for enterprise and cloud solutions.

Introduction to the shell#

The shell is for most Unix users the main interface to an Unix-based system like Linux or Mac OS X. The shell is a command line interface to the system and comes in different flavors like bash, tcsh, ksh, zsh, etc. While multiple shells exist, the most popular shells used are bash for interactive use and sh for system scripting.

A lot can be configured in the shell, for example the prompt. The prompt is the string that is displayed before the command line and can be changed by modifying the PS1 variable. The prompt normally also shows the current working directory and the current user, but this is a convention. A second convention is that if the prompt ends with a #, then your in a shell with root privileges and when it ends with a $, then you are in a shell with normal user privileges.

The prompt shows the # when the shell is in a root user context#
# whoami
root
The prompt shows the $ when the shell is in a normal user context#
$ whoami
user01

This convention is used in all examples on this site together with the assumption that the user is logged in as user01 and is by default located in the /home/user01 directory.

Using su#

Every shell is running under the account that was used to login with. This account also refered to as an user is member of a primary group that is required, and can also have up to 16 or 32 secondary groups depending is Network File System (NFS) is used or not.

With the command id you can get the primary group and the secondary groups of the user that is currently logged in.

The command id shows the primary group and the secondary groups of the user that is logged in#
$ id
uid=1000(user01) gid=1000(user01) groups=1000(user01)

The command can also be extended to get the groups of other users defined on the system as is show below for the user root.

The command id can also show the primary and secondary group for other users#
$ id root
uid=0(root) gid=0(root) groups=0(root)

A shell runs as the user that is logged in. This is the user that is used to run the command line and to see the effective user that is used to run the command whoami.

Show the effective user for the shell#
# whoami
root

The effective user can be changed by using the command su. This command changes the user that the shell runs as, but to accomplish this the password of the target user is required.

Change the effective user to the user root#
$ su root
password:

By default only the effective is changed by the su command, but the environment is not changed. To change the environment as well, use the - option and the environment is also changed when the user changes.

$ su - root
$ su - root -c "env"
$ su root -c "env"

Using sudo#

$ sudo -l
$ sudo su -
$ sudo cat /var/log/messages
$ sudoedit /etc/hosts

Monitoring the system and processes#

Process state:

  • D - Uninterruptable Sleep

  • R - Running or Runnable

  • S - Sleeping

  • T - Stopped or Traced

  • Z - Zombie

$ uptime
$ w

Showing who is logged on

$ who

cat /proc/cpuinfo

$ lscpu
Architecture:            x86_64
  CPU op-mode(s):        32-bit, 64-bit
  Address sizes:         39 bits physical, 48 bits virtual
  Byte Order:            Little Endian
CPU(s):                  4
  On-line CPU(s) list:   0-3
Vendor ID:               GenuineIntel
  Model name:            Intel(R) Core(TM) i5-6260U CPU @ 1.80GHz
...

Showing processes#

$ ps -ef
$ pstree
$ pgrep <process name>

Process priority#

Default value is 0

  • 0-19: can be set by the user

  • -20- -1: can only be set by root

$ nice <command>
$ nice -n 15 <command>
$ renice -n 7 <PID>
$ renice -n 7 $(pgrep <process name>)

Working with files#

Archiving and compression#

# tar cf archive.tar file1 file2 file3
# tar cf /root/etcbackup.tar /etc
# tar tf /root/etcbackup.tar

Compression methods:

  • z - gzip

  • j - bzip

  • J - xz

# tar czf /root/etcbackup.tar.gz /etc
# tar cjf /root/logbackup.tar.bz2 /var/log
# tar cJf /root/sshbackup.tar.xz /etc/ssh
# mkdir /root/logbackup
# cd /root/logbackup
# tar xjf /root/logbackup.tar.bz2
# mkdir /root/etcbackup
# cd /root/etcbackup
# tar xf /root/etcbackup.tar

SCP#

Copy a file to a remote host:

$ scp /etc/sudo.conf /etc/sudoers server02:/tmp

Copy a file to a remote host as root:

$ scp /etc/sudo.conf [email protected]:/tmp

Copy a file from a remote host as root to the current directory:

$ scp [email protected]:/tmp/sudo.conf .

indien je hele directories wilt overzetten moet je de -r vlag meegeven:

With the -r flag scp will copy the contents of the directory:

$ scp -r /etc [email protected]:~

SFTP#

$ sftp [email protected]
[email protected]'s password:
Connected to localhost.

sftp> ls
bin file.sh output
sftp> mkdir test
sftp> cd test
sftp> put /etc/hosts
Uploading /etc/hosts to /home/user/test/hosts
/etc/hosts 100% 510 0.5KB/s 00:00

Rsync#

Rsync is a fast, reliable, efficient, secure, and portable file transfer. The example below will copy the contents of the directory /etc to the directory /srv/rsync/etc/:

$ rsync -av /etc /srv/rsync

The example below will copy the contents of the directory /etc/ to the directory /srv/rsync/:

$ rsync -av /etc/ /srv/rsync

Copy log files from server01 to /tmp on the current host:

$ rsync -av server01:/var/log /tmp

Remote login with SSH keys#

$ ssh-keygen
$ scp ~/.ssh/id_rsa.pub [email protected]:~/.ssh/myhost.pub
$ cd .ssh
$ cat myhost.pub >> authorized_keys
$ ssh-copy-id [[email protected]]remotehost

Using Manual pages#

Introduction to manual pages#

On Unix and Unix-like systems the man command shows a man page, short for manual page, and covers topics like formal standards and conventions, but also computer programs, libraries, and system calls. These man-pages are by default in English but have been translated into many languages over the years. On most systems, the English language is available by default, but to reduce the size of virtual machines the man-pages have to be installed manually with the command below.

$ yum install man-pages

The man command itself has also a manual page explaining how the command works but also tells which section covers which area. It also gives additional information on how a manual page is structured. Knowing how man works is essential to do your job as a systems administrator or Linux engineer.

$ man man
MAN(1)                        Manual pager utils                        MAN(1)

NAME
    man - an interface to the system reference manuals

SYNOPSIS
    man [man options] [[section] page ...] ...
    man -k [apropos options] regexp ...
    man -K [man options] [section] term ...
    man -f [whatis options] page ...
    man -l [man options] file ...
    man -w|-W [man options] page ...

Manual pages have been divided into sections and the main sections are listed below. Subsections do exist but are most of the time not interesting for end-users to know as they cover legacy systems like the X Windows System, Tcl/Tk, or POSIX specifications.

Section

Description

1

Executable programs or shell commands

2

System calls

3

Library functions, covering, in particular, the C standard library

4

Special files (usually devices, those found in /dev) and drivers

5

File formats and conventions

6

Games and screensavers

7

Miscellaneous

8

System administration commands and daemons

9

Kernel routines

Using the man command#

In the previous example the command man man showed the manual page for man, but this works for other commands supplied by the Linux distribution as well like the passwd command.

$ man passwd
PASSWD(1)                       User utilities                       PASSWD(1)

NAME
    passwd - update user's authentication tokens

SYNOPSIS
    passwd  [-k]  [-l]  [-u  [-f]]  [-d] [-e] [-n mindays] [-x maxdays] [-w
    warndays] [-i inactivedays] [-S] [--stdin] [-?] [--usage] [username]

DESCRIPTION
    The passwd utility is used to update user's authentication token(s).
...

With man -k passwd we can see which other pages may exist with the keyword passwd and it lists passwd (1) and passwd (5) beside other pages it has found.

$ man -k passwd
chgpasswd (8)        - update group passwords in batch mode
chpasswd (8)         - update passwords in batch mode
fgetpwent_r (3)      - get passwd file entry reentrantly
getpwent_r (3)       - get passwd file entry reentrantly
gpasswd (1)          - administer /etc/group and /etc/gshadow
grub2-mkpasswd-pbkdf2 (1) - Generate a PBKDF2 password hash.
htpasswd (1)         - Manage user files for basic authentication
lpasswd (1)          - Change group or user password
mkpasswd (1)         - Overfeatured front end to crypt(3)
openssl-passwd (1ssl) - compute password hashes
pam_localuser (8)    - require users to be listed in /etc/passwd
pam_passwdqc (8)     - Password quality-control PAM module
passwd (1)           - update user's authentication tokens
passwd (5)           - password file
passwd2des (3)       - RFS password encryption
passwdqc.conf (5)    - libpasswdqc configuration file
pwhistory_helper (8) - Helper binary that transfers password hashes from pass...
saslpasswd2 (8)      - set a user's sasl password
smbpasswd (5)        - The Samba encrypted password file
sslpasswd (1ssl)     - compute password hashes
vncpasswd (1)        - change the VNC password

The man command allows to specify the section for the manual page you want to see. By simply adding section 1 before the page on the command line man retrieves the manual page from the Executable programs or shell commands section.

$ man 1 passwd
PASSWD(1)                       User utilities                       PASSWD(1)

NAME
    passwd - update user's authentication tokens

SYNOPSIS
    passwd  [-k]  [-l]  [-u  [-f]]  [-d] [-e] [-n mindays] [-x maxdays] [-w
    warndays] [-i inactivedays] [-S] [--stdin] [-?] [--usage] [username]

DESCRIPTION
    The passwd utility is used to update user's authentication token(s).
...

When the command is changed to show section 5 the manual page for passwd is also shown, but from the section File formats and conventions, the manual page for the command passwd is shown. Here we see the difference between the two sections and how this manual page explains the file format in which the password hashes are stored.

$ man 5 passwd
PASSWD(5)                  Linux Programmer's Manual                 PASSWD(5)

NAME
    passwd - password file

DESCRIPTION
    The  /etc/passwd file is a text file that describes user login accounts
    for the system.  It should have read permission allowed for  all  users
    (many  utilities,  like ls(1) use it to map user IDs to usernames), but
    write access only for the superuser.
...

For most new end-users who are still discovering Linux the whatis command is a good starting point. It lists all pages that contain the keyword you specify. The same can be accomplished with man -f <keyword>.

$ whatis passwd
passwd (1)           - update user's authentication tokens
openssl-passwd (1ssl) - compute password hashes
passwd (5)           - password file
$ man -f passwd
passwd (1)           - update user's authentication tokens
openssl-passwd (1ssl) - compute password hashes
passwd (5)           - password file

Sometimes keywords aren’t enough and the man can be used to do a global search on all manual pages. With man -K <keyword> it searches and displays all pages that contain the keyword.

$ man -K passwd

Alternatives to man command#

The manual page system dates back to the early days of the Unix system written by Dennis Ritchie and Ken Thompson, and has many updates and is available on almost every Unix-based system like Solaris, Linux, FreeBSD, OpenBSD, NetBSD, etc. This means the command below works on most of them the same, but how certain flags are used differs.

$ man tar

Alternatives do exist as the info system created by the GNU Project.

$ info tar

Or the curses-based lynx-style info browser.

$ pinfo tar

Useful commands#

Stream editor for filtering and transforming text#

Replace only the first Hello instance per line

$ echo "Hello World. Hello World." | sed 's/Hello/Bye/'
Bye World. Hello World.

Replace all Hello instances per line

$ echo "Hello World. Hello World." | sed 's/Hello/Bye/g'
Bye World. Bye World.

Replace only the second Hello instance per line

$ echo "Hello World. Hello World." | sed 's/Hello/Bye/2'
Bye World. Bye World.

Replace only the first Hello instance per line if the line contains the word World

$ echo "Hello World. Hello World." | sed '/World/s/Hello/Bye/'
Bye World. Hello World.

Show line 3 to 5 from file

$ sed -n 3,5p file.txt

Show all lines except 3 to 5 from file

$ sed -n 3,5d file.txt

Execute sed commands from script.sed

$ sed -f script.sed file.txt

Remove all trailing spaces from file with -i

$ sed -i 's/\s+$//' file.txt

Delete lines matching pattern

$ sed '/^#/d' /etc/services

Delete lines except matching pattern

$ sed '/^#/!d' /etc/services

remove sections from each line of files#

Displaying the 1st field of each line, using tab as the field separator

$ cut -f1 file.txt

Displaying the 2th field using : as the field separator

$ echo x:y:z | cut -d: -f2
y

Displaying the 1st and 3th field using ` ` as the field separator

$ echo x y z | cut -d" " -f1,3
x z

Displaying fields in a certain range using ` ` as the field separator

$ echo x y z a b c | cut -d" " -f1-3,5
x y z b

Display fields selected by the -f option aren’t reordered when printing it

$ echo x y z | cut -d" " -f3,2,1
x y z

Display fields from the 2th field and beyond

$ echo x y z | cut -d" " -f2-
y z

When no separators exist the command cut treats every character as a field

$ echo xyz | cut -f2,3
xyz

pattern scanning and processing language#

$ echo a  b | awk '{print $2}'
b
$ echo a  b | awk '{print $2 $1}'
ba

translate or delete characters#

$ echo "Hello World" | tr [a-z] [A-Z]
HELLO WORLD
$ echo "Hello World" | tr [:lower:] [:upper:]
HELLO WORLD
$ echo "Hello World" | tr -d ' '
HelloWorld
$ echo "Hello  World" | tr -d ' '
HelloWorld
$ echo "Hello  World" | tr -s ' '
Hello World
$ echo "Hello $UID"
Hello 1000
$ echo "Hello $UID" | tr " " "\n"
Hello
1000
$ echo "Hello $UID" | tr -cd "[:digit:]\n"
1000
$ echo "Hello $UID" | tr -d "a-zA-Z"
 1000
$ echo "Hello\n$UID" | tr "\n" " "
Hello 1000

sort lines of text files#

$ sort

Numerical value sort

$ sort -n

Reverse sort

$ sort -r

Random sort

$ sort -R

Sort by month

$ sort -M

Sort by specific column

$ sort -k 2

Sort and remove duplicates

$ sort -u

Ingore case while sorting

$ sort -f

Sort by human numeric value

$ sort -h

output the first part of files#

$ head

output the last part of files#

$ tail

Filesystem and permissions#

The file system on Unix-based systems like Linux are a collection of directories and files in a hierarchy. It is similar to a tree structure. The root directory is the parent of all other directories and files, and you can navigate from one directory to another. This is different from Microsoft Windows where each drive gets its own root directory and you can navigate from one drive to another.

Most Unix-based systems like Linux are following the Filesystem Hierarchy Standard (FHS) which is a set of guidelines for creating a filesystem. While the FHS is a set of guidelines, it is not a set of rules. The rules are implemented by the system and the guidelines are not and most Linux distributions give their own interpretations to the FHS, but most end-users won’t notice it. The table below gives an overview of where the files and directories are located on the filesystem on the highest level possible.

Directory

File

/

Primary hierarchy root and root directory of the entire file system hierarchy.

/bin

Essential command binaries that need to be available in single-user mode, including to bring up the system or repair it, for all users.

/boot

Boot loader.

/dev

Device files.

/etc

Host-specific system-wide configuration files.

/home

Users’ home directories, containing saved files, personal settings, etc.

/lib

Libraries essential for the binaries in /bin and /sbin.

/media

Mount points for removable media such as CD-ROMs.

/mnt

Temporarily mounted filesystems.

/opt

Add-on application software packages.

/proc

Virtual filesystem providing process and kernel information as files.

/root

Home directory for the root user.

/run

Run-time variable data.

/sbin

Essential system binaries.

/srv

Site-specific data served by this system.

/sys

Contains information about devices, drivers, and some kernel features.

/tmp

Directory for temporary files.

/usr

Secondary hierarchy for read-only user data; contains the majority of (multi-)user utilities and applications.

/var

Variable files.

Creating and removing files and directories#

Navigating the filesystem is the first step to working with files and directories. The second step is to create a file or directory with the command `touch` or `mkdir`. In the example below we are creating a file called `test.txt` in the directory for temporary files, view the contents of the file and delete it with `rm` command.

$ touch /tmp/test.txt
$ ls -l /tmp
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/test.txt
$ cat /tmp/test.txt
$ rm /tmp/test.txt

Creating and removing directories can be done with the command `mkdir` or `rmdir`. In the example below we are creating a directory called `testdir` in the directory for temporary files and removing it again.

$ mkdir /tmp/testdir
$ ls -l /tmp
drwxr-xr-x 2 user01 user01 0 Jan  1  1970 /tmp/testdir
$ rmdir /tmp/testdir
$ ls -l /tmp/testdir
ls: cannot access '/tmp/testdir': No such file or directory

Creating and removing subdirectories can be done with the command `mkdir -p` if the parent directory doesn’t exist yet or `rmdir -p` if the directory only contains empty subdirectories. In the example below we are creating a directory called `testdir/subdir` in the directory for temporary files and removing it again.

$ mkdir -p /tmp/testdir/subdir
$ ls -l /tmp/testdir
drwxr-xr-x 2 user01 user01 0 Jan  1  1970 /tmp/testdir/subdir
$ rmdir -p /tmp/testdir
$ ls -l /tmp/testdir
ls: cannot access '/tmp/testdir': No such file or directory

Use command `rm -rf` to remove a directory recursively. In the example below we are creating a directory called `testdir` in the directory for temporary files and removing it recursively.

$ mkdir -p /tmp/testdir/subdir
$ touch /tmp/testdir/test.txt
$ ls -l /tmp/testdir
drwxr-xr-x 2 user01 user01 0 Jan  1  1970 /tmp/testdir/subdir
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt
$ rm -rf /tmp/testdir
$ ls -l /tmp/testdir
ls: cannot access '/tmp/testdir': No such file or directory

Moving files and directories#

Moving a file or directory to another location is done with the command `mv`. In the example below we are moving the file `test.txt` to the directory for temporary files.

$ mkdir /tmp/testdir
$ touch /tmp/testdir/test.txt
$ ls -l /tmp/testdir
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt
$ mv /tmp/testdir/test.txt /tmp/testdir/test.txt.bak
$ ls -l /tmp/testdir
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt.bak
$ mkdir /tmp/testdir
$ touch /tmp/testdir/test.txt
$ ls -l /tmp/testdir
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt
$ cp /tmp/testdir/test.txt /tmp/testdir/test.txt.bak
$ ls -l /tmp/testdir
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt.bak
$ mkdir /tmp/testdir
$ touch /tmp/testdir/test.txt
$ ls -l /tmp/testdir
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir/test.txt
$ mv /tmp/testdir /tmp/testdir2
$ ls -l /tmp/testdir2
-rw-rw-r-- 1 user01 user01 0 Jan  1  1970 /tmp/testdir2/test.txt

File and directory ownership#

$ chown user02 /tmp/test.txt
# chown user02 /tmp/test.txt
$ chgrp group01 /tmp/test.txt
# chgrp root /tmp/test.txt
# chown root:root /tmp/test.txt

Using file and directory permissons#

Posix permissions

$ ls -l /etc/ssh/sshd_config
-rw-r--r--. 1 root root  631 Jan  5  2009 /etc/ssh/sshd_config
$ chmod 600 /etc/ssh/sshd_config
$ touch /tmp/test.txt
$ chmod u+x /tmp/test.txt
$ chmod +x /tmp/test.txt
$ chmod a=rw /tmp/test.txt
$ chmod o-w /tmp/test.txt
  • 4 - add read permission

  • 2 - add write permission

  • 1 - add execute permission

$ chmod 750 /tmp/test.txt
$ chmod 4750 /tmp/test.txt
$ chmod u+s /tmp/test.txt
$ chmod g+s /tmp/test.txt
$ chmod +t /tmp/test.txt

Default mask for files: -rw-rw-r--

Default mask for directory: drwxrwxr-x

  • 4 - remove read permission

  • 2 - remove write permission

  • 1 - remove execute permission

$ umask
0022
$ umask 0027
$ umask
0027

Using an Access Control List#

$ getfacls /etc/ssh/sshd_config
/etc/ssh/sshd_config:
user::rw-
group::r--
other::---
user:root:rw-
group:root:r--
other:root:---
$ setfacl -m u:johndoe:rwx /etc/ssh/sshd_config

Scripting with BASH#

Most Linux distributions come with the bash shell. It is a very simple shell, but it is also a very powerful one. It is an updated version of the Bourne shell, which is the most common shell on UNIX systems. As a result, it is the most commonly used shell on UNIX systems and knowning how to script in the bash shell is a prerequisite to use Linux as a power user on any system.

Variables in shells are strings that are assigned to a name. The name is followed by an equals sign, and then the value of the variable. The value can be a string, a number, or a special value.

Assigning a value to a variable#
1#!/bin/bash
2
3i=0
4echo $i

Command substitution#

Assinging a value to a variable can also be done by command substitution where the output of a command is assigned to a variable.

Command substitution#
1#!/bin/bash
2
3i=`date +%s`
4echo $i

Exit-codes#

`$?`

Conditional structures#

If-then-else#

Conditional structures are used to evaluate a condition and execute a command if the condition is true. Based on this a command is executed if the condition is true or another if the condition is false.

If-then-else#
1#!/bin/bash
2
3i=1
4if [ $i -eq 1 ]
5then
6    echo "i equals 1"
7else
8    echo "i does not equal 1"
9fi

The if-then-else construct can also be extended to include an else-if statement.

If-then-else#
 1#!/bin/bash
 2
 3i=1
 4j=2
 5if [ $i -eq 1 ]
 6then
 7    echo "i equals 1"
 8elif [ $j -eq 2 ]
 9then
10    echo "j equals 2"
11else
12    echo "i and j do not equal 1 or 2"
13fi

Short-circuit evaluation#

The shell also allows to write short form conditional statements. This is can be used by using /usr/bin/[ or [ as the first character of the condition. It is an alternative to the test command and with the && and || operators the action can be defined.

If-then-else#
1#!/bin/bash
2
3i=1
4[ $i -eq 1 ] && echo "i equals 1"

Case statement#

Beside the if-then-else construct, the shell also allows to define a case statement. This is used to evaluate a value and execute a command based on the value. This makes the script more flexible and can be used to evaluate multiple values.

Case statement#
 1#!/bin/bash
 2
 3i=1
 4
 5case $i in
 6    1) echo "One";;
 7    2) echo "Two";;
 8    3) echo "Three";;
 9    *) echo "Unknown";;
10esac

Loops#

For loops#

Iterating over a list of values is done by using a for loop. The for loop is used to iterate over a list of values. The for loop is defined by the keyword for, followed by the name of the variable, followed by the keyword in, followed by the list of values. The list of values is separated by a space.

For loop#
1#!/bin/bash
2
3for i in {1..10}
4do
5    echo $i
6done

While loops#

Counter based loops are used to iterate over a list of values. The while loop is defined by the keyword while, followed by the condition, followed by the keyword do, followed by the commands, followed by the keyword done.

While loop#
1#!/bin/bash
2
3while :
4do
5    echo "Hello World!"
6    sleep 1
7done
While loop#
1#!/bin/bash
2
3while :; do
4    echo "Hello World!"
5    sleep 1
6done

User management#

Users#

# useradd -c "John Doe" -m john
# usermod -a -G wheel john
# passwd john
# id john
# userdel -r john

Groups#

# groupadd -g 1001 mygroup
# groupdel mygroup
# gpasswd -r mygroup
# newgrp - mygroup
# gpasswd -r mygroup

Password policies#

# chage -d 0 -I -1 -m 0 -M 99999 -W -1 john

Verification#

# grpck -r
# pwck -r
user 'pulse': directory '/var/run/pulse' does not exist
user 'rpc': directory '/var/lib/rpcbind' does not exist
user 'sshd': directory '/var/empty/sshd' does not exist
user 'firebird': program '/bin/nologin' does not exist
pwck: no changes

Package management#

Every Linux distribution is a collection of software packages that can be installed, updated, and removed during the lifetime of the system. These packages are managed by the package manager, which is usually called apt or dnf or zypper depending on the distribution. For now we focus on Red Hat-based distributions and the dnf package manager.

Note

DNF is a drop-in replacement for YUM on Red Hat-based distributions. It has been introduced in Fedora 22 and Red Hat Enterprise Linux 7, and will replace YUM in future releases.

Getting started with DNF#

All actions require the root user as the system needs to be changed.

Install the package python-pip with dnf#
# dnf install python-pip
Install the package python-pip with dnf without accepting the change#
# dnf install -y python-pip
Install the package python-pip with dnf#
# dnf remove python-pip
# dnf install <packagename>
# dnf update <packagename>
# dnf list [packagename]
# dnf search <keyword>
# dnf search all <keyword>
# dnf info <packagename>
# dnf provides <filename>
# dnf remove <packagename>
# dnf grouplist
Last metadata expiration check: 2:12:35 ago on Sat Jun  4 15:19:19 2022.
Available Environment Groups:
    Fedora Custom Operating System
    Minimal Install
    Fedora Server Edition
    Fedora Workstation
    Fedora Cloud Server
    KDE Plasma Workspaces
    Xfce Desktop
    LXDE Desktop
    LXQt Desktop
    Cinnamon Desktop
    MATE Desktop
    Sugar Desktop Environment
    Deepin Desktop
    Development and Creative Workstation
    Web Server
    Infrastructure Server
    Basic Desktop
    i3 desktop
Installed Groups:
    LibreOffice
    GNOME Desktop Environment
    Fonts
    Hardware Support
Available Groups:
    3D Printing
    Administration Tools
    Audio Production
    Authoring and Publishing
    C Development Tools and Libraries
    Cloud Infrastructure
    Cloud Management Tools
    Compiz
    Container Management
    D Development Tools and Libraries
    Design Suite
    Development Tools
    Domain Membership
    Editors
    Educational Software
    Electronic Lab
    Engineering and Scientific
    FreeIPA Server
    Headless Management
    MATE Applications
    Milkymist
    Network Servers
    Neuron Modelling Simulators
    Office/Productivity
    Pantheon Desktop
    Python Classroom
    Python Science
    Robotics
    RPM Development Tools
    Security Lab
    Text-based Internet
    Window Managers
    Deepin Desktop Environment
    Graphical Internet
    KDE (K Desktop Environment)
    Games and Entertainment
    Sound and Video
    System Tools
# dnf grouplist hidden
$ dnf group info "groupname"
$ dnf group install "Groupname"

Package installation history#

dnf logging can be found in /var/log/dnf.log

$ dnf history
$ dnf history info <id>
$ dnf history undo <id>

Maintaining repositories#

List all available repositories on the system#
# dnf repolist
repo id                                                                     repo name
azure-cli                                                                   Azure CLI
code                                                                        Visual Studio Code
fedora                                                                      Fedora 36 - x86_64
fedora-cisco-openh264                                                       Fedora 36 openh264 (From Cisco) - x86_64
fedora-modular                                                              Fedora Modular 36 - x86_64
gh-cli                                                                      packages for the GitHub CLI
google-chrome-unstable                                                      google-chrome-unstable
google-cloud-sdk                                                            Google Cloud SDK
hashicorp                                                                   Hashicorp Stable - x86_64
rpmfusion-free                                                              RPM Fusion for Fedora 36 - Free
rpmfusion-free-updates                                                      RPM Fusion for Fedora 36 - Free - Updates
rpmfusion-nonfree                                                           RPM Fusion for Fedora 36 - Nonfree
rpmfusion-nonfree-nvidia-driver                                             RPM Fusion for Fedora 36 - Nonfree - NVIDIA Driver
rpmfusion-nonfree-steam                                                     RPM Fusion for Fedora 36 - Nonfree - Steam
rpmfusion-nonfree-updates                                                   RPM Fusion for Fedora 36 - Nonfree - Updates
sbt-rpm                                                                     sbt-rpm
updates                                                                     Fedora 36 - x86_64 - Updates
updates-modular                                                             Fedora Modular 36 - x86_64 - Updates

Refreshing metadata#

dnf [options] makecache

The systemd time dnf-makecache.timer refreshes the metadata on a regular interval

Add in the [main]-section of /etc/dnf/dnf.conf the following:

metadata_timer_sync=0
metadata_expire=-1

Note

See also Building a package

Storage management#

Partitions#

manipulate disk partition table#

# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table
Building a new DOS disklabel with disk identifier 0x941ca04d.

Command (m for help):
Command (m for help): n
Partition type:
p   primary (0 primary, 0 extended, 4 free)
e   extended
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-33554431, default 2048):
Using default value 2048
Last sector, +sectors or +size{K,M,G} (2048-33554431, default 33554431): +512M
Partition 1 of type Linux and of size 512 MiB is set

Command (m for help): t
Selected partition 1
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
   Device Boot Start   End    MiB    #blocks   Id  System
/dev/sdb1         1    512    512     524288   8e  Linux LVM
/dev/sdb2         0      -      0          0    0  Empty
/dev/sdb3         0      -      0          0    0  Empty
/dev/sdb4         0      -      0          0    0  Empty
# mkfs.xfs /dev/sdb1
meta-data=/dev/sdb1              isize=256    agcount=4, agsize=32768 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0
data     =                       bsize=4096   blocks=131072, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=853, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
# mount /dev/sdb1 /mnt
# blkid /dev/sdb1
/dev/sdb1: UUID="0c1dd574-92ef-4dd4-92f4-d5f966a24359" TYPE="xfs"
# echo 'UUID="0c1dd574-92ef-4dd4-92f4-d5f966a24359" /mnt xfs defaults 0 1' >> /etc/fstab
# mount | grep mnt
/dev/sdb1 on /mnt type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
# df -h
Filesystem                       Size  Used Avail Use% Mounted on
/dev/mapper/server01-root         28G  6.9G   21G  26% /
devtmpfs                         491M     0  491M   0% /dev
tmpfs                            498M   12K  498M   1% /dev/shm
tmpfs                            498M   51M  447M  11% /run
tmpfs                            498M     0  498M   0% /sys/fs/cgroup
/dev/sda1                        497M   96M  401M  20% /boot
/dev/sdb1                        509M   26M  483M   6% /mnt

GUID partition#

# gdisk /dev/sdb
GPT fdisk (gdisk) version 0.8.6

Partition table scan:
  MBR: MBR only
  BSD: not present
  APM: not present
  GPT: not present


***************************************************************
Found invalid GPT and valid MBR; converting MBR to GPT format.
THIS OPERATION IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if
you don't want to convert your MBR partitions to GPT format!
***************************************************************
# gdisk /dev/sdc
GPT fdisk (gdisk) version 0.8.6

Partition table scan:
  MBR: not present
  BSD: not present
  APM: not present
  GPT: not present

Creating new GPT entries.

Command (? for help): n
Partition number (1-128, default 1):
First sector (34-33554398, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-33554398, default = 33554398) or {+-}size{KMGTP}: +5G
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): L
0700 Microsoft basic data  0c01 Microsoft reserved    2700 Windows RE
4200 Windows LDM data      4201 Windows LDM metadata  7501 IBM GPFS
7f00 ChromeOS kernel       7f01 ChromeOS root         7f02 ChromeOS reserved
8200 Linux swap            8300 Linux filesystem      8301 Linux reserved
8e00 Linux LVM             a500 FreeBSD disklabel     a501 FreeBSD boot
a502 FreeBSD swap          a503 FreeBSD UFS           a504 FreeBSD ZFS
a505 FreeBSD Vinum/RAID    a580 Midnight BSD data     a581 Midnight BSD boot
a582 Midnight BSD swap     a583 Midnight BSD UFS      a584 Midnight BSD ZFS
a585 Midnight BSD Vinum    a800 Apple UFS             a901 NetBSD swap
a902 NetBSD FFS            a903 NetBSD LFS            a904 NetBSD concatenated
a905 NetBSD encrypted      a906 NetBSD RAID           ab00 Apple boot
af00 Apple HFS/HFS+        af01 Apple RAID            af02 Apple RAID offline
af03 Apple label           af04 AppleTV recovery      af05 Apple Core Storage
be00 Solaris boot          bf00 Solaris root          bf01 Solaris /usr & Mac Z
bf02 Solaris swap          bf03 Solaris backup        bf04 Solaris /var
bf05 Solaris /home         bf06 Solaris alternate se  bf07 Solaris Reserved 1
bf08 Solaris Reserved 2    bf09 Solaris Reserved 3    bf0a Solaris Reserved 4
bf0b Solaris Reserved 5    c001 HP-UX data            c002 HP-UX service
ed00 Sony system partitio  ef00 EFI System            ef01 MBR partition scheme
ef02 BIOS boot partition   fb00 VMWare VMFS           fb01 VMWare reserved
fc00 VMWare kcore crash p  fd00 Linux RAID
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): p
Disk /dev/sdc: 33554432 sectors, 16.0 GiB
Logical sector size: 512 bytes
Disk identifier (GUID): 43EEEEDD-A229-4405-BF8B-8611C034B76D
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 33554398
Partitions will be aligned on 2048-sector boundaries
Total free space is 23068605 sectors (11.0 GiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048        10487807   5.0 GiB     8300  Linux filesystem

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sdc.
The operation has completed successfully.

Swap#

# fdisk /dev/sdb
Welcome to fdisk (util-linux 2.23.2).

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): p

Disk /dev/sdb: 17.2 GB, 17179869184 bytes, 33554432 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0xac34a203

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048     1050623      524288   8e  Linux LVM

Command (m for help): n
Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): p
Partition number (2-4, default 2):
First sector (1050624-33554431, default 1050624):
Using default value 1050624
Last sector, +sectors or +size{K,M,G} (1050624-33554431, default 33554431): +2G
Partition 2 of type Linux and of size 2 GiB is set

Command (m for help): t
Partition number (1,2, default 2): 2
Hex code (type L to list all codes): L

 0  Empty           24  NEC DOS         81  Minix / old Lin bf  Solaris
 1  FAT12           27  Hidden NTFS Win 82  Linux swap / So c1  DRDOS/sec (FAT-
 2  XENIX root      39  Plan 9          83  Linux           c4  DRDOS/sec (FAT-
 3  XENIX usr       3c  PartitionMagic  84  OS/2 hidden C:  c6  DRDOS/sec (FAT-
 4  FAT16 <32M      40  Venix 80286     85  Linux extended  c7  Syrinx
 5  Extended        41  PPC PReP Boot   86  NTFS volume set da  Non-FS data
 6  FAT16           42  SFS             87  NTFS volume set db  CP/M / CTOS / .
 7  HPFS/NTFS/exFAT 4d  QNX4.x          88  Linux plaintext de  Dell Utility
 8  AIX             4e  QNX4.x 2nd part 8e  Linux LVM       df  BootIt
 9  AIX bootable    4f  QNX4.x 3rd part 93  Amoeba          e1  DOS access
 a  OS/2 Boot Manag 50  OnTrack DM      94  Amoeba BBT      e3  DOS R/O
 b  W95 FAT32       51  OnTrack DM6 Aux 9f  BSD/OS          e4  SpeedStor
 c  W95 FAT32 (LBA) 52  CP/M            a0  IBM Thinkpad hi eb  BeOS fs
 e  W95 FAT16 (LBA) 53  OnTrack DM6 Aux a5  FreeBSD         ee  GPT
 f  W95 Ext'd (LBA) 54  OnTrackDM6      a6  OpenBSD         ef  EFI (FAT-12/16/
10  OPUS            55  EZ-Drive        a7  NeXTSTEP        f0  Linux/PA-RISC b
11  Hidden FAT12    56  Golden Bow      a8  Darwin UFS      f1  SpeedStor
12  Compaq diagnost 5c  Priam Edisk     a9  NetBSD          f4  SpeedStor
14  Hidden FAT16 <3 61  SpeedStor       ab  Darwin boot     f2  DOS secondary
16  Hidden FAT16    63  GNU HURD or Sys af  HFS / HFS+      fb  VMware VMFS
17  Hidden HPFS/NTF 64  Novell Netware  b7  BSDI fs         fc  VMware VMKCORE
18  AST SmartSleep  65  Novell Netware  b8  BSDI swap       fd  Linux raid auto
1b  Hidden W95 FAT3 70  DiskSecure Mult bb  Boot Wizard hid fe  LANstep
1c  Hidden W95 FAT3 75  PC/IX           be  Solaris boot    ff  BBT
1e  Hidden W95 FAT1 80  Old Minix
Hex code (type L to list all codes): 82
Changed type of partition 'Linux' to 'Linux swap / Solaris'

Command (m for help): p

Disk /dev/sdb: 17.2 GB, 17179869184 bytes, 33554432 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0xac34a203

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048     1050623      524288   8e  Linux LVM
/dev/sdb2         1050624     5244927     2097152   82  Linux swap / Solaris

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.
# partprobe
# mkswap /dev/sdb2
Setting up swapspace version 1, size = 2097148 KiB
no label, UUID=dd31fd56-11ac-4580-9c39-c748535b9af7
# free -m
             total       used       free     shared    buffers     cached
Mem:           994        803        190         50          2        346
-/+ buffers/cache:        455        539
Swap:         2079          1       2078
# swapon /dev/sdb2
# free -m
             total       used       free     shared    buffers     cached
Mem:           994        302        691          7          1        111
-/+ buffers/cache:        190        804
Swap:         4127          0       4127
# blkid /dev/sdb2
/dev/sdb2: UUID="dd31fd56-11ac-4580-9c39-c748535b9af7" TYPE="swap"
# swapon -s (summary)
Filename Type Size Used Priority
/dev/dm-0 partition 2129916 0 -1

Logical Volume Management#

As seen in the previous chapter the size of filesystems are limited to the size of a single harddisk. By using Logical Volume Management we can work around this limitation as it an abstraction layer between one or more harddisks and filesystems.

The Basics#

On our example system we can see that we already has been deployed with a volume group called systemvg on partition /dev/sda2, but both /dev/sdb and /dev/sdc are still unused when we check with lsblk.

# lsblk
NAME              MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda                 8:0    0   20G  0 disk
├─sda1              8:1    0    1G  0 part /boot
└─sda2              8:2    0   11G  0 part
  ├─systemvg-root 253:0    0    4G  0 lvm  /
  ├─systemvg-var  253:1    0    4G  0 lvm  /var
  ├─systemvg-home 253:2    0 1024M  0 lvm  /home
  └─systemvg-swap 253:3    0    2G  0 lvm  [SWAP]
sdb                 8:16   0    8G  0 disk
sdc                 8:32   0    8G  0 disk
sr0                11:0    1 1024M  0 rom

A harddisk or partition can be prepared with the pvcreate command and verified with the command pvdisplay. In the example below harddisk /dev/sdb is prepared and verify the new physical volume. The pvdisplay command shows the maximum size that can be allocated and how much space has been allocated.

# pvcreate /dev/sdb
Physical volume "/dev/sdb" successfully created.

# pvdisplay /dev/sdb
  "/dev/sdb" is a new physical volume of "8.00 GiB"
    --- NEW Physical volume ---
    PV Name               /dev/sdb
    VG Name
    PV Size               8.00 GiB
    Allocatable           NO
    PE Size               0
    Total PE              0
    Free PE               0
    Allocated PE          0
    PV UUID               QFLoSk-uwBO-xSrP-nyLI-21wj-dCJ1-0pdLFy

One or more physical volumes can be combined into volume group with the command vgcreate. After creating a new volume group called datavg that contains the physical volume on /dev/sdb the specifications can be dispayed with command vgdisplay. Running vgdisplay and pvdisplay will the allocated space both within the volume group and physical volume.

# vgcreate datavg /dev/sdb
  Volume group "datavg" successfully created

# vgdisplay datavg
  --- Volume group ---
  VG Name               datavg
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               <8.00 GiB
  PE Size               4.00 MiB
  Total PE              2047
  Alloc PE / Size       0 / 0
  Free  PE / Size       2047 / <8.00 GiB
  VG UUID               pfKpWs-Qb3Z-rQMw-1EqO-TYRw-ZhkF-FhiSwM

# pvdisplay /dev/sdb
  --- Physical volume ---
  PV Name               /dev/sdb
  VG Name               datavg
  PV Size               8.00 GiB / not usable 4.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              2047
  Free PE               2047
  Allocated PE          0
  PV UUID               QFLoSk-uwBO-xSrP-nyLI-21wj-dCJ1-0pdLFy

Creating a logical volume called fs01 with the lvcreate command and allocating space for it in volume group ** datavg**. Running the command vgdisplay and pvdisplay will show that the allocated and remaining space.

# lvcreate -L 100M datavg -n fs01

# vgdisplay datavg
  --- Volume group ---
  VG Name               datavg
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  2
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               <8.00 GiB
  PE Size               4.00 MiB
  Total PE              2047
  Alloc PE / Size       25 / 100.00 MiB
  Free  PE / Size       2022 / <7.90 GiB
  VG UUID               pfKpWs-Qb3Z-rQMw-1EqO-TYRw-ZhkF-FhiSwM

# pvdisplay /dev/sdb
  --- Physical volume ---
  PV Name               /dev/sdb
  VG Name               datavg
  PV Size               8.00 GiB / not usable 4.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              2047
  Free PE               2022
  Allocated PE          25
  PV UUID               QFLoSk-uwBO-xSrP-nyLI-21wj-dCJ1-0pdLFy

The device mapper in Linux now provides a block device that can be accessed like a partition to create a filesystem and mount it.

# ls -lL /dev/mapper/
total 0
crw-------. 1 root root  10, 236 Dec 16 21:24 control
brw-rw----. 1 root disk 253,   2 Dec 16 21:43 datavg-fs01
brw-rw----. 1 root disk 253,   0 Dec 16 21:24 systemvg-root
brw-rw----. 1 root disk 253,   1 Dec 16 21:24 systemvg-swap

# mkfs.xfs /dev/mapper/datavg-fs01
meta-data=/dev/mapper/datavg-fs01 isize=512    agcount=4, agsize=6400 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1    bigtime=0 inobtcount=0
data     =                       bsize=4096   blocks=25600, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=1368, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
Discarding blocks...Done.

# mount /dev/mapper/datavg-fs01 /mnt

# df -h /mnt
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/datavg-fs01   95M  6.0M   89M   7% /mnt

After unmounten the filesystem the logical volume can de removed from the volume group with the lvremove command. The vgdisplay command also shows that the allocated space has been freed and is available to be used for another logical volume.

# umount /mnt

# lvremove /dev/mapper/datavg-fs01
Do you really want to remove active logical volume datavg/fs01? [y/n]: y
  Logical volume "fs01" successfully removed.

# vgdisplay datavg
  --- Volume group ---
  VG Name               datavg
  System ID
  Format                lvm2
  Metadata Areas        1
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                1
  Act PV                1
  VG Size               <8.00 GiB
  PE Size               4.00 MiB
  Total PE              2047
  Alloc PE / Size       0 / 0
  Free  PE / Size       2047 / <8.00 GiB
  VG UUID               pfKpWs-Qb3Z-rQMw-1EqO-TYRw-ZhkF-FhiSwM

When volume group datavg is also removed with the vgremove command and /dev/sdb isn’t part of a volume group anymore as the line with VG Name is empty. After this the LVM-label on disk can be remove with pvremove and the physical volume is completely gone.

# vgremove datavg
  Volume group "datavg" successfully removed

# pvdisplay /dev/sdb
"/dev/sdb" is a new physical volume of "8.00 GiB"
--- NEW Physical volume ---
PV Name               /dev/sdb
VG Name
PV Size               8.00 GiB
Allocatable           NO
PE Size               0
Total PE              0
Free PE               0
Allocated PE          0
PV UUID               QFLoSk-uwBO-xSrP-nyLI-21wj-dCJ1-0pdLFy

# pvremove /dev/sdc1

Extending#

# vgextend vg_name /dev/sdc2
# pvmove /dev/sdc1 /dev/sdc2
# vgreduce vg_name /dev/sdc2
# lvextend -L +512M /dev/vg_name/lv_name
# lvextend -L +128 /dev/vg_name/lv_name
# lvextend -l+100%FREE /dev/vg_name/lv_name
# xfs_growfs /dev/vg_name/lv_name
# resize2fs /dev/vg_name/lv_name

Scheduling Tasks#

Linux systems come with a number of tools for scheduling tasks on a system. The traditional way to do this is to use the cron daemon for persistant scheduled jobs or the at command for non-persistant jobs. The new alternative is to use systemd timers as it is more flexible and more reliable.

Scheduled commands with cron#

Cron is a system for scheduling tasks to be run periodically with a precission of one minute. Multiple implementations are available, but most Linux distributions use the anacron implementation. The name is derived from the name of the greek god Cronos, the god of time.

Using cron itself is simple, but defining the tasks is a bit more involved as you need to figure out the correct scheduling syntax. Let start with option -l to list all available tasks that are defined for the current user.

Listing cron jobs for current user#
$ crontab -l
no crontab for user01

With the option -e you can edit the cron file as cron makes a copy of the crontab file and lets you edit it via the editor specified in the EDITOR environment variable or specified as the system default as a fallback.

Editing the crontab file for the current user#
$ crontab -e

Warning

The option -r will remove all tasks from the crontab file without prompting for confirmation. Some users confuse this with the -e option which will edit the crontab file or to view the crontab file in read-only mode.

Removing all tasks from the crontab file can be done with the option -r.

Remove all cron jobs for current user#
$ crontab -r

All actions are performed on the crontab file for the current user, but with the following option -u <user> you can also perform them on the crontab file for another user.

List cron jobs for specific user#
# crontab -u user01 -l

Beside the crontab files per user in /var/spool/cron there is also a cron file for the system cron daemon in /etc/crontab and a cron file for the root user in /etc/cron.d. Taking a closer look at /etc/crontab you can see that the system cron daemon is using the cron file for the root user and can run commands under a different user.

$ cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

Crontab settings per user are located in /var/spool/cron and are similar to the crontab file for the system cron daemon, but without the option to switch to a different user. For all these values you can combine them as single value, a list of values or a range of values, but also divide them to get a matching schedule. Some examples are listed in the table below.

Job definition

Description

1 2 3 4 5

Every Friday (5) the is on April (4) 3th at 2:01am

30 4 * * *

Every day at 4:30am

30 4-6 * * *

Every day at 4:30am, 5:30am and 6:30am

30 4-8/2 * * *

Every day at 4:30am, 6:30am, 8:30am

30 4,6,8 * * *

Every day at 4:30am, 6:30am and 8:30am

0 15,20 * */2 1-5

Every workday during an even month at 15:00 and 20:00

*/10 8-16,22 * * *

Every 10 minutes between 8am and 5pm and between 10pm and 11pm

Scheduled commands with at#

at [-V] [-q queue] [-f file] [-mMlv] timespec...
at [-V] [-q queue] [-f file] [-mMkv] [-t time]
at -c job [job...]
atq [-V] [-q queue]
at [-rd] job [job...]
atrm [-V] job [job...]
batch
at -b

Systemd timers#

Systemd Timers

List all active timers#
# systemctl list-timers
NEXT                        LEFT          LAST                        PASSED       UNIT                         ACTIVATES
Wed 2021-11-17 02:00:00 CET 15s left      Wed 2021-11-17 01:50:34 CET 9min ago     sysstat-collect.timer        sysstat-collect.service
Wed 2021-11-17 03:19:18 CET 1h 19min left Wed 2021-11-17 01:22:46 CET 36min ago    dnf-makecache.timer          dnf-makecache.service
Wed 2021-11-17 21:30:46 CET 19h left      Tue 2021-11-16 11:17:42 CET 14h ago      systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Thu 2021-11-18 00:00:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago logrotate.timer              logrotate.service
Thu 2021-11-18 00:00:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago mlocate-updatedb.timer       mlocate-updatedb.service
Thu 2021-11-18 00:00:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago unbound-anchor.timer         unbound-anchor.service
Thu 2021-11-18 00:07:00 CET 22h left      Wed 2021-11-17 00:45:27 CET 1h 14min ago sysstat-summary.timer        sysstat-summary.service
Mon 2021-11-22 01:07:18 CET 4 days left   Mon 2021-11-15 01:00:34 CET 2 days ago   fstrim.timer                 fstrim.service
n/a                         n/a           Mon 2021-11-15 00:00:35 CET 2 days ago   rdiff-backup.timer           rdiff-backup.target

9 timers listed.
Pass --all to see loaded but inactive timers, too
Stop timer#
$ systemctl --user stop schedule-test.timer
$ systemctl --user disable schedule-test.timer
$ systemctl --user stop schedule-test.service
$ systemctl --user disable schedule-test.service
$ systemctl --user daemon-reload
$ systemctl --user reset-failed
[Unit]
Description=Schedule a message every 1 minute
RefuseManualStart=no  # Allow manual starts
RefuseManualStop=no   # Allow manual stops

[Timer]
#Execute job if it missed a run due to machine being off
Persistent=true
#Run 120 seconds after boot for the first time
OnBootSec=120
#Run every 1 minute thereafter
OnUnitActiveSec=60
#File describing job to execute
Unit=schedule-test.service

[Install]
WantedBy=timers.target

Transient timer units#

Like

create a transient timer unit to run a command#
# systemd-run --on-active=30 /bin/touch /tmp/foo

Execute

create a transient timer unit to run a command#
# systemd-run --on-active="1h 5m" --unit app.service

Network Management#

Network information#

$ ip a s ens192
2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:50:56:0b:fa:af brd ff:ff:ff:ff:ff:ff
    inet 5.135.236.224/32 brd 5.135.236.224 scope global ens192
      valid_lft forever preferred_lft forever
ip -s(tatistics) link show ens192
ip r(oute)
ping -c3 google.com
traceroute google.com
tracepath google.com
ss -ta

Network Manager#

# nmcli c s
NAME           UUID                                  TYPE            DEVICE
System ens192  757d582e-22b3-4514-91df-63e29a49a388  802-3-ethernet  ens192
System ens224  0a0c153f-47a4-4d23-81f0-d588b1ec1418  802-3-ethernet  ens224
# nmcli c show "System ens192"
connection.id:                          System ens192
connection.uuid:                        757d582e-22b3-4514-91df-63e29a49a388
connection.interface-name:              ens192
connection.type:                        802-3-ethernet
connection.autoconnect:                 yes
connection.timestamp:                   1460972356
# nmcli d s
DEVICE  TYPE      STATE         CONNECTION
ens192  ethernet  connected     System ens192
ens224  ethernet  connected     System ens224
ens256  ethernet  disconnected  --
lo      loopback  unmanaged     --
# nmcli d show ens192
GENERAL.DEVICE:                         ens192
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         00:0C:29:3A:E6:77
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     System ens192
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/0
WIRED-PROPERTIES.CARRIER:               on
IP4.ADDRESS[1]:                         ip = 192.168.0.1/24, gw = 0.0.0.0
IP4.DNS[1]:                             213.186.33.99
IP4.DOMAIN[1]:                          example.org
IP6.ADDRESS[1]:                         ip = fe80::20c:29ff:fe3a:e677/64, gw = ::
nmcli c s
ip a show ens256
# hostname
server01.intranet
hostnamectl set-hostname server02.intranet
hostnamectl status
# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.0.100   server01.intranet server01
# cat /etc/resolv.conf
# Generated by NetworkManager
domain intranet
search intranet intranet.
nameserver 213.186.33.99
# nmcli con mod statictest ipv4.dns 10.10.10.254
# nmcli con down statictest
# nmcli con up statictest
# cat /etc/resolv.conf
# Generated by NetworkManager
domain example.org
search example.org example.org.
nameserver 213.186.33.99
nameserver 10.10.10.254

Logging#

Rsyslogd#

# echo "*.debug /var/log/messages-debug" > /etc/rsyslog.d/debug.conf
$ logger -p user.debug "Dit is een debug test"

Journald#

$ journalctl
$ journalctl -n 10
$ journalctl -p err
$ journalctl -f
$ journalctl --since yesterday
$ journalctl --since "2021-12-06 13:00:00" --until yesterday
$ journalctl -o verbose
$ journalctl _SYSTEMD_UNIT=sshd.service _PID=28203
-- Logs begin at Mon 2021-12-06 10:28:15 CEST, end at Mon 2021-12-06 12:32:05 CEST. --
Dec 06 10:25:32 server01.intranet sshd[28203]: Accepted password for user01 from 213.19.196.11 port 34590 ssh2

Persistant journal#

# mkdir -p /var/log/journal
# chown root:systemd-journal /var/log/journal
# chmod 2775 /var/log/journal
# killall -USR1 systemd-journald
# journalctl -b
# journalctl -b 1

Time management#

System time#

$ timedatectl
               Local time: vr 2021-11-19 00:16:38 CET
           Universal time: do 2021-11-18 23:16:38 UTC
                 RTC time: do 2021-11-18 23:16:38
                Time zone: Europe/Amsterdam (CET, +0100)
System clock synchronized: yes
              NTP service: active
          RTC in local TZ: no
$ timedatectl list-timezones | grep -i europe
Europe/Amsterdam
Europe/Andorra
Europe/Astrakhan
Europe/Athens
Europe/Belfast
Europe/Belgrade
Europe/Berlin
Europe/Bratislava
Europe/Brussels
# timedatectl set-timezone Europe/Amsterdam
# timedatectl set-time 19:30
# timedatectl set-ntp true

Network time#

# chronyc sources -v

Systemd and SysVinit#

Unix-based systems used SysV-style start-stop-scripts to control services and so did most Linux distributions. Systemd has become the default for most Linux distributions since 2011, and it is the default for most recent versions of Ubuntu. This chapter covers primarly systemd or how to convert to systemd as well as how to use systemd to manage services.

The original SysVinit was a replacement for initscripts and was used on most Linux distributions. Systemd was started by Lennart Poettering as a replacement for initd and SysVinit to manage services like on other operating systems as Microsoft Windows for example. With a dependency graph systemd can make your system more reliable and stable as you define the dependencies between services and the order in which they are started.

Available unit types#

Systemd defines every service as a unit. A unit is a collection of configuration files and a set of binaries that are used to start and stop the service. The unit name is the name of the service. The example below shows how to list all available units on your system as they depend on the systemd version on your system.

$ systemctl -t help
Available unit types:
service
mount
swap
socket
target
device
automount
timer
path
slice
scope

By knowing the unit types you can list all available units of that type as we can see below where the command systemctl --type=service lists all available services.

$ systemctl --type=service
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  abrt-journal-core.service   loaded active running Creates ABRT problems from …
  abrt-oops.service           loaded active running ABRT kernel log watcher
  abrt-xorg.service           loaded active running ABRT Xorg log watcher
  abrtd.service               loaded active running ABRT Automated Bug Reportin…
  accounts-daemon.service     loaded active running Accounts Service
  alsa-state.service          loaded active running Manage Sound Card State (re…
  atd.service                 loaded active running Deferred execution scheduler
  auditd.service              loaded active running Security Auditing Service
  avahi-daemon.service        loaded active running Avahi mDNS/DNS-SD Stack

Systemd also can act like a scheduler and run services on a specific time schedule, but also verifies if all requirements are satisfied before execution the schedule. In a later section we will see how to use systemd to manage timers.

$ systemctl --type=timer
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  dnf-makecache.timer         loaded active waiting dnf makecache --timer
  fstrim.timer                loaded active waiting Discard unused blocks once …
  logrotate.timer             loaded active waiting Daily rotation of log files
  mlocate-updatedb.timer      loaded active waiting Updates mlocate database ev…
  rdiff-backup.timer          loaded active running Execute rdiff-backup
  snapper-cleanup.timer       loaded active waiting Daily Cleanup of Snapper Sn…
  snapper-timeline.timer      loaded active waiting Timeline of Snapper Snapsho…
  sysstat-collect.timer       loaded active waiting Run system activity account…
  sysstat-summary.timer       loaded active waiting Generate summary of yesterd…
  systemd-tmpfiles-clean.tim… loaded active waiting Daily Cleanup of Temporary …
  unbound-anchor.timer        loaded active waiting daily update of the root tr…

Unit type mount is another example and can be created for mounting filesystems, but systemd itself generates during the boot procedure of the system all required unit files based on the content of /etc/fstab. This makes the transition smooth for a lot people working with Linux.

$ systemctl --type=mount
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  -.mount                     loaded active mounted Root Mount
  boot-efi.mount              loaded active mounted /boot/efi
  boot.mount                  loaded active mounted /boot
  dev-hugepages.mount         loaded active mounted Huge Pages File System
  dev-mqueue.mount            loaded active mounted POSIX Message Queue File Sy…
  home.mount                  loaded active mounted /home
  run-user-1000-doc.mount     loaded active mounted /run/user/1000/doc
  run-user-1000-gvfs.mount    loaded active mounted /run/user/1000/gvfs
  run-user-1000.mount         loaded active mounted /run/user/1000
  srv.mount                   loaded active mounted /srv
  sys-fs-fuse-connections.mo… loaded active mounted FUSE Control File System
  sys-kernel-config.mount     loaded active mounted Kernel Configuration File S…
  sys-kernel-debug.mount      loaded active mounted Kernel Debug File System
  sys-kernel-tracing.mount    loaded active mounted Kernel Trace File System
  tmp.mount                   loaded active mounted Temporary Directory /tmp
  var-lib-docker.mount        loaded active mounted /var/lib/docker
  var-lib-libvirt.mount       loaded active mounted /var/lib/libvirt
  var-lib-nfs-rpc_pipefs.mou… loaded active mounted RPC Pipe File System

Managing services#

One of the benefits of systemd is that it can monitor the state of services and make sure that they are running as expected. This is done by using the systemctl command. In the section Available unit types it was shown how to list all services on the system. The example below shows how to request the status of a service, but also if it is enabled or not to be started on boot.

$ systemctl status sshd.service
● sshd.service - OpenSSH server daemon
    Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: disabled)
    Active: active (running) since Sun 2022-04-17 09:36:55 CEST; 20s ago
      Docs: man:sshd(8)
            man:sshd_config(5)
  Main PID: 663271 (sshd)
      Tasks: 1 (limit: 18476)
    Memory: 2.1M
        CPU: 14ms
    CGroup: /system.slice/sshd.service
            └─663271 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

apr 17 09:36:55 server01 systemd[1]: Starting OpenSSH server daemon...
apr 17 09:36:55 server01 sshd[663271]: Server listening on 0.0.0.0 port 22.
apr 17 09:36:55 server01 sshd[663271]: Server listening on :: port 22.
apr 17 09:36:55 server01 systemd[1]: Started OpenSSH server daemon.

Note

By default systemd will assume the unit type service if no unit type is specified. In the case for the example above systemctl status sshd.service and systemctl status sshd are the same.

Enabling the sshd service with command systemctl enable <service name> will tell systemd to start the service when the system boots, but the service isn’t automatically started. To start the service we need to use the systemctl start sshd command.

$ systemctl enable sshd

Disabling the sshd service with command systemctl diable <service name> has the same behavior as systemctl enable <service name> and will only make sure the services isn’t started when the system boots.

$ systemctl disable sshd

Note

The --now option is used to start or stop the service immediately after enabling or disabling it. This option is available since Red Hat Enterprise Linux 7.2 and CentOS 7.2. Older versions require two commands to both enable and start a service.

Starting the sshd service with command systemctl start <service name> will start the service immediately. The service doesn’t have to be enabled for this and when the system system reboots the service will be stopped automatically, but not started if it isn’t enabled.

$ systemctl start sshd

The same rules as with starting a service also apply to stopping a service. This makes troubleshooting easier as it is easy to see if the service is running or not and should be running or not.

$ systemctl stop sshd

Like most SysVinit scripts systemd also has the option to restart a service by stopping and starting if for you. This is done by using the systemctl restart <service name> command.

$ systemctl restart sshd
$ systemctl reload sshd

With the command systemctl is-active <service name> we can check if the service is running or not as systemd will return active if the service is running and inactive if it isn’t. This make scripting and automation easier.

$ systemctl is-active sshd
active

The same rules apply to verify if a service is enabled or not as well with the command systemctl is-enabled <service name>.

$ systemctl is-enabled sshd
enabled

List active services#

$ systemctl list-units --type=service
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  abrt-journal-core.service   loaded active running Creates ABRT problems from …
  abrt-oops.service           loaded active running ABRT kernel log watcher
  abrt-xorg.service           loaded active running ABRT Xorg log watcher
  abrtd.service               loaded active running ABRT Automated Bug Reportin…
  accounts-daemon.service     loaded active running Accounts Service
  alsa-state.service          loaded active running Manage Sound Card State (re…
  atd.service                 loaded active running Deferred execution scheduler
  auditd.service              loaded active running Security Auditing Service
  avahi-daemon.service        loaded active running Avahi mDNS/DNS-SD Stack
$ systemctl list-units --type=service --all
  UNIT                        LOAD   ACTIVE SUB     DESCRIPTION
  abrt-journal-core.service loaded    active   running Creates ABRT problems fr…
  abrt-oops.service         loaded    active   running ABRT kernel log watcher
  abrt-vmcore.service       loaded    inactive dead    Harvest vmcores for ABRT
  abrt-xorg.service         loaded    active   running ABRT Xorg log watcher
  abrtd.service             loaded    active   running ABRT Automated Bug Repor…
  accounts-daemon.service   loaded    active   running Accounts Service
  alsa-restore.service      loaded    inactive dead    Save/Restore Sound Card …
  alsa-state.service        loaded    active   running Manage Sound Card State …
● apparmor.service          not-found inactive dead    apparmor.service
  atd.service               loaded    active   running Deferred execution sched…
  auditd.service            loaded    active   running Security Auditing Service
  auth-rpcgss-module.servi… loaded    inactive dead    Kernel Module supporting…
● auto-cpufreq.service      not-found inactive dead    auto-cpufreq.service
● autofs.service            not-found inactive dead    autofs.service
  avahi-daemon.service      loaded    active   running Avahi mDNS/DNS-SD Stack

List enabled services#

$ systemctl list-unit-files --type=service
  UNIT FILE                                          STATE           VENDOR PRESET
  abrt-journal-core.service                          enabled         enabled
  abrt-oops.service                                  enabled         enabled
  abrt-pstoreoops.service                            disabled        disabled
  abrt-vmcore.service                                enabled         enabled
  abrt-xorg.service                                  enabled         enabled
  abrtd.service                                      enabled         enabled
  accounts-daemon.service                            enabled         enabled
  alsa-restore.service                               static          -
  alsa-state.service                                 static          -
  anaconda-direct.service                            static          -
  anaconda-fips.service                              static          -
  anaconda-nm-config.service                         static          -
  anaconda-noshell.service                           static          -
  anaconda-pre.service                               static          -
  [email protected]                            static          -
  anaconda-sshd.service                              static          -
  [email protected]                             static          -
  anaconda.service                                   static          -
  arp-ethers.service                                 disabled        disabled
  atd.service                                        enabled         enabled
  auditd.service                                     enabled         enabled
  auth-rpcgss-module.service                         static          -
  [email protected]                                    alias           -
  avahi-daemon.service                               enabled         enabled
$ systemctl --failed --type=service
  UNIT                         LOAD   ACTIVE SUB    DESCRIPTION

Dependencies#

$ systemctl list-dependencies sshd.service
sshd.service
● ├─system.slice
○ ├─sshd-keygen.target
○ │ ├─[email protected]
○ │ ├─[email protected]
○ │ └─[email protected]
● └─sysinit.target
●   ├─dev-hugepages.mount
●   ├─dev-mqueue.mount
●   ├─dracut-shutdown.service
○   ├─fedora-import-state.service
○   ├─iscsi.service
●   ├─kmod-static-nodes.service
○   ├─ldconfig.service
○   ├─lvm2-lvmetad.socket
$ systemctl list-dependencies sshd.service --reverse
sshd.service

Masking services#

With systemd it is possible to define the state of a service by enabling or disabling it. It still allows the service to be started or enabled even. Another option exists and systemd allows a service to be masked. This means that the service is a symbolic link to /dev/null and stops systemd from starting it.

$ systemctl mask iptables
Created symlink from /etc/systemd/system/iptables.service to /dev/null.

Masked services can also be unmasked so they can be enabled and started again.

$ systemctl unmask iptables

Note

The main purpose of masking services is to prevent administrative errors when competing services like iptables and firewalld are installed on the same system.

Managing bootlevels#

$ systemctl list-dependencies graphical.target | grep target
graphical.target
● └─multi-user.target
●   ├─basic.target
●   │ ├─paths.target
●   │ ├─slices.target
●   │ ├─sockets.target
●   │ ├─sysinit.target
●   │ │ ├─cryptsetup.target
●   │ │ ├─local-fs.target
●   │ │ ├─swap.target
●   │ │ └─veritysetup.target
●   │ └─timers.target
●   ├─getty.target
●   ├─nfs-client.target
●   │ └─remote-fs-pre.target
●   └─remote-fs.target
●     └─nfs-client.target
●       └─remote-fs-pre.target
$ systemctl list-units --type=target --all
$ systemctl list-unit-files --type=target --all
$ systemctl isolate graphical.target
$ systemctl get-default
graphical.target
$ systemctl set-default multi-user.target

To be used with Grub:

systemd.unit=rescue.target (emergency.target)

Managing temporary files#

A generic mechanism for creating, adjusting, and deleting temporary files is provided by systemd-tmpfiles. It is mainly used in combinantion of volatile and temporary files and directories located under /run/, /tmp/, and /var/tmp/ for example. A standard set of rules is shipped with the systemd-tmpfiles package, but it can be customized to suit your needs by adding additional configuration files under /etc/tmpfiles.d/. A full list of locations with configuration files is shown in the table below.

Location

Description

/etc/tmpfiles.d/*.conf

Manual configuration

/run/tmpfiles.d/*.conf

Generated configuration

/usr/lib/tmpfiles.d/*.conf

System configuration

In unit file /usr/lib/systemd/system/systemd-tmpfiles-clean.service, shown below, it is defined which command is runned to clean up the temporary files. Secondly, it is defined when the unit file has to be executed and that is right after both dependencies local-fs and time-set are met, but also just before the system shutdown. If required the service can also be executed manually by running systemctl start systemd-tmpfiles-clean.service.

#  SPDX-License-Identifier: LGPL-2.1-or-later
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
DefaultDependencies=no
Conflicts=shutdown.target initrd-switch-root.service
After=local-fs.target time-set.target
Before=shutdown.target

[Service]
Type=oneshot
ExecStart=systemd-tmpfiles --clean
SuccessExitStatus=DATAERR
IOSchedulingClass=idle

The previous unit file describes the service, but is only executed during the boot and shutdown process. Running it regulary is done by the timer unit file /usr/lib/systemd/system/systemd-tmpfiles-clean.timer. This unit file is defined to run the service every day and at least 15 minutes after the system has been booted. This to not affect the system performance when the system is booted.

#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Daily Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
ConditionPathExists=!/etc/initrd-release

[Timer]
OnBootSec=15min
OnUnitActiveSec=1d

Creating a new configuration file /etc/tmpfiles.d/local.conf with the examples below and running command systemd-tmpfiles --create to create the directory defined in the configuration file. It also cleans up the defined folder after 10 days.

d       /var/local/appdump 2750 apprun appgrp 10d -

With option d the systemd-tmpfiles --clean triggers the removal of all files passed the 10 day mark, but command systemd-tmpfiles --remove doesn’t remove anything. If the configuration file is changed to start with D the files are still removed after the 10 days, but also all files are removed if the command systemd-tmpfiles --remove is run.

D       /var/local/appdump 2750 apprun appgrp 10d -

Another example is to create symbolic links and directories in /run/ with the example below.

L       /run/mtab  -    root   root   - /proc/self/mounts
D       /run/myapp 2750 apprun appgrp - -

More options do exist, but are not shown here and can be found with man tmpfiles.d.

Firewall Management#

Linux systems are often connected to the internet directly or indirectly via a firewall, but Linux itself also has a firewall built-in. This firewall is constantly being developed and upgraded, and it is not always easy to configure. For this firewalld was created to be an uniform way to manage the firewall as a whole.

Linux 2.0 came with ipfwadm and was replaced by ipchains in Linux 2.2. With Linux 2.4, ipchains was replaced by iptables. Since a couple of years development has started to replace iptables with nftables to provide a more flexible and powerful firewall ready for the next decade. With nftables, the firewall can be configured on the fly and should be able to work in environments with 10 Gbps or more network bandwidth.

A short introduction to firewalld#

Firewalld is the way to unify the iptables and nftables, and make the transition easier. Automation tools like Ansible understand the abstraction layer firewalld provides and playbooks should work as expected. Recent versions of Red Hat, CentOS and Fedora come by default with firewalld installed and enabled. Lets make sure firewalld is installed and running.

Install and enable firewalld#
# dnf install firewalld
# systemctl enable --now firewalld

As seen with systemd, also firewalld has been designed to be script friendly. Command firewall-cmd --state allows you to check if the firewall is enabled on a system.

Check if firewalld is running#
# firewall-cmd --state
running

In the previous example firewall-cmd was already shown and it is the command line interface to the firewalld daemon. Now that we have the firewall running, we can start configuring it. First we check all the active zones that are bound to which network interfaces.

Show the active zones and interfaces#
# firewall-cmd --get-active-zones
public
  interfaces: enp1s0

The example above shows that network interface enp1s0 is placed in the public zone, but what is defined in the public zone? With the option --list-all we can see the rules that are defined in the public zone. By default not a lot is defined in the public zone, but services like cockpit, dhcpv6-client and ssh are defined making the public zone a very useful zone to start with.

Show the configuration of the public zone#
# firewall-cmd --list-all --zone=public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: enp1s0
  sources:
  services: cockpit dhcpv6-client ssh
  ports:
  protocols:
  forward: no
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

What are firewall or network zones#

If we take the definition that the firewalld manpage says, a firewall zone is a collection of rules that are applied to a specific network interface. The public zone is the default zone, and it is the zone that is used when no other zone is specified.

Zones

A network or firewall zone defines the trust level of the interface used for a connection. There are several pre-defined zones provided by firewalld. Zone configuration options and generic information about zones are described in firewalld.zone(5)

But again, what is a zone and which one to select? The answer is simple as the zone defines the trust level of the interface used for a connection. If our server was directly connected to internet the dmz zone would be used, but if we were connected to a router, the internal zone would be used. By default a couple of zones are predefined, but you can add your own zones.

Show the available zones#
# firewall-cmd --get-zones
block dmz drop external home internal nm-shared public trusted work

All network interfaces are placed in the default network zone unless explicitly defined. With the option --get-default-zone we can see the default zone.

Show the default zone#
# firewall-cmd --get-default-zone
public

The default zone can also be changed and will directly change for all the interfaces unless explicitly defined. If you make the default zone block, then all unspecified interfaces will be placed in the block zone and all network traffic will direct stop directly.

Set the default zone#
# firewall-cmd --get-default-zone dmz
success
# firewall-cmd --get-active-zones
dmz
  interfaces: enp1s0

Note

The default zone in all examples will be public unless otherwise specified.

# firewall-cmd --change-interface=<nic> [--zone=<ZONE>]
Show the zone for a network interface#
# firewall-cmd --get-zone-of-interface=enp1s0
public
Show the interfaces in a zone#
# firewall-cmd --zone=dmz --list-interfaces
# firewall-cmd --zone=public --list-interfaces
enp1s0

Services#

$ firewall-cmd --get-services
RH-Satellite-6 RH-Satellite-6-capsule amanda-client amanda-k5-client amqp amqps apcupsd audit bacula bacula-client bb bgp bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc bittorrent-lsd ceph ceph-mon cfengine cockpit collectd condor-collector ctdb dhcp dhcpv6 dhcpv6-client distcc dns dns-over-tls docker-registry docker-swarm dropbox-lansync elasticsearch etcd-client etcd-server finger foreman foreman-proxy freeipa-4 freeipa-ldap freeipa-ldaps freeipa-replication freeipa-trust ftp galera ganglia-client ganglia-master git grafana gre high-availability http https imap imaps ipp ipp-client ipsec irc ircs iscsi-target isns jenkins kadmin kdeconnect kerberos kibana klogin kpasswd kprop kshell kube-api kube-apiserver kube-control-plane kube-controller-manager kube-scheduler kubelet-worker ldap ldaps libvirt libvirt-tls lightning-network llmnr managesieve matrix mdns memcache minidlna mongodb mosh mountd mqtt mqtt-tls ms-wbt mssql murmur mysql nbd netbios-ns nfs nfs3 nmea-0183 nrpe ntp nut openvpn ovirt-imageio ovirt-storageconsole ovirt-vmconsole plex pmcd pmproxy pmwebapi pmwebapis pop3 pop3s postgresql privoxy prometheus proxy-dhcp ptp pulseaudio puppetmaster quassel radius rdp redis redis-sentinel rpc-bind rquotad rsh rsyncd rtsp salt-master samba samba-client samba-dc sane sip sips slp smtp smtp-submission smtps snmp snmptrap spideroak-lansync spotify-sync squid ssdp ssh steam-streaming svdrp svn syncthing syncthing-gui synergy syslog syslog-tls telnet tentacle tftp tile38 tinc tor-socks transmission-client upnp-client vdsm vnc-server wbem-http wbem-https wireguard wsman wsmans xdmcp xmpp-bosh xmpp-client xmpp-local xmpp-server zabbix-agent zabbix-server
$ firewall-cmd --reload
$ firewall-cmd --add-service=oracle [--zone=<ZONE>]
$ firewall-cmd --add-service=oracle --zone=dmz --permanent
$ firewall-cmd --add-port=666/tcp
$ firewall-cmd --add-source=192.168.1.0/24
$ firewall-cmd --list-all
$ firewall-cmd --remove-port=666/tcp [--permanent] [--zone=<ZONE>]
$ firewall-cmd --remove-service=oracle [--permanent] [--zone=<ZONE>]
$ firewall-cmd --add-rich-rule `rule family=“ipv4” source address=“10.0.0.0/8” service name=“http” accept’
$ firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT

Runtime vs permanent and timeouts#

$ firewall-cmd --add-service=http --add-service=https
$ firewall-cmd --add-service=http --add-service=https --permanent
$ firewall-cmd --add-service=http --add-port=https/tcp
$ firewall-cmd --reload
$ firewall-cmd --add-service=http --add-service=https --timeout=<seconds>

Rich rules#

$ firewall-cmd --direct --permanent --add-chain ipv4 raw blacklist
$ firewall-cmd --direct --permanent --add-rule ipv4 raw PREROUTING 0 -s 192.168.0.0/24 blacklist
$ firewall-cmd --direct --permanent --add-rule ipv4 raw blacklist 0 -m limit --limit 1/min -j LOG --log-prefix "blacklist "
$ firewall-cmd --direct --permanent --add-rule ipv4 raw blacklist 1 -j DROP

Masquerading/NAT#

$ firewall-cmd --permanent --zone=work --add-masquerade

Port-forwarding#

$ firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.0.0/24 forward-port port=3000 protocol=tcp to-port=22122'
$ firewall-cmd --add-forward-port=port=3000:proto=tcp:toport=22122:toaddr=192.168.0.4

Advanced Network Management#

Network Management

Teaming and bonding#

Bridging#

Warning

Bridging support is known to be broken in many distributions. Be aware that your network configuration may be broken after using this feature.

$ yum install -y bridge-utils
$ nmcli con add type bridge con-name br0 ifname br0
$ nmcli con add type bridge-slave con-name br0-port1 ifname ens256 master br0
$ nmcli con add type bridge-slave con-name br0-port2 ifname ens161 master br0
$ nmcli con mod br0 ipv4.addresses 10.10.10.1/24
$ nmcli con mod br0 ipv4.method manual
$ nmcli con up br0
$ ip a
# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.000c293ae68b yes ens161
ens256

Teamed Bridging#

# nmcli con add type team con-name team0 ifname team0 config '{"runner": {"name": "activebackup"}}'
# nmcli con add type team-slave con-name team0-ens256 ifname ens256 master team0
# nmcli con add type team-slave con-name team0-ens161 ifname ens161 master team0

# nmcli dev dis team0
# systemctl stop NetworkManager
# systemctl disable NetworkManager

# vi /etc/sysconfig/network-scripts/ifcfg-team0
BRIDGE=brteam0

Removing the team config

# cat /etc/sysconfig/network-scripts/ifcfg-team0-ens161
NAME=team0-ens161
UUID=9dced9f4-35b6-4edb-9aed-8c922ded7b52
DEVICE=ens161
ONBOOT=yes
TEAM_MASTER=team0
DEVICETYPE=TeamPort

Create Bridge config:

vi ifcfg-brteam0
# cat ifcfg-brteam0
DEVICE=brteam0
ONBOOT=yes
type=Bridge
IPADDR0=10.10.10.1
PREFIX=24

Routing#

$ route  -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         192.168.2.254   0.0.0.0         UG    600    0        0 wlp1s0
10.0.1.0        0.0.0.0         255.255.255.0   U     0      0        0 virbr1
10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 virbr5
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.2.0     0.0.0.0         255.255.255.0   U     600    0        0 wlp1s0
192.168.122.0   0.0.0.0         255.255.255.0   U     0      0        0 virbr0

IPv6#

Domain Name System#

dig is a command line tool for querying the Domain Name System. There are alternatives like nslookup and host, but are being phased out and may give incorrect results.

$ dig mastering-linux.com soa

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com soa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27187
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      SOA

;; ANSWER SECTION:
mastering-linux.com.        3600    IN      SOA     gabe.ns.cloudflare.com. dns.cloudflare.com. 2274772751 10000 2400 604800 3600

;; Query time: 34 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:28:48 CEST 2022
;; MSG SIZE  rcvd: 107
$ dig mastering-linux.com ns

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com ns
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 55122
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      NS

;; ANSWER SECTION:
mastering-linux.com.        86400   IN      NS      megan.ns.cloudflare.com.
mastering-linux.com.        86400   IN      NS      gabe.ns.cloudflare.com.

;; Query time: 32 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:29:23 CEST 2022
;; MSG SIZE  rcvd: 101

dig mastering-linux.com a

$ dig mastering-linux.com

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13993
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      A

;; ANSWER SECTION:
mastering-linux.com.        300     IN      A       172.67.215.199
mastering-linux.com.        300     IN      A       104.21.69.237

;; Query time: 44 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:30:27 CEST 2022
;; MSG SIZE  rcvd: 80
$ dig mastering-linux.com a
$ dig mastering-linux.com aaaa

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com aaaa
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29375
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      AAAA

;; ANSWER SECTION:
mastering-linux.com.        300     IN      AAAA    2606:4700:3030::6815:45ed
mastering-linux.com.        300     IN      AAAA    2606:4700:3032::ac43:d7c7

;; Query time: 27 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:31:31 CEST 2022
;; MSG SIZE  rcvd: 104
$ dig mastering-linux.com mx

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com mx
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5323
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      MX

;; ANSWER SECTION:
mastering-linux.com.        300     IN      MX      55 isaac.mx.cloudflare.net.
mastering-linux.com.        300     IN      MX      40 linda.mx.cloudflare.net.
mastering-linux.com.        300     IN      MX      45 amir.mx.cloudflare.net.

;; Query time: 17 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:33:45 CEST 2022
;; MSG SIZE  rcvd: 130
$ dig mastering-linux.com txt

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com txt
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 20220
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      TXT

;; ANSWER SECTION:
mastering-linux.com.        300     IN      TXT     "google-site-verification=agka8dGjaI2llW-M_P6UgxjSteDeyW0whOvS1U0SprM"
mastering-linux.com.        300     IN      TXT     "v=spf1 include:_spf.mx.cloudflare.net ~all"

;; Query time: 26 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:32:17 CEST 2022
;; MSG SIZE  rcvd: 184
$ dig mastering-linux.com any

; <<>> DiG 9.16.27-RH <<>> mastering-linux.com any
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40601
;; flags: qr rd ra; QUERY: 1, ANSWER: 15, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 65494
;; QUESTION SECTION:
;mastering-linux.com.               IN      ANY

;; ANSWER SECTION:
mastering-linux.com.        36      IN      A       104.21.69.237
mastering-linux.com.        146     IN      TXT     "google-site-verification=agka8dGjaI2llW-M_P6UgxjSteDeyW0whOvS1U0SprM"
mastering-linux.com.        234     IN      MX      45 amir.mx.cloudflare.net.
mastering-linux.com.        3336    IN      DNSKEY  257 3 13 mdsswUyr3DPW132mOi8V9xESWE8jTo0dxCjjnopKl+GqJxpVXckHAeF+ KkxLbxILfDLUT0rAK9iUzy1L53eKGQ==
mastering-linux.com.        146     IN      TXT     "v=spf1 include:_spf.mx.cloudflare.net ~all"
mastering-linux.com.        234     IN      MX      55 isaac.mx.cloudflare.net.
mastering-linux.com.        36      IN      A       172.67.215.199
mastering-linux.com.        86136   IN      DS      2371 13 2 4777D07532CFC5B1E063C917FFCD4FAE816734AE78A8002A8EA4133C B2B8144C
mastering-linux.com.        3336    IN      DNSKEY  256 3 13 oJMRESz5E4gYzS/q6XDrvU1qMPYIjCWzJaOau8XNEZeqCYKD5ar0IRd8 KqXXFJkqmVfRvMGPmM1x8fGAa2XhSA==
mastering-linux.com.        234     IN      MX      40 linda.mx.cloudflare.net.
mastering-linux.com.        86136   IN      RRSIG   MX 13 2 300 20220418153345 20220416133345 34505 mastering-linux.com. eugoWsioT6xGWO3xqQUAo92qUBj3ne5t9wsB78mk33X5U2obF8Cfv7Ku tIId9myY0W9HW80iBiHPkxMPeyPAKg==
mastering-linux.com.        86136   IN      RRSIG   TXT 13 2 300 20220418153217 20220416133217 34505 mastering-linux.com. O5Po+DiLqYGIW87bGo9KhmBmlrbI0VpT9E0LJnmw6du4SSsdOJvU9MX/ nqG9LbFcH8Hkkgv/u1FFZbj4EZDtlw==
mastering-linux.com.        86136   IN      RRSIG   A 13 2 300 20220418153027 20220416133027 34505 mastering-linux.com. /0ofambSsTTdMVinzLJ/splLR8IzYKkK3bYPqwC97K6iyMIWOpZ723xw AYcrJvUIjn27HccuRzNI36EZwCP4Hg==
mastering-linux.com.        86136   IN      RRSIG   DNSKEY 13 2 3600 20220521081442 20220321081442 2371 mastering-linux.com. u5h/0jU+crxew/ZHZ65+3Fmy+HWwi1TPxUwICDerVLRfL1pHwkgbRGTG YH9gPBiJ6RMpXt0fB577YNrWs3MYbg==
mastering-linux.com.        86136   IN      RRSIG   DS 8 2 86400 20220422052804 20220415041804 38535 com. CwDNOW3A8kGRbVjJEaM1wi1Gi0KUEpM5Cx+WciMPBS3b1lz4Ggs1wBe2 Poo/s4pIRzWB+FZ2/LlqgDMC6YhPnb7caag+4/YVP5aJijS1RHF1/IFG 4kr7vBDCqZ3Qo96G6+Wf3g8Vf+Ii/HlfWv9ImkHJ3Lc4AnB6y7oPQgFr 1Y1QTxF+d7NmVUPPFcDK0AH7ZisSVjHiSKcLIjHu9ExqMw==

;; Query time: 39 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: Sun Apr 17 16:34:51 CEST 2022
;; MSG SIZE  rcvd: 1161
$ dig www.mastering-linux.com cname
$ dig mastering-linux.com axfr @ns1.mastering-linux.com

Network Services#

Network Time Protocol (NTP)#

# dnf install ntpsec

DNS Resolver#

# dnf install bind

Authoritative DNS Server#

# dnf install bind

DHCP Server#

# dnf install dhcp-server

DHCP relay

# dnf install dhcp-relay

Using iSCSI#

Introduction to iSCSI#

Target#

# yum install -y targetcli

# targetcli

Initiator#

Network File System (NFS)#

Introduction to NFS#

Install nfs-utils package

# yum install -y nfs-utils

Enable firewall rules for NFS

Note

This is not a complete list of firewall rules for NFS. Additional firewall services to open are rpc-bind and mountd

$ firewall-cmd --add-service=nfs
$ firewall-cmd --add-service=nfs --permamnent

Warning

Exposing NFS to the Internet is not recommended.

$ systemctl enable --now nfs-server
# mkdir -p /srv/nfs/share1
/srv/nfs/share1 10.0.0.0/8(rw)
# exportfs -r

/etc/fstab

servername:/share1  /mnt/nfsexport  nfs defaults 0 0
# mount -a

Samba#

Client#

Warning

Exposing Samba to the Internet is not recommended and most Internet providers block Samba access by default.

For mount and automounting, the cifs-util package is required.

# yum install -y cifs-utils

For manual connections, you can use the following package is required.

# yum install -y samba-client

Query a server for shares

# smbclient -L //<server-name>

Query a server for shares for a specific user

# smbclient -L //<server-name> -U <username>

Mount a shares

# mount -t cifs -o guest //server/public /mnt

/etc/fstab

//server/public /mnt cifs guest,uid=1000,gid=1000 0 0

Mount a shares

# mount -t cifs -o username=user01,password=secret //server/public /mnt

/root/smb-credetials.txt chmod 600

username=user01
password=secret
# mount -t cifs -o credentials=/root/smb-credentials.txt //server/public /mnt

/etc/fstab

//server/public /mnt cifs credentials=/root/smb-credentials.txt 0 0

Automounting#

/etc/auto.master.d/smb.autofs

/mnt /etc/auto.samba

/etc/auto.samba


SELinux#

SELinux, Security Enhanced Linux, is an implementation of Mandatory Access Control (MAC) for the Linux kernel. Mandatory Access Control (MAC) is a security feature that allows the kernel to enforce access control policies on the kernel objects. This means that with SELinux enforces if a process can access a file or directory, or execute a program, or open a device or socket while having the same user identifier.

While SELinux may seem difficult to use, it is very easy to use with the right tools and knowledge. The benefits of applying SELinux correctly are enourmous as it reduced lateral movement of people and data, and reduced the risk of security breaches. It can also be used te determine if an account has the right security level to access a file or directory.

Introduction to SELinux#

Mode: * Disabled (reboot required) * Permissive * Enforcing

$ sudo setenforce 0
$ sudo getenforce
Permissive
$ sudo setenforce 1
$ sudo getenforce
Enforcing
$ ps Zaux
LABEL                           USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
system_u:system_r:init_t:s0     root           1  0.0  0.0 173684 14312 ?        Ss   apr09   0:25 /usr/lib/systemd/systemd rhgb --system --deserialize 61
system_u:system_r:kernel_t:s0   root           2  0.0  0.0      0     0 ?        S    apr09   0:00 [kthreadd]
system_u:system_r:kernel_t:s0   root           3  0.0  0.0      0     0 ?        I<   apr09   0:00 [rcu_gp]
system_u:system_r:kernel_t:s0   root           4  0.0  0.0      0     0 ?        I<   apr09   0:00 [rcu_par_gp]
system_u:system_r:kernel_t:s0   root           6  0.0  0.0      0     0 ?        I<   apr09   0:00 [kworker/0:0H-events_highpri]
$ ps -ZC sshd
LABEL                               PID TTY          TIME CMD
system_u:system_r:sshd_t:s0-s0:c0.c1023 669548 ? 00:00:00 sshd
$ ls -Z /home
unconfined_u:object_r:user_home_dir_t:s0 user01
unconfined_u:object_r:user_home_dir_t:s0 user02
$ ls -Z /var/www
system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin
    system_u:object_r:httpd_sys_content_t:s0 html
$ ls -Z ~/.ssh
unconfined_u:object_r:user_home_t:s0 authorized_keys
unconfined_u:object_r:user_home_t:s0 aws-test-2022.pem
 unconfined_u:object_r:ssh_home_t:s0 config
 unconfined_u:object_r:ssh_home_t:s0 id_rsa
 unconfined_u:object_r:ssh_home_t:s0 id_rsa.pub
 unconfined_u:object_r:ssh_home_t:s0 known_hosts
unconfined_u:object_r:user_home_t:s0 other_keys.seahorse

SELinux Booleans#

$ getsebool -a
abrt_anon_write --> off
abrt_handle_event --> off
abrt_upload_watch_anon_write --> on
antivirus_can_scan_system --> off
antivirus_use_jit --> off
auditadm_exec_content --> on
authlogin_nsswitch_use_ldap --> off
authlogin_radius --> off
authlogin_yubikey --> off
awstats_purge_apache_log_files --> off
...
# setsebool zabbix_can_network 1
# setsebool -P zabbix_can_network 1

SELinux file context#

# ls -Zd /var/www/html
# touch /var/www/html/somefile
# ls -Z /var/www/html/somefile
# mkdir /srv/html
# ls -Z /srv/html
# semanage fcontext -a -t httpd_sys_content_t '/srv/html(/.*)?'
# ls -Z /srv/html
# restorecon -RFvv /srv/html
# ls -Z /srv/html

Troubleshooting#

/var/log/audit/audit.log and with package setroubleshoot-server installed also in /var/log/messages

sealert -a /var/log/audit/audit.log

Building a package#

Building a package from source#

Create a local repository#

# mkdir -p /srv/repo/local01
# createrepo /srv/repo/local01

Virtualization#

$ machinectl list
$ virsh

QEMU#

Checking a disk image#
# qemu-img check [-f format] imgname
Committing changes to an image#
# qemu-img commit [-f fmt] [-t cache] imgname
Comparing images#
# qemu-img compare [-f fmt] [-F fmt] [-p] [-s] [-q] imgname1 imgname2

Migrating Virtual Machines#

# systemctl enable --now libvirtd.service
# systemctl restart libvirtd.service
# vim /etc/libvirt/libvirtd.conf
# systemctl restart libvirtd.service

Shared Storage on NFS#

/etc/exports#
/var/lib/libvirt/images *.hypervisors.example.com(rw,no_root_squash,sync)
# dnf install nfs-utils
# systemctl enable --now nfs-server
# mount nfs01.storage.example.com:/var/lib/libvirt/images /var/lib/libvirt/images

Note

The directory has to be the same on all hypervisor machines.

Live Migration#

# virsh migrate --live GuestName DestinationURL
On brick01.hypervisor.example.com#
# virsh migrate --live vm01 qemu+ssh://brick02.hypervisor.example.com/system

Containers#

Introduction to Containers#

$ dnf install podman

Building Containers#