FHS On Debian/Ubuntu

FHSOnDebianUbuntu: Filesystem Hierarchy Standard on Debian and Ubuntu

Copyright (C) 2024 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.1. Introduction 
# - FHS (Filesystem Hierarchy Standard) is a set of guidelines and  specifications
# for organizing the structure and layout of directories in a Unix-like operating
# system. 
# - The goal of FHS is to create a consistent and predictable directory structure
# across different Unix and Unix-like systems, making it easier for software
# developers, system administrators, and users to understand where different types
# of files and data are located.
#
# Required Directories:
# /bin:   Essential command binaries
# /boot:  Static files of the boot loader
# /dev:   Device files
# /etc:   Host-specific system configuration
# /lib:   Essential shared libraries and kernel modules
# /media: Mount point for removable media
# /mnt:   Mount point for mounting a filesystem temporarily
# /opt:   Add-on application software packages
# /run:   Data relevant to running processes
# /sbin:  Essential system binaries
# /srv:   Data for services provided by this system
# /tmp:   Temporary files
# /usr:   Secondary hierarchy
# /var:   Variable data
#
# Optional Directories:
# /home:  User home directories
# /lib*:  Alternate format essential shared libraries
# /root:  Home directory for the root user
#
# Linux Specific Directories:
# /proc: Kernel and process information virtual filesystem.
# /sys: Kernel and system information virtual filesystem.
#
# In addition to the directory structure described in the FHS, the following
# directory can be found on Debian systems:
# /lost+found/ : File fragments that were recovered during the previous fsck
#
#-- 0.2. Quick Shot:
# /bin:                 Essential command binaries
# /boot:                Static files of the boot loader
# /dev:                 Device files
# /etc:                 Host-specific system configuration
# /etc/opt:             Configuration for /opt
# /etc/X11:             Configuration for the X Window system (Optional)
# /etc/sgml:            Configuration for SGML (Optional)
# /etc/xml:             Configuration for XML (Optional)
# /home:                User home directories
# /lib:                 Essential shared libraries and kernel modules
# /lib/modules:         Loadable kernel modules (Optional)
# /lib*:                Alternate format essential shared libraries
# /media:               Mount point for removable media
# /media/floppy:        Floppy drive (Optional)
# /media/cdrom:         CD-ROM drive (Optional)
# /media/cdrecorder:    CD writer (Optional)
# /media/zip:           Zip drive (Optional)
# /mnt:                 Mount point for mounting a filesystem temporarily
# /opt:                 Add-on application software packages
# /proc:                Kernel and process information virtual filesystem.
# /root:                Home directory for the root user
# /run:                 Data relevant to running processes
# /sbin:                Essential system binaries
# /srv:                 Data for services provided by this system
# /sys:                 Kernel and system information virtual filesystem.
# /tmp:                 Temporary files
# /usr:                 Secondary hierarchy
# /usr/bin:             Most user commands
# /usr/games:           Games and educational binaries (optional)
# /usr/include:         Header files included by C programs
# /usr/lib:             Libraries
# /usr/libexec:         Binaries run by other programs (optional)
# /usr/lib*:            Alternate Format Libraries (optional)
# /usr/local:           Local hierarchy (empty after main installation)
# /usr/local/bin:       Local binaries
# /usr/local/etc:       Host-specific system configuration for local binaries
# /usr/local/games:     Local game binaries
# /usr/local/include:   Local C header files
# /usr/local/lib:       Local libraries
# /usr/local/man:       Local online manuals
# /usr/local/sbin:      Local system binaries
# /usr/local/share:     Local architecture-independent hierarchy
# /usr/local/src:       Local source code
# /usr/sbin:            Non-vital system binaries
# /usr/share:           Architecture-independent data
# /usr/share/color:     Color management information
# /usr/share/dict:      Word lists
# /usr/share/doc:       Miscellaneous documentation
# /usr/share/games:     Static data files for /usr/games
# /usr/share/info:      Primary directory for GNU Info system
# /usr/share/locale:    Locale information
# /usr/share/man:       Online manuals
# /usr/share/misc:      Miscellaneous architecture-independent data
# /usr/share/nls:       Message catalogs for Native language support
# /usr/share/ppd:       Printer definitions
# /usr/share/sgml:      SGML data
# /usr/share/terminfo:  Directories for terminfo database
# /usr/share/tmac:      troff macros not distributed with groff
# /usr/share/xml:       XML data
# /usr/share/zoneinfo:  Timezone information and configuration
# /usr/src:             Source code (optional)
# /var:                 Variable data
# /var/account:         Process accounting logs (Optional)
# /var/cache:           Application cache data
# /var/crash:           System crash dumps (Optional)
# /var/games:           Variable game data (Optional)
# /var/lib:             Variable state information
# /var/local:           Variable data for /usr/local
# /var/lock:            Lock files
# /var/log:             Log files and directories
# /var/mail:            User mailbox files (Optional)
# /var/opt:             Variable data for /opt
# /var/run:             Data relevant to running processes
# /var/spool:           Application spool data
# /var/tmp:             Temporary files preserved between system reboots
# /var/yp:              Network Information Service (NIS) database files  
#
#-- 0.3. Sources:
# Filesystem Hierarchy Standard by LSB Workgroup, The Linux Foundation.
# ChatGPT

1. /bin – Essential Command Binaries

# - Contains commands for system administrators and users. These commands 
# must be required required when no other filesystems are mounted (e.g. in
# single user mode). It may also contain commands which are used indirectly by
# scripts.
#
# - In Debian 12 and Ubuntu 22.04 /bin is a symbolic link to /usr/bin.
# - There must be no subdirectories in /bin.
#
# - Command binaries that are not essential enough to place into /bin must be
# placed in /usr/bin, instead.
#
# - Some example commands: cat, chgrp, chmod, chown, cp, date, dd, df, dmesg,
# echo, false, hostname, kill, ln, login, ls, mkdir, mknod, more, mount, mv, ps,
# pwd, rm, rmdir, sed, sh, stty, su, sync, true, umount, uname.

2. /boot – Static Files of the Boot Loader

# - Contains everything required for the boot process except configuration files 
# not needed at boot time and the map installer. Stores data that is used before
# the kernel begins executing user-mode programs. This may include saved master
# boot sectors and sector map files.
# - Programs necessary to arrange for the boot loader to be able to boot a file
# must be placed in /sbin.
# - Configuration files for boot loaders that are not required at boot time must
# be placed in /etc.
# - The operating system kernel must be located in either / or /boot.
# - Certain architectures may have other requirements for /boot related to
# limitations or expectations specific to that architecture. 

3. /dev – Device Files

# - The /dev directory is the location of special or device files.
# - The devices in the /dev directory are created dynamically during the boot
# process or when new hardware is detected.
# - Some examples: 
# /dev/tty0
# /dev/sda
# /dev/null

4. /etc – Host-specific System Configuration

# - The /etc hierarchy contains configuration files.
# - It is recommended that files be stored in subdirectories of /etc rather than 
# directly in /etc.
# - No binaries may be located under /etc.
# - The following directory (or symbolic link to directory) is required:
# /etc/opt:   Configuration for /opt
#
# - The following directories (or symbolic links to directories) must be in 
# /etc, if the corresponding subsystem is installed:
# /etc/X11:   Configuration for the X Window system
# /etc/sgml:  Configuration for SGML
# /etc/xml:   Configuration for XML
#
# - The following files, or symbolic links to files, must be in /etc if the
# corresponding subsystem is installed:
#
# /etc/csh.login:   Systemwide initialization file for C shell logins
# /etc/exports:     NFS filesystem access control list
# /etc/fstab:       Static information about filesystems
# /etc/ftpusers:    FTP daemon user access control list
# /etc/gateways:    File which lists gateways for routed
# /etc/gettydefs:   Speed and terminal settings used by getty
# /etc/group:       User group file
# /etc/host.conf:   Resolver configuration file
# /etc/hosts:       Static information about host names
# /etc/hosts.allow: Host access file for TCP wrappers
# /etc/hosts.deny:  Host access file for TCP wrappers
# /etc/hosts.equiv: List of trusted hosts for rlogin, rsh, rcp
# /etc/hosts.lpd:   List of trusted hosts for lpd
# /etc/inetd.conf:  Configuration file for inetd
# /etc/inittab:     Configuration file for init
# /etc/issue:       Pre-login message and identification file
# /etc/ld.so.conf:  List of extra directories to search for shared libraries
# /etc/motd:        Post-login message of the day file
# /etc/mtab:        Dynamic information about filesystems
# /etc/mtools.conf: Configuration file for mtools
# /etc/networks:    Static information about network names
# /etc/passwd:      The password file
# /etc/printcap:    The lpd printer capability database
# /etc/profile:     Systemwide initialization file for sh shell logins
# /etc/protocols:   IP protocol listing
# /etc/resolv.conf: Resolver configuration file
# /etc/rpc:         RPC protocol listing
# /etc/securetty:   TTY access control for root login
# /etc/services:    Port names for network services
# /etc/shells:      Pathnames of valid login shells
# /etc/syslog.conf: Configuration file for syslogd
#
#-- 4.1. /etc/opt - Configuration for /opt
# - Host-specific configuration files for add-on application software packages
# must be installed within the directory /etc/opt/<subdir>, where <subdir> is 
# the name of the subtree in /opt where the static data from that package is
# stored.
# - No structure is imposed on the internal arrangement of /etc/opt/<subdir>.
# - If a configuration file must reside in a different location in order for the
# package or system to function properly, it may be placed in a location other
# than /etc/opt/<subdir>.
#
#-- 4.2. /etc/X11 - Configuration for the X Window System
# - Location for all X11 host-specific configuration. This directory is necessary
# to allow local control if /usr is mounted read only.
# - The following files, or symbolic links to files, must be in /etc/X11 if the
# corresponding subsystem is installed:
# /etc/opt/xorg.conf: The configuration file for X.org
# /etc/opt/Xmodmap:   Global X11 keyboard modification file
#
#-- 4.3. /etc/sgml - Configuration for SGML
# - Generic configuration files defining high-level parameters of the SGML systems
# are installed here. 
# - Files with names *.conf indicate generic configuration files. 
# - File with names *.cat are the DTD-specific centralized catalogs, containing
# references to all other catalogs needed to use the given DTD.
#
#-- 4.4. /etc/xml - Configuration for XML
# - Generic configuration files defining high-level parameters of the XML systems
# are installed here. 
# - Files with names *.conf indicate generic configuration files.

5. /home – User Home Directories

# - Home directories of users are stored here.
# - User specific configuration files for applications are stored in the user's
# home directory in a file that starts with the '.' character (a "dot file"). 
# - If an application needs to create more than one dot file then they should
# be placed in a subdirectory with a name starting with a '.' character, (a "dot
# directory"). In this case the configuration files should not start with the '.'
# character.
# - To find a user's home directory, use a library function such as getpwent,
# getpwent_r of fgetpwent rather than relying on /etc/passwd because user
# information may be stored remotely using systems such as NIS.
# - It is recommended that, apart from autosave and lock files, programs should
# refrain from creating non dot files or directories in a home directory
# without user consent.

6. /lib – Essential Shared Libraries and Kernel Modules

# - In Debian 12 and Ubuntu 22.04 /lib is a symbolic link to /usr/lib.
# - Contains shared library images needed to boot the system and run the commands
# in /bin and /sbin.
# - At least one of each of the following filename patterns are required (files or
# symbolic links):
# /lib/libc.so.*: The dynamically-linked C library
# /lib/ld*:        The execution time linker/loader
# - If a C preprocessor is installed, /lib/cpp must be a reference to it, for
# historical reasons.
# The following directory (or symbolic link to directory) must be in /lib, if the
# corresponding subsystem is installed:
# /lib/modules:    Loadable kernel modules

7. /lib* – Alternate format essential shared libraries

# - There may be one or more variants of the /lib directory on systems which 
# support more than one binary format requiring separate libraries.
# - By default; Debian 12 and Ubuntu 22.04 has the following directories:
# /lib32  - symbolic link to /usr/lib32
# /lib64  - symbolic link to /usr/lib64
# /libx32 - symbolic link to /usr/libx32
#
# - If one or more of these directories exist, the requirements for their contents
# are the same as the normal /lib directory, except that /lib*/cpp is not
# required.

8. /media – Mount Point for Removable Media

# - Contains subdirectories which are used as mount points for removable media
# such as floppy disks, cdroms and zip disks.
# - The following directories, or symbolic links to directories, must be in 
# /media, if the corresponding subsystem is installed:
# /media/floppy:      Floppy drive
# /media/cdrom:       CD-ROM drive
# /media/cdrecorder:  CD writer
# /media/zip:         Zip drive
#
# - On systems where more than one device exists for mounting a certain type of
# media, mount directories can be created by appending a digit to the name of
# those available above starting with '0', but the unqualified name must also
# exist.

9. /mnt – Mount Point for Mounting a Filesystem Temporarily

# - System administrators may temporarily mount a filesystem here.
# - The content of this directory is a local issue and should not affect the
# manner in which any program is run.
# - This directory must not be used by installation programs: a suitable temporary
# directory not in use by the system must be used instead.

10. /opt – Add-on Application Software Packages

# - This folder is empty on default Debian 12 and Ubuntu 22.04 installations.
# - Reserved for the installation of add-on application software packages.
# - The purpose of the /opt directory is to provide a location where software 
# vendors can install their software and organize it in a way that is separate 
# from the rest of the system's directory structure.
# - A package in /opt must locate its static files in a separate /opt/<package> 
# or /opt/<provider> directory tree. <package> is a name that describes the
# software package; and <provider> is the provider's LANANA registered name.
# - The directories /opt/bin, /opt/doc, /opt/include, /opt/info, /opt/lib, and 
# /opt/man are reserved for local system administrator use.
# - Package files that are variable (change in normal operation) must be installed
# in /var/opt.
# - Host-specific configuration files must be installed in /etc/opt.

11. /root – Home directory for the root user

# - Recommended home directory for the root user.
# - The root account's home directory may be determined by developer or local
# preference, but this is the recommended default location.
# - It is not recommended to use the root account for tasks that can be performed
# by an unprivileged user, and that it be used solely for system administration.
# For this reason, it is recommended that subdirectories for mail and other
# applications not appear in the root account's home directory.

12. /run – Data Relevant to Running Processes

# - Contains system information data describing the system since it was booted.
# - Files under this directory must be cleared (removed or truncated as
# appropriate) at the beginning of the boot process.
# - The purposes of this directory were once served by /var/run. In general,
# programs may continue to use /var/run to fulfill the requirements set out for 
# /run for the purposes of backwards compatibility.
# - Programs may have a subdirectory of /run; this is encouraged for programs that
# use more than one run-time file.
# - Process identifier (PID) files, which were originally placed in /etc, must be
# placed in /run. The naming convention for PID files is <program-name>.pid. For
# example, the crond PID file is named /run/crond.pid.

13. /sbin – Essential System Binaries

# - In Debian 12 and Ubuntu 22.04 /sbin is a symbolic link to /usr/bin.
# - Utilities used for system administration (and other root-only commands) are
# stored in /sbin, /usr/sbin, and /usr/local/sbin. 
# - /sbin contains binaries essential for booting, restoring, recovering, and/or
# repairing the system in addition to the binaries in /bin. 
# - There must be no subdirectories in /sbin.
# - If a normal user will ever run a command directly, then it must be placed in
# one of the "bin" directories. 
# - Ordinary users should not have to place any of the sbin directories in their
# path.
#
# - The following command (or symbolic link) is required in /sbin:
# /sbin/shutdown:  Command to bring the system down.
#
# - The following files (or symbolic links to files) must be in /sbin if the
# corresponding subsystem is installed:
# /sbin/fastboot:  Reboot the system without checking the disks
# /sbin/fasthalt:  Stop the system without checking the disks
# /sbin/fdisk:     Partition table manipulator
# /sbin/fsck:      File system check and repair utility
# /sbin/fsck.*:    File system check and repair utility for a specific filesystem
# /sbin/getty:     The getty program
# /sbin/halt:      Command to stop the system
# /sbin/ifconfig:  Configure a network interface
# /sbin/init:      Initial process
# /sbin/mkfs:      Command to build a filesystem
# /sbin/mkfs.*:    Command to build a specific filesystem
# /sbin/mkswap:    Command to set up a swap area
# /sbin/reboot:    Command to reboot the system
# /sbin/route:     IP routing table utility
# /sbin/swapon:    Enable paging and swapping
# /sbin/swapoff:   Disable paging and swapping
# /sbin/update:    Daemon to periodically flush filesystem buffers

14. /srv – Data for Services Provided by This System

# - This directory is empty on default installations of Debian 12 and Ubuntu
# 22.04.
# - Contains site-specific data that is served by the system. This directory 
# provides a location for data that is served by various services running on the 
# system, separate from other files associated with the operating system.
# - Unlike directories such as /usr or /var, which may contain data related to
# installed packages, the /srv directory is not intended for distribution
# packages. It is for locally administered data associated with specific services.

15. /tmp – Temporary Files

# - Provides a location for temporary files that are used by programs and users 
# during the course of their activities. 
# - It is recommended that files and directories located in /tmp be deleted
# whenever the system is booted.
# - Many applications and system processes use the /tmp directory for temporary
# file storage. For example, the system's package manager or various software
# installers may use /tmp to download and store temporary files before
# installation.
- /tmp directory is typically world-writable, allowing any user on the system to
# create, modify, or delete files within it. This openness facilitates the sharing
# of temporary files among users and processes.

16. /usr – Secondary hierarchy

# - Stands for "Unix System Resources".
# - Contains various subdirectories with user-related programs, libraries, documentation, and other resources. 
# - Typically mounted as a separate partition and may be shared among multiple 
# machines in a networked environment.
#
# - The following directories (or symbolic links to directories) are required: 
# /usr/bin:    Most user commands
# /usr/lib:    Libraries
# /usr/local:  Local hierarchy (empty after main installation)
# /usr/sbin:   Non-vital system binaries
# /usr/share:  Architecture-independent data
#
# - The following directories (or symbolic links to directories) are optional: 
# /usr/games:    Games and educational binaries
# /usr/include:  Header files included by C programs
# /usr/libexec:  Binaries run by other programs
# /usr/lib*:     Alternate Format Libraries
# /usr/src:      Source code
#
#-- 16.1. /usr/bin - Most User Commands
# - Primary directory of executable commands on the system.
# - There must be no subdirectories in /usr/bin.
#
# - The following files, or symbolic links to files, must be in /usr/bin, if 
# the corresponding subsystem is installed:
# /usr/bin/perl:    The Practical Extraction and Report Language
# /usr/bin/python:  The Python interpreted language
# /usr/bin/tclsh:   Simple shell containing Tcl interpreter
# /usr/bin/wish:    Simple Tcl/Tk windowing shell
# /usr/bin/expect:  Program for interactive dialog
#
#-- 16.2. /usr/include - Header Files Included by C Programs
# - All of the system's general-use include files for the C programming language
# should be placed here.
#
# - The following directory (or symbolic link to directory) must be in 
# /usr/include, if the corresponding subsystem is installed:
# /usr/include/bsd: BSD compatibility include files (optional)
#
#-- 16.3. /usr/lib - Libraries
# - Includes object files and libraries. On some systems, it may also include
# internal binaries that are not intended to be executed directly by users or
# shell scripts.
# - Applications may use a single subdirectory under /usr/lib. If so; all
# architecture-dependent data exclusively used by the application must be placed
# within that subdirectory. 
# - For historical reasons, /usr/lib/sendmail must be a symbolic link which
# resolves to the sendmail-compatible command provided by the system's mail
# transfer agent, if the latter exists.
#
#-- 16.4. /usr/libexec - Binaries Run by Other Programs
# - Includes internal binaries that are not intended to be executed directly by
# users or shell scripts. 
# - Applications may use a single subdirectory under /usr/libexec.
# - Applications which use /usr/libexec in this way must not also use /usr/lib 
# to store internal binaries, though they may use /usr/lib for the other purposes
# documented here.
#
#-- 16.5. /usr/lib* - Alternate Format Libraries
# - By default; Debian 12 and Ubuntu 22.04 has the following directories:
# /usr/lib32  - symbolic link to /usr/lib32
# /usr/lib64  - symbolic link to /usr/lib64
# /usr/libx32 - symbolic link to /usr/libx32
#
# - /usr/lib* performs the same role as /usr/lib for an alternate binary format,
# except that the symbolic links /usr/lib*/sendmail and /usr/lib*/X11 are not
# required.
# - The case where /usr/lib and /usr/lib<qual> are the same (one is a symbolic
# link to the other) these files and the per-application subdirectories will
# exist.
#
#-- 16.6. /usr/local - Local Hierarchy
# - For use by the system administrator when installing software locally. 
# - It needs to be safe from being overwritten when the system software is
# updated. 
#
# - The following directories (or symbolic links to directories), must be in 
# /usr/local:
# /usr/local/bin:     Local binaries
# /usr/local/etc:     Host-specific system configuration for local binaries
# /usr/local/games:   Local game binaries
# /usr/local/include: Local C header files
# /usr/local/lib:     Local libraries
# /usr/local/man:     Local online manuals
# /usr/local/sbin:    Local system binaries
# /usr/local/share:   Local architecture-independent hierarchy
# /usr/local/src:     Local source code
#
# - If directories /lib* or /usr/lib* exist, the equivalent directories must also
# exist in /usr/local.
# - /usr/local/etc may be a symbolic link to /etc/local.
#
#-- 16.7. /usr/sbin - Non-vital System Binaries
# - Contains any non-essential binaries used exclusively by the system 
# administrator. 
# - System administration programs that are required for system repair, system
# recovery, mounting /usr, or other essential functions must be placed in /sbin
# instead.
# - There must be no subdirectories in /usr/sbin.
#
#-- 16.8. /usr/share - Architecture-Independent Data
# - This hierarchy is for all read-only architecture independent data files.
# - This hierarchy is intended to be shareable among all architecture platforms of 
# a given OS; thus, for example, a site with i386, Alpha, and PPC platforms might
# maintain a single /usr/share directory that is centrally-mounted. 
# - However, that /usr/share is generally not intended to be shared by different
# OSes or by different releases of the same OS.
# - Game data stored in /usr/share/games must be purely static data. Any
# modifiable files, such as score files, game play logs, and so forth, should be
# placed in /var/games.
#
# - The following directories, or symbolic links to directories, must be in 
# /usr/share
# /usr/share/man:   Online manuals
# /usr/share/misc:  Miscellaneous architecture-independent data
#
# - The following directories, or symbolic links to directories, must be in 
# /usr/share, if the corresponding subsystem is installed:
# /usr/share/color:     Color management information
# /usr/share/dict:      Word lists
# /usr/share/doc:       Miscellaneous documentation
# /usr/share/games:     Static data files for /usr/games
# /usr/share/info:      Primary directory for GNU Info system
# /usr/share/locale:    Locale information
# /usr/share/nls:       Message catalogs for Native language support
# /usr/share/ppd:       Printer definitions
# /usr/share/sgml:      SGML data
# /usr/share/terminfo:  Directories for terminfo database
# /usr/share/tmac:      troff macros not distributed with groff
# /usr/share/xml:       XML data
# /usr/share/zoneinfo:  Timezone information and configuration
#
#- 16.8.1. /usr/share/color - Color Management Information
# - This directory is the home for ICC color management files installed by the
# system.
# - The following directory must be in /usr/share/color, if the corresponding 
# subsystem is installed:
# /usr/share/color/icc:   ICC color profiles (optional)
#
# - The top-level directory /usr/share/color must not contain any files; all files
# should be in subdirectories of /usr/share/color.
#
#- 16.8.2. /usr/share/dict - Word Lists
# - Home for word lists on the system.
# - Traditionally this directory contains only the English words file, which is 
# - used by look(1) and various spelling programs. 
# - Words may use either American or British spelling.
# - The reason that only word lists are located here is that they are the only
# files common to all spell checkers.
#
# - The following files, or symbolic links to files, must be in /usr/share/dict,
# if the corresponding
# /usr/share/dict/words: List of English words
#
# - Sites that require both American and British spelling may link words to 
# /usr/share/dict/american-english or /usr/share/dict/british-english.
# - Word lists for other languages may be added using the English name for that
# language, e.g., /usr/share/dict/french, /usr/share/dict/danish, etc. 
#
#- 16.8.3. /usr/share/man - Online Manuals
# - The primary <mandir> of the system is /usr/share/man. /usr/share/man contains
# manual information for commands and data under the / and /usr filesystems.
#
#- 16.8.4. /usr/share/misc - Miscellaneous Architecture-independent Data
# - Contains miscellaneous architecture-independent files which don't require a
# separate subdirectory under /usr/share.
# - The following files, or symbolic links to files, must be in /usr/share/misc,
# if the corresponding subsystem is installed:
# /usr/share/misc/ascii       ASCII character set table
# /usr/share/misc/termcap     Terminal capability database
# /usr/share/misc/termcap.db  Terminal capability database
#
#- 16.8.5. /usr/share/ppd - Printer Definitions
# - Contains PostScript Printer Definition (PPD) files, which are used as 
# descriptions of printer drivers by many print systems. 
# - PPD files may be placed in this directory, or in a subdirectory.
#
#- 16.8.6. /usr/share/sgml - SGML Data
# - Contains architecture-independent files used by SGML applications, such as
# ordinary catalogs (not the centralized ones, see /etc/sgml), DTDs, entities, 
# or style sheets.
#
# - The following directories, or symbolic links to directories, must be in 
# /usr/share/sgml, if the corresponding subsystem is installed:
# /usr/share/sgml/docbook  docbook DTD
# /usr/share/sgml/tei      tei DTD
# /usr/share/sgml/html     html DTD
# /usr/share/sgml/mathml   mathml DTD
#
# - Other files that are not specific to a given DTD may reside in their own
# subdirectory.
#
#- 16.8.7. /usr/share/xml - XML Data
# - Contains architecture-independent files used by XML applications, such as
# ordinary catalogs (not the centralized ones, see /etc/sgml), DTDs, entities, 
# or style sheets.
#
# - The following directories (or symbolic links to directories) must be in 
# /usr/share/xml, if the corresponding subsystem is installed:
# /usr/share/xml/docbook  docbook XML DTD
# /usr/share/xml/xhtml    XHTML DTD
# /usr/share/xml/mathml   MathML DTD
#
#-- 16.9. /usr/src - Source Code
# - Source code may be placed in this subdirectory, only for reference purposes.
# - Generally, source should not be built within this hierarchy.

17. /var – Variable Data

# - Contains variable data files. This includes spool directories and files,
# administrative and logging data, and transient and temporary files.
# - Applications must generally not add directories to the top level of /var.
#
# The following directories (or symbolic links to directories) are required in 
# /var:
# /var/cache:  Application cache data
# /var/lib:    Variable state information
# /var/local:  Variable data for /usr/local
# /var/lock:   Lock files
# /var/log:    Log files and directories
# /var/opt:    Variable data for /opt
# /var/run:    Data relevant to running processes
# /var/spool:  Application spool data
# /var/tmp:    Temporary files preserved between system reboots
#
# - Following directories are `reserved' and must not be used arbitrarily by some
# new application:
# /var/backups
# /var/cron
# /var/msgs
# /var/preserve
#
# - The following directories, or symbolic links to directories, must be in /var,
# if the corresponding subsystem is installed:
# /var/account:  Process accounting logs
# /var/crash:    System crash dumps
# /var/games:    Variable game data
# /var/mail:     User mailbox files
# /var/yp:       Network Information Service (NIS) database files

18. Special to Linux

# - There are two more directory standarts specific to Linux:
# /proc and /sys
#
#-- 18.1. /proc - Kernel and Process Information Virtual Filesystem
# - Kernel and process information virtual filesystem.
# - The proc filesystem is the de-facto standard Linux method for handling process
# and system information, rather than /dev/kmem and other similar methods. 
# - /proc is a virtual filesystem, which means that it doesn't exist on a physical
# storage device like a hard drive. Instead, it is dynamically generated by the
# kernel and provides a window into the current state of the running kernel and
# system.
#
#-- 18.2. /sys - Kernel and System Information Virtual Filesystem
# - Kernel and system information virtual filesystem.
# - The sys filesystem is the location where information about devices, drivers, 
# and some kernel features is exposed.
# - The /sys directory exposes information about various kernel parameters and
# configurations. You can read and modify certain kernel parameters through the
# files in this directory.
# - /sys is a virtual filesystem, which means that it doesn't exist on a physical
# storage device like a hard drive.




Systemd on Debian/Ubuntu 2

SystemdOnDebianUbuntu2 Other Systemd Components on Debian and Ubuntu

Copyright (C) 2024 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.1. Intro
# - The first Systemd tutorial, namely Systemd On Debian/Ubuntu was about 
# systemd's init and service management properties.
#
# - Systemd has more than that, it has a lot of other services and tools. This 
# tutorial covers them.
#
# - You may think that I like systemd. Not at all, I don't like it, more precisely
# I hate it. Just because my favorite distros (Debian and Ubuntu) uses it, I have
# to learn it too.
# 
#-- 0.2. Sources
# - For this tutorial I tried another approach. Instead of searching information 
# from the internet and the books; I asked questions to ChatGPT and collected the
# answers.
# - Unfortunately (or maybe fortunately) there were a lot of wrong information 
# from ChatGPP. I checked every answer before I prepare this tutorial.
# - AI still needs a lot of work before becoming really useful.
#

1. Services

# Debian 12 and Ubuntu 22.04 Server has the following systemd services by
# default:
#
# systemd-journald
# systemd-logind
# systemd-networkd
# systemd-resolved
# systemd-timesyncd
# systemd-udevd
# systemd-tmpfiles
# systemd-binfmt
# systemd-modules-load
# systemd-random-seed
# systemd-remount-fs
# systemd-sysctl
# systemd-sysusers

1.1. systemd-journald

# systemd-journald is the component of the systemd suite responsible for
# collecting, storing, and managing log data on Linux systems. It is the default
# logging system on systems using systemd, including Debian and Ubuntu Linux
# distributions.
#
#-- 1.1.1. Logs
# - Stores log data in binary format
# - log data stored in the /var/log/journal/ directory. 
# - Log files undergo automatic rotation and compression.
# - Includes rate-limiting mechanisms to prevent logs from being flooded in
# high-traffic situations.
# - The journalctl command is used to query and display log data managed by
# systemd-journald. 
# - Manages user specific logs too.
#
#-- 1.1.2. Configuration
# Configuration file is /etc/systemd/journald.conf file. 
# /etc/systemd/journald.conf
[Journal]
# Specify the maximum disk space that journal files may use.
# The default is infinity (i.e., unlimited).
SystemMaxUse=50M
#
# Specify the maximum disk space that should be used for runtime logs.
RuntimeMaxUse=50M
#
# Specify the maximum disk space that may be used for log data.
# This controls both system and runtime logs.
# The default is infinity (i.e., unlimited).
MaxUse=100M
#
# Specify the maximum number of individual journal files to retain.
# Older files are deleted when the limit is reached.
SystemMaxFiles=100
#
# Specify the maximum number of runtime journal files to retain.
# Older files are deleted when the limit is reached.
RuntimeMaxFiles=100
#
# Specify the maximum number of journal files to retain.
# This controls both system and runtime logs.
# Older files are deleted when the limit is reached.
MaxFiles=200
#
# Compress and store journal files in a read-only archive directory.
# Uncomment the line below and specify the archive directory path.
# This reduces the disk space usage but prevents further writes to the archived 
# logs.
# Also, consider setting "Storage=auto" if using this option.
# Compress=yes
# SystemKeepFree=50M
# RuntimeKeepFree=50M
# KeepFree=100M
#
# Specify a higher verbosity level for detailed log information.
# Options: "emerg", "alert", "crit", "err", "warning", "notice", "info", "debug".
# The default is "info".
# LogLevel=debug
#
# Specify the maximum runtime for system services to finish startup.
# This helps in capturing early boot logs completely.
# The default is 30s.
# RuntimeMaxSec=30s
#
# Enable persistent journal storage across reboots.
# The default is "auto".
# Storage=auto
#
# Disable persistent journal storage.
# Storage=none
#
# Specify the maximum size of individual journal files.
# The default is 8M.
# SystemMaxFileSize=16M
# RuntimeMaxFileSize=16M
# MaxFileSize=32M
#
# Specify the rate limit for journal events in bytes per second.
# The default is 1M.
# RateLimitBurst=2M
# RateLimitIntervalSec=30s
#
# Enable forwarding of journal logs to syslog.
# ForwardToSyslog=yes
#
# Specify the syslog identifier to use when forwarding logs.
# ForwardToSyslogIdentifier=journal
#
# Activate changed configuration:
sudo systemctl restart systemd-journald

1.2. systemd-logind

#
# systemd-logind is a component of the systemd system and service manager that
# manages user sessions and seat devices on Linux systems. It is responsible for
# handling user logins, seat management (logical grouping of input and output
# devices), and various aspects of the user environment.
#
#-- 1.2.1. Key Points
# - Tracks user sessions, allowing the system to associate processes with
# specific user logins.
# - Involved in power management tasks. Can apply inhibition of shutdown and
# sleep.
# - Keeps track of user sessions and provides information about active and 
# inactive sessions.
# - Integrates with desktop environments and display managers, allowing for
# better control over user sessions and seat devices.
#
#-- 1.2.2. Configuration
# Configuration file: /etc/systemd/logind.conf file.
#
# Example configuration:
# /etc/systemd/logind.conf
#
[Login]
# This controls whether systemd-logind shall remove all sessions and seats
# on logout. This includes killing all processes in these sessions and
# stopping any session scope units that may be active. Note that enabling
# this setting may result in multiple sessions being created and removed
# on login and logout of a user.
#Default: yes
KillUserProcesses=yes
#
# ConsoleKit compatibility
# In addition to SessionsActivated, which can be used to check whether a
# user session is registered with systemd-logind, this switch enables
# basic ConsoleKit compatibility.
#Default: yes
ConsoleKitCompatibility=yes
#
# ReserveVT=N tells logind to leave N VTs unbound from it and do not
# release them from its VT pool. This option is only useful for embedded
# and appliance-like systems where the system console shall always be
# bound to VT number 1 or similar. In this case, set this to 1.
#Default: 6
ReserveVT=6
#
# Kill only user processes that are part of the same session as the
# service that is being terminated. Setting this to "yes" is equivalent
# to enabling KillUserProcesses=yes.
#Default: no
KillOnlyUsers=no
#
# Enable power management features when requested by a graphical session
# (with "HandlePowerKey=ignore" in logind.conf). This includes
# logind's inhibitors mechanism that is used to block system sleep/shutdown
# via inhibitors of running multimedia sessions.
#Default: yes
HandlePowerKey=yes
#
# HandleRebootKey and HandlePowerKey are not handled by logind when
# the caller is not root or a member of the group root. The user is expected
# to start "systemctl start shutdown.target", "systemctl start reboot.target"
# manually in the session.
# NOTE: PowerKey and RebootKey must be set to "ignore" to disable any
# handling, even if HandlePowerKey/HandleRebootKey is set to "yes".
HandleSuspendKey=yes
HandleHibernateKey=yes
HandleLidSwitch=yes
#
# Disable user switching
# Allow users who are logged in on one virtual terminal to switch to
# another one.
#Default: yes
#AllowUserSwitching=yes
#
# Enable user switching
#DisallowUserSwitching=no
#
# Handle displays that are attached to seats (such as graphics cards).
# If all seats are taken, users with displays attached to a seat are not
# allowed to log in.
#Default: yes
#Multiseat=no
#
# Handle automatic handling of display numbering, based on the seat and
# hardware ID of the graphics card. See "systemd-localed.service" for details.
#Default: no
#AutomaticVTSwitch=no
#
# Controls whether logind shall use ACLs and other mechanisms to control the
# access to the devices seats depend on. ACLs and other controls might add
# security, but may lead to problems when running certain setups (e.g.
# multiseat). Turn this off if you experience problems.
#Default: yes
#RestrictAccessToVT=yes
#
# Activate new conf
sudo systemctl restart systemd-logind

1.3. systemd-networkd

#
# This service is not active in default Debian 12 installation.
#
# Ubuntu installations use netplan as an interface to networkd.
#
# systemd-networkd is a component of the systemd suite that manages network
# configurations on Linux systems. It is designed to provide a simple and
# efficient way to configure and manage network interfaces, including wired and
# wireless connections. 
#
#-- 1.3.1. Key Points
# - Configures various link settings, including IP addresses, gateways, DNS
# servers, and other network parameters.
# - Supports the configuration of bridges and VLANs
# - Integrates with systemd-resolved to provide DNS resolution services.
# - Can dynamically discover and configure network interfaces.
#
#-- 1.3.2. Configuration
# - Relies on configuration files (with a .network extension) in the 
# /etc/systemd/network/ directory. 
#
# A simple systemd-networkd configuration file for DHCP
# /etc/systemd/network/eth0.network
[Match]
Name=eth0
#
[Network]
DHCP=yes
#
# This configuration file tells systemd-networkd to apply the settings to the
# network interface named "eth0" and to use DHCP for IP configuration.
#
# A detailed configuration with a static IP address, DNS settings, and
# additional options for a more comprehensive configuration.
# /etc/systemd/network/20-wired.network
[Match]
Name=enp0s3
#
[Network]
Address=192.168.1.2/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
Domains=mydomain.local
NTP=pool.ntp.org
#
[Link]
MTUBytes=1400
MACAddressPolicy=persistent
# 
# - Address: The static IP address and subnet mask.
# - Gateway: The default gateway.
# - DNS: DNS server addresses.
# - Domains: Search domains for DNS resolution.
# - NTP: NTP server for time synchronization.
# - MTUBytes: Maximum Transmission Unit size.
# - MACAddressPolicy: Set to persistent to use a stable MAC address.
#
# 1.3.3. Important Notes
# - Please remember that; Debian 12 does not use systemd-networkd; and Ubuntu
# 22.04 uses Netplan for network configuration. Netplan generates networkd 
# configuration files on /run/systemd/network directory; you are not supposed 
# to change those files.
# 

1.4. systemd-resolved

#
# This service is not active in a default Debian 12 installation.
#
# systemd-resolved is a systemd service that provides network name resolution
# services on Linux systems. It is responsible for DNS resolution and provides a
# local DNS stub resolver and caching daemon. 
#
#-- 1.4.1. Key Points
# - Runs as a daemon process.
# - Acts as a local DNS stub resolver, which means it forwards DNS queries to
# DNS servers on behalf of client applications.
# - Caches DNS responses locally to reduce the need for repeated DNS queries.
# - Supports Multicast DNS (mDNS), allowing resolution of hostnames in the local
# network without relying on a dedicated DNS server.
# - Can be configured to use DNS over TLS (DoT)
# - Can dynamically reconfigure itself based on changes in network
# configuration, such as changes in DNS server addresses or domain search lists.
# - Often used in conjunction with systemd-networkd
# - Integrates with the Name Service Switch (NSS) configuration
# - resolvectl command is used to query and interact with systemd-resolved.
#
#-- 1.4.2. Configuration
# The configuration file is /etc/systemd/resolved.conf.
#
# Simple example configuration
# /etc/systemd/resolved.conf
#
ini
[Resolve]
DNS=8.8.8.8 8.8.4.4
DNSOverTLS=yes
DNSSEC=yes
#
# Detailed example configuration
# /etc/systemd/resolved.conf
#
[Resolve]
# Specify DNS servers to use for name resolution.
# Multiple servers can be separated by spaces.
# You can use IPv4 and IPv6 addresses.
# Example DNS settings for Google Public DNS:
# DNS=8.8.8.8 8.8.4.4
# DNS=2001:4860:4860::8888 2001:4860:4860::8844
# 
# Enable DNS over TLS (DoT) for encrypted and authenticated communication with 
# DNS servers.
# This enhances the security and privacy of DNS queries.
# DNSOverTLS=yes
# 
# Specify the DNSSEC (DNS Security Extensions) validation mode.
# Valid options: "allow-downgrade", "opportunistic", "require", and "no".
# DNSSEC=yes
# 
# Enable DNSSEC negative trust anchors.
# DNSSECNegativeTrustAnchors=yes
# 
# Specify the domains for which DNS queries should use DNS over TLS.
# Domains using DoT will not fall back to plaintext DNS.
# DNSOverTLSDomains=example.com test.net
# 
# Specify the search domains for unqualified hostnames.
# Multiple domains can be separated by spaces.
# SearchDomains=example.com subdomain.example.net
# 
# Specify the domains for which LLMNR (Link-Local Multicast Name Resolution) 
# should be used.
# LLMNR=yes
# 
# Specify the multicast DNS (mDNS) domains.
# mDNS=yes
# 
# Specify the time to live (TTL) for positive cache entries in seconds.
# CacheTTL=120
# 
# Specify the TTL for negative cache entries in seconds.
# NegativeCacheTTL=120
# 
# Specify the maximum size of the cache in kilobytes.
# CacheLimit=512M
# 
# Specify the maximum number of DNS messages in transit.
# Messages max transit=4096
# 
# Enable DNS fallback in case the resolved server cannot be contacted.
# FallbackDNS=8.8.8.8 8.8.4.4
# 
# Enable caching DNS negative responses.
# CacheNegative=yes
# 
# Enable automatic reconfiguration of resolved in response to network changes.
# DynamicUser=yes

1.5. systemd-timesyncd

#
# systemd-timesyncd is a component of the systemd suite designed to synchronize
# the system clock across a network, ensuring accurate timekeeping on Linux
# systems. It acts as a simple NTP (Network Time Protocol) client, allowing your
# system to regularly synchronize its clock with remote NTP servers.
#
#-- 1.5.1. Key Points
# - Runs as a service.
# - Functions as a lightweight NTP client, periodically querying remote NTP
# servers to obtain accurate time information.
# - timedatectl command provides information about the system clock and its
# synchronization status.
#
#-- 1.5.2. Configuration
# Example configuration
# /etc/systemd/timesyncd.conf
[Time]
# Specify the NTP servers to use for time synchronization.
# Multiple servers can be specified, separated by spaces.
# Example NTP servers:
# NTP=pool.ntp.org time.google.com
#
# Specify the time to wait for the initial synchronization in seconds.
# The default is 1 minute.
# TimeoutStartSec=1min
#
# Specify the interval between updates.
# The default is 5 minutes.
# PollIntervalMinSec=5min
#
# Enable or disable systemd-timesyncd's NTP server.
# The default is "no".
# EnableNTP=yes
#
# Enable or disable setting the system clock from the RTC.
# The default is "yes".
# RTCUseUtc=yes
#
# - Detailed Example
# /etc/systemd/timesyncd.conf
#
[Time]
# Specify the NTP servers to use for time synchronization.
# Multiple servers can be specified, separated by spaces.
# Example NTP servers:
# NTP=pool.ntp.org time.google.com
NTP=pool.ntp.org
#
# Specify the time to wait for the initial synchronization in seconds.
# The default is 1 minute.
# TimeoutStartSec=1min
#
# Specify the interval between updates.
# The default is 5 minutes.
# PollIntervalMinSec=5min
#
# Enable or disable systemd-timesyncd's NTP server.
# The default is "no".
# EnableNTP=yes
#
# Enable or disable setting the system clock from the RTC.
# The default is "yes".
# RTCUseUtc=yes
#
# Specify the maximum allowed adjustment in seconds.
# If the difference between the system clock and the NTP server exceeds this 
# value, a larger step will be used to correct the time.
# The default is 0.2 seconds.
# MaxOffsetSec=1
#
# Specify the maximum acceptable root distance.
# This is the maximum possible error due to the network latency in seconds.
# The default is 5 seconds.
# RootDistanceMaxSec=5
#
# Specify the maximum acceptable polling interval for reaching out to NTP 
# servers.
# The default is 64 seconds.
# PollIntervalMaxSec=64
#
# Specify the minimum acceptable polling interval.
# The default is 32 seconds.
# PollIntervalMinSec=32

1.6. systemd-udevd

#
# systemd-udevd is a component of the systemd suite, responsible for handling
# device events and managing the device nodes in the Linux kernel's /dev
# directory. It is a dynamic device management daemon that monitors hardware
# changes and triggers actions based on device-related events.
#
#-- 1.6.1. Key Points
# - Monitors the Linux kernel's netlink interface for device-related events,
# such as the discovery of new devices or the removal of existing devices.
# - Dynamically manages the device nodes in the /dev directory.
# - Uses a rule-based configuration system to define how it should respond to
# specific device events. 
# - Allows for persistent device naming based on attributes like MAC addresses
# or other unique identifiers.
# - Maintains a device database (/run/udev/data) that stores device information.
#
#-- 1.6.2. Configuration
# - Rules written in /etc/udev/rules.d/ directory define
# - Rules can include actions such as running scripts, creating symlinks, 
# setting permissions, and more.
# - Rules specify actions to be taken for specific devices. Common actions
# include "add," "remove," "change," and "move."
# - Rules can execute custom scripts or commands in response to events, allowing
# for fine-grained customization of device handling.
# 
# - An example rule that runs a script when a USB drive with a specific vendor
# ID is inserted:
#
# /etc/udev/rules.d/80-custom-network.rules
#
# Rule for a USB drive with vendor ID 1234
SUBSYSTEM=="block", ACTION=="add", ENV{ID_VENDOR_ID}=="1234", RUN+="/path/to/custom-script.sh"
#     
# SUBSYSTEM=="block": The rule applies to block devices.
# ACTION=="add": The rule triggers when a new block device is added.
# ENV{ID_VENDOR_ID}=="1234": Vendor ID should be 1234.
# RUN+="/path/to/custom-script.sh": The script to run
#
# Various conditions can be used  to match devices based on attributes such as
# subsystem, kernel, device name, and more.
#
# udev provides a set of variables that you can use in your rules. Like: 
# SUBSYSTEM, KERNEL, ID_VENDOR_ID, ID_MODEL_ID

1.7.. systemd-tmpfiles

# systemd-tempfiles is a component of the systemd suite, and it is responsible
# for managing temporary files and directories on a Linux system. It provides a
# mechanism for creating and cleaning up temporary files and directories at
# system startup and during runtime. 
#
#-- 1.7.1. Configuration
# - Configuration files are in /usr/lib/tmpfiles.d/ and /etc/tmpfiles.d/
# directories.
#
# - Configuration Format:
# [Type] Path Mode Age Argument
#
# Type: Specifies the type of operation (create, remove, modify).
# Path: Specifies the path to the file or directory.
# Mode: Specifies the permissions mode for the file or directory.
# Age: Specifies how long the file or directory should be retained before 
# removal.
# Argument: Additional arguments or options, depending on the type.
#
# - Example configuration:
#
# /etc/tmpfiles.d/my_temporary_files.conf
#
# Create a directory with specific permissions
d /var/my_temp_dir 0755 root root -
#
# Create an empty file with specific permissions
f /var/my_temp_file 0644 root root -
#
# Remove files older than 7 days in a specific directory
D /var/log/my_logs/*.log - - - 7d
#
# d: Create a directory.
# f: Create an empty file.
# D: Remove files older than a specified age.
# F: Create file with contents
# L: Create symlink
# c: Create character device
# b: Create block device)
#
#-- 1.7.2. Examples
#
# Create a temporary directory at boot.
# /etc/tmpfiles.d/my_temp_directory.conf
#
# Type 'd' indicates creating a directory
d /var/my_temp_directory 0755 root root -
#
# d: Specifies that a directory should be created.
# /var/my_temp_directory: Path to the directory.
# 0755: Permissions (owner: read, write, execute; group and others: read, 
# execute).
# root root: Specifies the owner and group.
# - : No specific age for removal.
#
# Create an empty file with specific permissions.
# /etc/tmpfiles.d/my_temp_file.conf
#
# Type 'f' indicates creating an empty file
f /var/my_temp_file 0644 root root -
#
# f: Specifies that an empty file should be created.
# /var/my_temp_file: Path to the file.
# 0644: Permissions (owner: read, write; group and others: read).
# root root: Specifies the owner and group.
# -: No specific age for removal.
#
# Remove log files older than 7 days:
# /etc/tmpfiles.d/remove_old_logs.conf
#
# Type 'D' indicates removing files older than a specified age
D /var/log/my_logs/*.log - - - 7d
#
# D: Specifies that files older than a specified age should be removed.
# /var/log/my_logs/*.log: Path to the files (wildcards are allowed).
# - - - 7d: No specific permissions or owner; files older than 7 days will be 
# removed.
#
# Create a symbolic link:
# /etc/tmpfiles.d/create_symlink.conf
#
# Type 'L' indicates creating a symbolic link
L /var/my_symlink - /var/my_target_file
#
# Apply the changes
sudo systemd-tmpfiles --create

1.8. systemd-binfmt

#
# The systemd-binfmt service is part of the systemd suite and is responsible 
# for handling binary formats. Binary formats are the different executable 
# file formats that a system can support. 
#
#-- 1.8.1. Key Points
# - binfmt_misc in the Linux kernel allows the execution of binaries in non-
# native formats. 
#
# - Interpreters are programs that can execute binaries in specific formats. The
# systemd-binfmt service registers these interpreters with the kernel.
#
# - For binfmt_misc to work, the kernel must be compiled with support for
# CONFIG_BINFMT_MISC.
#
#-- 1.8.2. Configuration
# - The configuration files are in /etc/binfmt.d/. Each configuration file 
# defines rules for handling specific binary formats. This directory is empty
# at default Debian 12 and Ubuntu 22.04 installations.
#
# - Configuration files follow a simple key-value format. Each rule defines the
# binary format and specifies the interpreter to use.
#
# /etc/binfmt.d/my_format.conf
#
:my_format:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x3e\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/my_interpreter:OC
#
# - The last part of the configuration file specifies optional arguments for the
# interpreter. In the example, OC specifies that the interpreter should be
# called with the OC argument.
#
# Enable a binfmt rule
sudo systemctl enable binfmt@my_format.service
#
# Disable a binfmt rule
sudo systemctl disable binfmt@my_format.service
#
# Check the status of binfmt rules
systemctl status binfmt@my_format.service

1.9. systemd-modules-load

#
# systemd-modules-load is a component of the systemd suite, responsible for
# loading kernel modules at system boot. 
#
# - Runs as a service (systemd-modules-load.service) and is typically started
# automatically during system boot.
#
# - The configuration files are in /etc/modules-load.d/ directory. Files in 
# /etc/modules-load.d/ specify which kernel modules should be loaded at boot 
# time. 
#
# Syntax is simple: each line represents the name of a module to be loaded.
#
# /etc/modules-load.d/my_modules.conf
#
# Load the 'vboxdrv' module for VirtualBox
vboxdrv
#
# - In addition to using the /etc/modules-load.d/ directory, Debian and Ubuntu
# systems traditionally had an /etc/modules file where you could list modules to
# be loaded. This file is still supported, but systemd-modules-load primarily
# uses the /etc/modules-load.d/ directory.

1.10. systemd-random-seed

#
# systemd-random-seed is a component of the systemd suite responsible for
# initializing the kernel's entropy pool with random data during the system's
# startup. The entropy pool is essential for generating cryptographic keys and
# ensuring the randomness of various cryptographic operations on a Linux system.
#
# - The primary purpose of systemd-random-seed is to initialize the kernel's
# entropy pool during the early boot phase. 
#
# - The kernel maintains an entropy pool that serves as a source of randomness
# for cryptographic operations. Having a sufficient amount of entropy is crucial
# for the security of the system.
#
# - Reads random data from /var/lib/systemd/random-seed and uses it to seed the
# kernel's entropy pool during the system's startup. This file is typically 
# created during the shutdown process and saved to preserve the entropy across
# reboots. This allows the system
#
# - The random data used to seed the entropy pool is collected from various
# sources, including interrupt timing, keyboard and mouse events, and other
# sources of hardware and environmental noise.
#
# - The seed file is restricted to ensure its security. It is owned by root and 
#  readable only by the root user.
#
# - systemd-random-seed operates during the early stages of the boot process,
# ensuring that the kernel's entropy pool is adequately seeded before
# cryptographic services and applications that rely on random data become
# active.

1.11. systemd-remount-fs

#
# The systemd-remount-fs service is part of the systemd suite and is responsible
# for remounting the root file system with specific mount options during the
# early boot process. This service is typically involved in adjusting the mount
# options for the root file system before other services are started, ensuring
# that the file system is mounted with the desired configuration.
#
# Key aspects of systemd-remount-fs:
#
# - The mount options applied by systemd-remount-fs are defined in the systemd 
# configuration, specifically in the /etc/systemd/system.conf file.
#
# - The /etc/systemd/system.conf file contains settings for the system manager,
# and it may include parameters related to the root file system's remounting.
#
# /etc/systemd/system.conf snippet:
ini
[Manager]
#...
DefaultTimeoutStartSec=10s
DefaultTimeoutStopSec=10s
DefaultRestartSec=10s
DefaultStartLimitIntervalSec=10s
DefaultStartLimitBurst=5
DefaultLimitNOFILE=4096
DefaultLimitNPROC=4096
# Set root file system mount options
DefaultMountOptions=ro
#
# - Changing the mount options with systemd-remount-fs can impact the behavior
# of the system during boot. For example, setting the root file system to be
# mounted read-only (ro) can be useful for checking and repairing the file
# system.
#

1.12. systemd-sysctl

#
# systemd-sysctl is a component of the systemd suite that provides a way to
# configure kernel parameters at runtime on Linux systems. It is a systemd
# service responsible for applying sysctl settings during the system's boot
# process. Sysctl settings are used to configure various aspects of the Linux
# kernel, influencing its behavior and performance.
#
# - The main sysctl configuration file is /etc/sysctl.conf. It can be used to
# set global sysctl settings. However, it is recommended to use the 
# /etc/sysctl.d/ directory for custom configurations.
#
# Example sysctl configuration file
# /etc/sysctl.d/99-my-custom-settings.conf
#
# Increase the maximum number of file handles
fs.file-max=65536
#
# Enable TCP window scaling
net.ipv4.tcp_window_scaling=1
#
# Increase the maximum number of network connections
net.ipv4.ip_local_port_range=1024 65000
#     
# - After modifying sysctl configuration files, you can apply the changes
# without rebooting by using the sysctl command:
#
sudo sysctl --system
#
# - The /usr/lib/sysctl.d/ directory contains default sysctl configuration files
# provided by packages. Files in this directory should not be modified, as
# changes may be overwritten during package updates.
#

1.13. systemd-sysusers

# systemd-sysusers is a utility that is part of the systemd suite, and it is
# responsible for creating and managing system users and groups during the early
# stages of system boot. It operates based on configuration files that define
# the users and groups to be created, their attributes, and other related
# settings. This tool is often used in conjunction with other systemd components
# to ensure consistent and predictable user and group management.
#
# - Configuration files are in /usr/lib/sysusers.d/ directory. Each file contains 
# instructions for creating or
# removing system users and groups.
#
#- Configuration files can also specify users and groups that should be removed.
# This allows for cleaning up obsolete or unnecessary users and groups.
#
# - Attributes such as UID (User ID), GID (Group ID), home directory, shell, and
# user comment can be specified in the configuration files.
#
# Example configuration file
# /etc/sysusers.d/my_users.conf
#
u johndoe - John Doe:/home/johndoe:/bin/bash
g mygroup - My Group
#
# - Applying Changes:
sudo systemd-sysusers

2. Tools

#-- 2.1. systemctl
#
# systemctl is a command-line utility in Linux used to control and query the
# state of the systemd system and service manager. It is a central tool for
# managing services, viewing logs, and interacting with the initialization
# system on systems using systemd as the init system. 
#
# Check the status of a service:
systemctl status apache2
#
# Stop a service:
sudo systemctl stop apache2
#
# Start a service:
sudo systemctl start apache2
#
# Disable a service from starting on boot:
sudo systemctl disable apache2
#
# Enable a service to start on boot:
sudo systemctl enable apache2
#
# Restart a service:
sudo systemctl restart apache2
#
# Reload the configuration of a running service without restarting it:
sudo systemctl reload apache2
#
# Show a service's dependencies:
systemctl list-dependencies apache2
#
# List all loaded units (services, sockets, targets, etc.):
systemctl list-units
#
# List failed units (units that failed to start):
systemctl --failed
#
# Display detailed information about a unit, including its configuration:
systemctl show apache2
#
# Mask a unit (prevent it from being started):
sudo systemctl mask apache2
#
# Unmask a previously masked unit:
sudo systemctl unmask apache2
#
# Enter rescue mode for system maintenance:
sudo systemctl rescue
#
# Enter emergency mode for critical system recovery:
sudo systemctl emergency
#      
#-- 2.2. journalctl
# journalctl is a command-line utility that provides access to the logs
# generated by the journal facility in the systemd system and service manager.
# On Debian and Ubuntu systems, journalctl is commonly used to query and display
# messages from the journal.
#
# View the journal
sudo journalctl
#
# View the journal for a systemd unit or target
#
sudo journalctl -u apache2.service
#
# Filtering by time. 
# Show logs from the last 30 minutes
sudo journalctl --since "30 minutes ago"
#
# Show logs from a specific date and time range
sudo journalctl --since "2024-01-01 08:00:00" --until "2024-01-01 12:00:00"
#
# See live journal (Ctrl-C to quit)
sudo journalctl -f
#
# Display logs for the current boot
sudo journalctl --boot
#
# View kernel messages
sudo journalctl -k
#
# Export journal entries to a file
sudo journalctl > journal.log
#
# Change output format to Json
sudo journalctl -o json
#
# Filter by priority (e.g., emerg, alert, crit, err, warning, notice, info, 
# debug).
#
sudo journalctl -p err
#
# View logs for a specific Process ID
sudo journalctl _PID=1234
#
# Clear the journal
sudo journalctl --vacuum-size=50M
#
# - The size of the journal can be managed through the SystemMaxUse and
# RuntimeMaxUse options in the /etc/systemd/journald.conf configuration file.
#
#-- 2.3. systemd-analyze
# The systemd-analyze command is part of the systemd suite, and it is used to
# analyze and display information about the system's boot and initialization
# process. It provides insights into how long the system took to boot, the time
# spent by individual services, and other related information.
#
# Basic Boot Time Information
systemd-analyze
#
# Display the chain of units that took the most time during boot.
systemd-analyze critical-chain
#
# Show the time taken by each service during boot, sorted by the time taken.
systemd-analyze blame
#
# Generate a SVG plot of the time spent by each unit during boot.
systemd-analyze plot > plot.svg
#
# Display security-relevant information about the system's boot.
systemd-analyze security
#
# Create a detailed graphical representation of time usage for different units.
systemd-analyze plot > plot.svg
#
#-- 2.4. hostnamectl
# The hostnamectl command is part of the systemd suite and is used for querying
# and changing the system hostname and related settings on Linux systems. It
# provides a convenient way to manage the system's hostname and view additional
# information about the system.
#
# Display information about the system's hostname and related settings
hostnamectl
#
# This command provides information such as the static hostname, transient
# hostname, icon name, chassis type, and more.
#
# Set the static hostname (the system's fully qualified domain name)
sudo hostnamectl set-hostname your-new-hostname
#
# Set the transient hostname. The transient hostname is a runtime hostname
# that is set temporarily and may not persist after a reboot.
sudo hostnamectl set-hostname --transient your-temporary-hostname
#
# Set the pretty hostname. The pretty hostname is a free-form UTF-8 encoded
# string describing the host.
sudo hostnamectl set-hostname --pretty "Your Pretty Hostname"
#
# Check hostname status.
hostnamectl status
#
#-- 2.5. loginctl
# The loginctl command is a part of the systemd suite and is used for
# introspecting and interacting with the state of the systemd login manager. 
# It provides information about user sessions, seats, and the status of the 
# user manager. Here are some common uses of the loginctl command:
#
# Display a list of current user sessions
loginctl list-sessions
#
# Display a list of seats
loginctl list-seats
#
# Displaying session properties
loginctl show-session SESSION_ID
#
# Displaying seat properties
loginctl show-seat SEAT_NAME
#
# Show information about the user manager
loginctl show-user USER_NAME
#
# Display a list of processes associated with a specific session:
loginctl session-status SESSION_ID
#
# Terminate a specific user session:
loginctl terminate-session SESSION_ID
#
# Display a list of user session IDs:
loginctl list-users
#
#-- 2.6. localectl
# localectl is a command-line utility in the systemd suite that allows you to
# query and change system locale and keyboard layout settings on Linux systems.
# It provides a convenient way to manage and inspect the system's locale-related
# configurations.
#
# Show the current system locale settings.
localectl
#
# Show a list of available locales that can be set on the system.
localectl list-locales
#
# Set the system locale.
sudo localectl set-locale LANG=en_US.UTF-8
#
# Display a concise status summary, including locale and keyboard layout 
# information.
localectl status
# 
#-- 2.7. systemd-ask-password
# The systemd-ask-password command is part of the systemd suite and is used
# for querying the user for authentication-related information, such as
# passwords or passphrases, in a secure and standardized way. It is often used
# in conjunction with various systemd services or components that may need to
# request passwords during the system boot process or at runtime.
#
# Some key aspects of systemd-ask-password:
#
# - Usage: The command is typically used by other systemd components or services
# to request passwords interactively.
#
# - Invocation: systemd-ask-password is usually invoked by other systemd
# components or services and may not be used directly by users from the command
# line.
#
# - Systemd Components Using systemd-ask-password: Components like 
# systemd-cryptsetup, which handles encrypted disk volumes, or services
# requiring authentication during boot, may use systemd-ask-password to prompt
# the user for passwords in a secure manner.
#
# - Modes: systemd-ask-password supports different modes of operation, such as
# prompting the user on the console, querying a password agent, or sending the
# password request to a wall message.
#
# - Password Agents: In some cases, systemd-ask-password may communicate with a
# password agent, such as systemd-tty-ask-password-agent, to handle password
# requests. This allows for a more flexible and secure way of handling
# passwords, especially in non-interactive or headless environments.
#
# - Communication: Communication between systemd-ask-password and password
# agents is done through file descriptors, ensuring a secure and reliable means
# of passing sensitive information.
#
# - Security: systemd-ask-password is designed to handle password prompts
# securely, ensuring that passwords are not inadvertently leaked or exposed
# during the authentication process.
#
# Wall Message: The --wall option can be used to send a wall message (broadcast
# message to all users) requesting a password.
systemd-ask-password --wall "Please enter the encryption password:"
#   
# This might be used by services like disk decryption to inform users about the
# need for a password.
#
# - Integration with Other Tools: systemd-ask-password is often part of a larger
# workflow involving other systemd tools and services, especially those related
# to system initialization, encryption, or authentication.
# 
# - Examples of Use:
# Password requests during disk decryption.
# Password requests for encrypted home directories.
# Authentication requests for services during runtime.
#
#-- 2.8. systemd-cat
# systemd-cat is a command-line utility that is part of the systemd suite. Its
# primary purpose is to concatenate and print messages to the journal, which is
# managed by systemd-journald. The journal is a central component of systemd
# that collects and stores log messages from various sources, making it a
# centralized and structured logging system.
#
# Can be used as a prefix to other commands or scripts to capture their output
# and send it to the journal.
systemd-cat echo "Hello, systemd!"
#   
# Redirect the standard output and standard error of a command or script to the
# journal.
systemd-cat -p info ls /etc
#   
# Set message priority. The priority levels include "emerg," "alert," "crit,"
# "err," "warning," "notice," "info," and "debug."
systemd-cat -p err echo "An error occurred."
#   
# Logging from ccripts
echo "Script is running." | systemd-cat
#   
# you can use journalctl to retrieve and filter these messages.
journalctl _SYSTEMD_UNIT=echo.service
#
#-- 2.9. systemd-cgls
# The systemd-cgls command is a utility in the systemd suite used for listing
# and displaying the hierarchy of control groups (cgroups) on a Linux system.
# Control groups are a feature of the Linux kernel that enables the organization
# and management of processes into hierarchical groups with resource constraints
# and accounting.
#
# - systemd-cgls is primarily used to visualize the hierarchy of control groups
# and their relationships. It provides a tree-like representation of the cgroup
# hierarchy.
systemd-cgls
#
# - The output of systemd-cgls shows the control groups arranged in a tree
# structure, indicating the parent-child relationships. Each line represents a
# cgroup, and indentation indicates the hierarchy.
#
# Example simplified output:
 └─user.slice
   ├─user-1000.slice
   │ ├─session-c1.scope
   │ │ └─1337 sshd: johndoe@pts/0
   │ └─session-c2.scope
   │   ├─1445 bash
   │   ├─1452 systemd-cgls
   │   └─1453 less
   └─user-2000.slice
 └─session-c3.scope
   └─1555 sshd: janedoe@pts/1
#
#-- 2.10. systemd-cgtop
# systemd-cgtop is a tool that provides a real-time, dynamic view of the
# resource usage of systemd control groups (cgroups) on a Linux system. It is
# part of the systemd suite and allows users to monitor the resource consumption
# of different units, services, and slices managed by systemd.
#
# Run `systemd-cgtop` with default settings:
sudo systemd-cgtop
#
# This will display real-time statistics for all control groups.
#
# Quits displaying after 5 updates.
sudo systemd-cgtop -n 5
#
# Display tree view
sudo systemd-cgtop -t
#
#-- 2.11. systemd-delta
# The systemd-delta command is part of the systemd suite and is used to display
# the differences between configuration files provided by different packages and
# the runtime configuration of the system. It helps identify changes made to the
# default systemd configuration by administrators or other packages on the
# system.
#
# When you run systemd-delta, it scans the system's configuration directories
# and compares the shipped configuration files from packages with the runtime
# configuration on the system. It then displays the differences.
#
# systemd-delta scans several directories for configuration files, including 
# /etc/systemd/, /run/systemd/, and /usr/lib/systemd/.
#
# Changes made by administrators are marked with +/ (additions) or !
# (modifications). 
# Changes made by packages are marked with +/ (additions) or -/ (deletions).
#
# List all changes made to systemd unit files and configuration files:
sudo systemd-delta
# 
# Display changes in a specific directory (e.g., `/etc/systemd/system/`):
sudo systemd-delta /etc/systemd/system/
#
#-- 2.12. systemd-detect-virt
# The `systemd-detect-virt` command is a part of the systemd suite, and it is
# used to detect the type of virtualization technology or hypervisor that a
# Linux system is currently running on. This can be useful in scripts or system
# initialization routines where the behavior might need to be adjusted based on
# whether the system is running on physical hardware or within a virtualized
# environment.
#
# The command is typically used in shell scripts or systemd service files to
# conditionally execute specific actions based on the detected virtualization
# type.
systemd-detect-virt
#
# The command outputs the detected virtualization type or "none" if no 
# virtualization is detected.
#
# qemu       : QEMU or KVM
# kvm        : KVM (Kernel-based Virtual Machine)
# vmware     : VMware
# oracle     : Oracle VM VirtualBox
# microsoft  : Microsoft Hyper-V
# xen        : Xen
# bochs      : Bochs
# uml        : User-Mode Linux
# parallels  : Parallels
#
# Using systemd-detect-virt in a script
if [ "$(systemd-detect-virt)" = "qemu" ]; then
  echo "Running on QEMU/KVM"
else
  echo "Not running on QEMU/KVM"
fi
# 
# Exit Codes:
# 0: Detected virtualization. The detected virtualization type will be printed
# to stdout.
# 1: No virtualization detected.
# 2: Invalid or missing arguments.
#
#-- 2.13. systemd-escape
# The systemd-escape command is a utility that comes with the systemd suite.
# It is used to escape strings, making them suitable for use as filenames, unit
# names, or other identifiers in the systemd ecosystem. This is particularly
# useful for generating valid and safe names for systemd units, files, and other
# resources.
#
# Escapes special characters in the input string, replacing them with safe
# alternatives. For example, slashes ("/") might be replaced with dashes ("-").
#
systemd-escape "My Service"
#   
# Output:
My\x20Service
#
#-- 2.14. systemd-inhibit
# The systemd-inhibit command is a part of the systemd suite, and it is used to
# inhibit the system from certain actions or events for the duration of a
# specified command or until the command exits. This is useful for preventing
# actions that might interfere with a running operation or task. The command is
# commonly employed to avoid disruptions during critical processes like software
# installations, backups, or presentations.
#
# - Command Syntax: The basic syntax for systemd-inhibit is as follows:
systemd-inhibit [OPTIONS] COMMAND
#     
# - Options: Various options can be used to specify the actions to be inhibited
# and other properties. Some common options include:
# --what=EVENT: Specifies the event to inhibit (e.g., sleep, shutdown).
# --why=REASON: Provides a human-readable reason for the inhibition.
# --mode=MODE: Specifies the inhibition mode (e.g., block, delay, fail).
#
# - Example Usage:
# Inhibit shutdown while a backup operation is in progress:
sudo systemd-inhibit --what=shutdown --why="Backup in progress" \
    my_backup_script.sh
#
# Inhibit sleep while a presentation is running:
sudo  systemd-inhibit --what=sleep --why="Presentation in progress" \
    my_pres_command
#     
# - Inhibition Modes:
# block: Blocks the action until the command exits.
# delay: Delays the action until the command exits.
# fail: Fails the command if the action cannot be inhibited.
#
# - Listing Current Inhibitions: You can use the --list option to display the
# currently active inhibitions.
systemd-inhibit --list
#     
#-- 2.15. systemd-machine-id-setup
# systemd-machine-id-setup is a command-line tool in the systemd suite used to
# initialize or regenerate the machine ID on a Linux system. The machine ID is a
# unique identifier associated with a specific installation of an operating
# system. It is often used by various system components and applications to
# distinguish between different systems.
#
# - The machine ID is stored in the /etc/machine-id file. It is a 32-character
# hexadecimal string that uniquely identifies the system. Applications and
# services often use the machine ID for various purposes, such as generating
# unique identifiers or ensuring system-specific configurations.
#
# - During the first boot of a Linux system, systemd-machine-id-setup is
# typically called to generate a random machine ID and store it in 
# /etc/machine-id.
#
# - If, for any reason, the machine ID needs to be regenerated (for example, in
# the case of system cloning or copying an installation), administrators can run
# systemd-machine-id-setup to create a new machine ID.
sudo systemd-machine-id-setup
#
# This command generates a new machine ID and updates the /etc/machine-id file.
#
# - In scenarios where system images are cloned or deployed to multiple
# machines, it's essential to regenerate the machine ID on each cloned system
# using systemd-machine-id-setup to ensure uniqueness.
#
# - While systemd-machine-id-setup is the recommended way to manage the machine
# ID, the /etc/machine-id file can also be edited manually. However, it's
# generally advised to use the provided tools to avoid potential issues.
#
#-- 2.16. systemd-mount
# systemd-mount is a command-line tool that is part of the systemd suite, and it
# is used for mounting and unmounting file systems. It provides a convenient
# interface to mount and manage various types of filesystems and network shares.
# The utility is designed to work with systemd's broader system and service
# management capabilities.
#
# Can be used to mount network file systems like NFS or SMB.
sudo systemd-mount -t nfs server:/export /mnt/nfs
#   
# - To unmount a filesystem, use the --umount option.
sudo systemd-mount --umount /mnt/data
#
# - Mounts managed by systemd-mount are often associated with systemd mount
# units, providing additional control and configuration options.
#
#-- 2.17. systemd-notify
# systemd-notify is a command-line utility provided by the systemd init system. 
# It allows a service or script to notify systemd about its status and readiness.
# This tool is often used by long-running services to signal when they have
# completed initialization or specific milestones. It's a way for services to
# communicate with systemd and integrate with the overall service management
# infrastructure.
#
# When a service uses systemd-notify, it sends signals to systemd, allowing
# systemd to track the service's progress and readiness. This information is
# valuable for systemd's dependency tracking and ordering of services during
# startup.
#
# Example in a Service Unit:
[Service]
Type=simple
ExecStart=/path/to/myservice
ExecStartPost=/bin/systemd-notify --ready
#
# In this example, myservice is expected to call systemd-notify --ready after it
# has completed its initialization.
#
#-- 2.18. systemd-path
#
# The systemd-path command is a part of the systemd suite, and it provides a 
# way to query various system and user paths managed by systemd. It allows you
# to retrieve information about directories, files, and other paths that systemd
# uses or manages. This command is typically used for scripting or querying
# system information in a consistent manner.
#
# Print the system and users path 
systemd-path 
#
#-- 2.19. systemd-run
# systemd-run is a systemd command-line tool that allows users to run transient
# systemd services and service units. It provides a simple way to create and
# manage temporary or one-shot services without the need to write custom unit
# files. This can be useful for testing, ad-hoc tasks, or running short-lived
# processes.
#
# Unlike traditional systemd services, using systemd-run does not require 
# writing and managing unit files. Instead, the user provides the command to 
# be executed directly on the command line.
#
# Transient units created by systemd-run are isolated from the calling terminal,
# and they run in their own scope. This helps prevent interference with other
# services or processes.
#
# Transient services created by systemd-run can be of different types, such as
# simple services (--service-type=simple), forking services 
# (--service-type=forking), or executed directly (--service-type=exec).
#
# Once the transient service completes, systemd-run provides information about
# the service's exit status, runtime, and resource usage.
#
# Transient services created by systemd-run are automatically cleaned up once
# the service completes, making it suitable for short-lived tasks.
#
# Execute the `echo` command within a transient service.
sudo systemd-run echo "Hello, systemd-run!"
#
# This example uses the `--pipe` option to capture the output, and `--collect`
# to ensure that the transient service's logs are collected and stored.
sudo systemd-run --pipe --collect echo "Capturing output in journal logs"
sudo journalctl -b -u transient-*.scope
#
# This example sets a CPU time quota of 50% and a memory limit of 100 megabytes
# for the transient service.
sudo systemd-run --unit=my-service --service-type=exec --property=CPUQuota=50% \
   --property=MemoryLimit=100M -- /path/to/executable
#
# Run a command as a specific user:
sudo systemd-run --uid=username --gid=groupname command-to-be-executed
#
# This example uses `--scope` to create a transient service in the background
# and runs the `sleep` command for 300 seconds.
sudo systemd-run --scope --unit=my-background-service sleep 300
#
# 
#-- 2.20. systemd-socket-activate
# systemd-socket-activate is a utility within the systemd suite that facilitates
# socket-based activation for services. Socket activation is a mechanism that
# allows services to be started on-demand when a connection is made to a
# specific network socket. This approach helps improve system efficiency by
# delaying the initialization of services until they are actually needed.
#
# Socket activation is an alternative to the traditional method of starting
# services at boot time. Instead of having services running continuously in the
# background, services are started dynamically when a connection is made to a
# specific socket.
#
# In systemd, a socket unit is defined to represent a network socket. When a
# connection is made to this socket, systemd activates the associated service.
#
#-- 2.21. systemd-stdio-bridge
# systemd-stdio-bridge is a utility provided by the systemd suite, designed to 
# act as a bridge between standard input/output streams and a client-server
# architecture. It facilitates communication between a traditional (non-systemd)
# daemon that expects input/output on standard input/output and a systemd
# service that runs in a separate process.
#
# systemd-stdio-bridge is used to adapt daemons that are not originally designed
# to work with systemd socket activation. It allows these daemons to be 
# socket-activated by systemd.
#
# When a daemon is adapted to use systemd-stdio-bridge, systemd creates a socket
# for the daemon and starts systemd-stdio-bridge as a separate process. The
# bridge connects the standard input/output of the daemon to the socket,
# allowing it to communicate with clients through the socket.




LAPP On Debian/Ubuntu

LappOnDebianUbuntu: LAPP Stack On Debian and Ubuntu

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

Specs

# L: Debian 12/11 or Ubuntu 22.04/20.04 LTS Server
# A: Apache 2 
# P: Postgresql
# P: PHP (Python or Perl could be other options)
#
# Sources:
https://stackoverflow.com/questions/49157928/how-to-fetch-data-from-postgresql-using-php

1. Install Packages

#-- 1.0. Update Repositories
sudo apt update
#
#-- 1.1. Install Apache
sudo apt install --yes apache2
#
#-- 1.2. Install Postgres
sudo apt install --yes postgresql
#
#
#-- 1.4. Install PHP, Postgres and Apache dependencies
sudo apt install --yes php libapache2-mod-php php-pgsql
#
#-- 1.5. Install other PHP dependencies 
# Depending on the PHP code, you may need some more PHP library packages.
# For example, WordPress needs the following packages:
sudo apt install --yes php-curl php-gd php-mbstring php-xml php-xmlrpc \
     php-soap php-intl php-zip
#
#-- 1.6. Restart Apache
sudo systemctl restart apache2

2. Test LAPP Stack

# - We'll create a test database, a table in that database, add some rows to the 
# table on Postgres. We will also create a test PHP file with the PHP code to 
# retrieve the data from the database and display it as HTML. 
#
#-- 2.1. DB Operations
# Create a test Postgres user
# Give its password too
sudo -u postgres createuser --pwprompt testuser
#
# Create a test Database
sudo -u postgres createdb testdb
#
# Connect to Postgres shell
sudo -u postgres psql testdb
# - Create a table, fill the table, give test user access permission to that 
# database and the table.
# !!! BEGIN Run on Postgres shell. !!!
CREATE TABLE Employees (Name char(15), Age int, Occupation char(15));
INSERT INTO Employees VALUES ('Joe Smith', '26', 'Ninja');
INSERT INTO Employees VALUES ('John Doe', '33', 'Sleeper');
INSERT INTO Employees VALUES ('Postgres Server', '14', 'RDBM');
GRANT SELECT ON ALL TABLES IN SCHEMA public to testuser;
exit
# !!! END Run on Postgres shell. !!!
# 
#-- 2.2. Create Test PHP
sudo nano /var/www/html/test.php
# Fill it as below, remember to change to your password
<?php
    $dbh = 'localhost';
    $dbn= 'testdb';
    $dbu = 'testuser';
    $dbp = 'password';
    $dbconn = pg_connect("host=$dbh dbname=$dbn user=$dbu password=$dbp")
        or die('Connection Error: ' . pg_last_error());
   $query = 'SELECT * FROM Employees';
   $result = pg_query($query) or die('Error message: ' . pg_last_error());
?>
<!DOCTYPE html>
<html>
<body>
    <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>Age</th>
                <th>Occupation</th>
            </tr>
        </thead>
        <tbody>
            <?php
               while ($row = pg_fetch_row($result)) {
            ?>
            <tr>
                <td><?php echo $row[0]; ?></td>
                <td><?php echo $row[1]; ?></td>
                <td><?php echo $row[2]; ?></td>
            </tr>
            <?php } ?>
        </tbody>
    </table>
</body>
</html>
<?php
    pg_free_result($result);
    pg_close($dbconn);
?>
#
#-- 2.3. Test it
# Now, from your workstation's browser, load the page (replace srv with your 
#    server's IP: 
#    http:/srv/test.php




Postgresql On Debian

PostgresqlOnDebian: Postgresql Tutorial On Debian

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.0. Notes
# - Debian 12 and Ubuntu 22.04 LTS Server has packages for different 
# versions of Postgresql (15 and 14). 
# - For the ease of following the tutorials, I prepared different versions 
# for Debian and Ubuntu.
#
#-- 0.1. Infrastructure
# Server:      Debian 12   IP: 192.168.1.174
# Workstation: Debian 12   IP: 192.168.1.231
#
#-- 0.2. Resources
https://www.postgresql.org/docs
https://www.postgresqltutorial.com/
ISBN: 978-1-80324-897-4 PostgreSQL 14 Administration Cookbook by Simon Riggs & Gianni Ciolli
ISBN: 978-1-83898-528-8 Learn PostgreSQL by Luca Ferrari & Enrico Pirozzi 

1. Introduction

#-- 1.1. Terminology:
# Cluster  : A PostgreSQL Instance. Can contain many databases
# Database : Accessed by allowed users. Can contain schemas (namespaces)
# Schema   : Used for organizing database objects. Can contain database 
# objects.
# Database Objects: Tables, functions, triggers, data types etc.
#
#-- 1.2. Basic Information
# 2 types of users: Normal and Superuser
# All the data and configuration information is kept in PGDATA directory.
# PostgreSQL supports information schema, but has catalog which is more 
# detailed.
# Postmaster: The first process, responsible for all the executions.
# WAL (Write Ahead Logs): Database change log, mainly used for recovering.
#
#-- 1.3. Software Components:
# PostgreSQL server  : Database server.
# PostgreSQL client  : Client tools
# PostgreSQL contrib : Extensions.
# PostgreSQL docs    : Documentation.
# PostgreSQL PL/Perl, PL/Python, and PL/Tcl: Programming interface.
# Ubuntu postgresql package installs postgresql-client by default

2. Installation and Basic Management

#-- 2.1. Installation
# Update repositories
sudo apt update
# Install necessary packages
# Debian 12 installs Postgresql version 15
sudo apt install --yes postgresql
# Check status
systemctl status postgresql
#
#-- 2.2. Cluster Management
# Debian allows running more than 1 clusters (instances) on a server.
# See the list of clusters on a server:
pg_lsclusters
# Sample output:
Ver Cluster Port Status Owner    Data directory              Log file
15  main    5432 online postgres /var/lib/postgresql/15/main /var/log/...
# - Values of Ver anf Cluster is important for us. We'll use them for 
# pg_ctlcluster command. Ours are 15 and main.
# pg_ctlcluster is a wrapper command for the original pg_ctl command of 
# postgres.
# See the status of a cluster:
sudo pg_ctlcluster 15 main status
# Start a cluster
sudo pg_ctlcluster 15 main start
# Stop a cluster
sudo pg_ctlcluster 15 main stop
# - There are 3 modes of stop: smart (wait for connections to stop), fast 
# (stop all connections), immediate (immediately). immediate option may
# cause database to crash. Default mode is fast.
sudo pg_ctlcluster 15 main stop -m smart
sudo pg_ctlcluster 15 main stop -m fast
sudo pg_ctlcluster 15 main stop -m immediate
# Restart, reload a cluster
sudo pg_ctlcluster 15 main restart
sudo pg_ctlcluster 15 main reload
#
#-- 2.3. Adding and Deleting Clusters
# - There might be more than 1 clusters on a server. At the first sight it 
# may not make sense, but for example if you need of 2 different admins for 
# 2 different databases this solution could be very useful.
# - Currently we only have main cluster. We will add a second one with the 
# name second. 
# Create another Postgres 15 cluster with the name second
sudo pg_createcluster 15 second
# Start it
sudo pg_ctlcluster 15 second start
# Create another Postgres 15 cluster with the name third and start it
sudo pg_createcluster 15 third --start
# Delete (drop) third cluster
sudo pg_dropcluster 15 third --stop
# Rename second cluster to secondary
sudo pg_renamecluster 15 second secondary
# List clusters:
pg_lsclusters
# Sample output:
Ver Cluster   Port Status Owner    Data directory                   Log file
15  main      5432 online postgres /var/lib/postgresql/15/main      /var/log/..
15  secondary 5433 online postgres /var/lib/postgresql/15/secondary /var/log/..
#
# - Here we can understand that, our 14 main cluster listens on port 5432 
# (default postgres listening port), and 14 secondary cluster listens on
# port 5433.
# - Directory of configuration files for both clusters:
# /var/lib/postgresql/14/main/ and /var/lib/postgresql/14/secondary.
#
#-- 2.4. Service vs Cluster Management
# Postgres and its clusters can be managed by systemctl command too.
# Stop postgres (all the clusters)
sudo systemctl stop postgresql
# Stop 15-main postgres cluster
sudo systemctl stop postgresql@15-main
# - Other systemctl options (like restart, stop, enable, disable, reload) 
# can be used too.
#
#-- 2.5. Login to Postgres shell
# - With the default installation; postgres linux user can login to psql 
# shell without the need of password authentication. 
sudo -u postgres psql
# Type exit to quit from postgres shell
# - As you may guess, you logged in to 14 Main cluster. To login 14 
# secondary cluster:
sudo -u postgres psql -p 5433

3. User and Connection Management

# - After installing Postgres, postgres user is able to login psql shell 
# with Linux authentication. No other users are defined and noone can login 
# remotely.
# - We will implement a scenario for user management.
#
#-- 3.0. Backup Configuration Files
cd /etc/postgresql/15/main/
sudo cp postgresql.conf postgresql.conf.backup
sudo cp pg_hba.conf pg_hba.conf.backup
# 
#-- 3.1. Scenario
# - Leave postgres user as it is (will be used as DB admin)
# - Create a database named test1
# - Create a user (role) rwuser with read and write permission at all the 
# test1 tables. Can access only from 1 IP (192.168.1.231). 
# - Create a user (role) rouser with read only permissons at all the test1 
# tables.
# Can access from a network (192.168.1.1/24).
#
#-- 3.2. Create users
# Give their passwords too
sudo -u postgres createuser --pwprompt rwuser
sudo -u postgres createuser --pwprompt rouser
#
#-- 3.3. Create test1 database and give R/W and R/O permissions. 
# Create database
sudo -u postgres createdb test1
# Create a sample table and fill it with sample data.
# Run psql to connect test1 database
sudo -u postgres psql test1
# Run on psql shell
CREATE TABLE Employees (Name char(15), Age int, Occupation char(15));
INSERT INTO Employees VALUES ('Joe Smith', '26', 'Ninja');
GRANT ALL ON ALL TABLES IN SCHEMA public to rwuser;
GRANT SELECT ON ALL TABLES IN SCHEMA public to rouser;
exit
#
#-- 3.4. Configure Postgres to allow remote connections
# Edit postgres.conf file to allow network connections
sudo nano /etc/postgresql/15/main/postgresql.conf
# Uncomment and change the line below (around line 60)
#listen_addresses = 'localhost'         # what IP address(es) to listen on;
# as below
listen_addresses = '*'                  # what IP address(es) to listen on;
#
# - Edit pg_hba.conf file to allow rwuser and rouser to allow connections 
# from specified ip/networks.
sudo nano /etc/postgresql/15/main/pg_hba.conf
# Add following lines to the file
host    test1           rwuser          192.168.1.231/32        scram-sha-256
host    test1           rouser          192.168.1.0/24          scram-sha-256
#
# Restart our cluster
sudo pg_ctlcluster restart 15 main
#
#-- 3.5. Connection test from Workstation (192.168.1.231)
# !! Run on workstation !!
# Install Postgres Client to the workstation
sudo apt update
sudo apt install postgresql-client --yes	
# 
# Connect with rwuser and test adding data (test must be successfull)
psql -h 192.168.1.174 -U rwuser test1
# Run on psql shell
INSERT INTO Employees VALUES ('John Doe', '33', 'Kedi');
exit
#
# - Connect with rouser and test reading and adding data 
# (reading test must be successfull, adding test must fail)
psql -h 192.168.1.174 -U rouser test1
# Run on psql shell
SELECT * from Employees;
INSERT INTO Employees VALUES ('Halim Selim', '41', 'Hirsiz');
exit
# - If you try to use psql from another workstation in 192.168.1.0/24 
# network, you will see that rwuser cannot connect and rouser can connect.

4. Backup and Restore

# - You can backup a database or a whole cluster. When backing up a 
# database, users (roles) and any other clusterwide data is not backed up.
# So if you backup a database and restore it on another cluster, you have to
# create users and (if necessary) access permissions there too.
#
#-- 4.0. Considerations
# - We need to use postgres user for backup and restore. When we sudo for
# this user; we need to change the directory to /tmp, because postgres user
# does not have permissions on our home directory.
#
#-- 4.1. Backup a database
# - Backing up a database is performed with pg_dump command:
#    pg_dump dbname > dumpfile
# - pg_dump command's connection parameters are like psql command's. 
# Move to /tmp directory
cd /tmp
# Backup test1 database on 15 main cluster to test1.pg file
sudo -u postgres pg_dump test1 > /tmp/test1.pg
# Backup postgres database on 15 secondary cluster to sdb.pg
#    We need to specify the port of 15 secondary cluster
sudo -u postgres pg_dump -p 5433 postgres > /tmp/sdb.pg
#
#-- 4.2. Restore a database
# You can restore a database dump with psql command:
psql dbname < dumpfile
# Restore test1 database back on 15 main cluster
sudo -u postgres psql test1 < /tmp/test1.pg
#
# Lets restore test1 db to secondary cluster
# We need an empty test1 database. 
# Create test1 database on 15 secondary
sudo -u postgres createdb -p 5433 test1
# Create users rwuser and rouser on secondary cluster. 
# createuser command's connection parameter are like psql command's too. So 
# we need to specify port number 5433 for secondary cluster.
sudo -u postgres createuser -p 5433 --pwprompt rwuser
sudo -u postgres createuser -p 5433 --pwprompt rouser
# Import the database
sudo -u postgres psql -p 5433 test1 < /tmp/test1.pg
#
#-- 4.3. Backup and Restore Whole Cluster
# - When we backup a cluster, all clusterwide data including users and 
# access rights are backed up too. But remember, you have to change the 
# configuration files by yourself.
# - Cluster dump is made by pg_dumpall command. This command too has the 
# same connection parameters as psql command. 
# Backup 15 main cluster to main.pg file
sudo -u postgres pg_dumpall > /tmp/main.pg
# Restore main.pg file to 14 secondary cluster
sudo -u postgres psql -p 5433 -f /tmp/main.pg

5. psql – PostgreSQL Shell

#-- 5.1. The Command
# - psql command is used to open a Postgres shell. At the fresh install, 
# only postgres Linux user has the right to connect to Postgres shell. So 
# we need to run it by impersonating postgres user:
sudo -u postgres psql
# - If we want another Linux user to login to psql shell, we have to create 
# them using createuser command and add connection permission to them at
# pg_hba.conf configuration file. I don't prefer that method. In my very
# humble opinion, 1 database admin is enough.
# 
#-- 5.2. The command arguments
# - psql command has a lot of arguments. If no argument is given; it tries 
# to connect with the current Linux user name as the user name and again
# current Linux user name as the database name. My Linux user name is
# exforge, so when I run psql command, I get the following error message.
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432"
failed: FATAL:  role "exforge" does not exist
# - If I go beyond and create exforge user (role actually, user=role in 
# postgres) only I have a different error message:
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  database "exforge" does not exist
# -- If I go even beyond and create a database named exforge then everything 
# goes fine.
# - Well, of course instead of creating a database with my user name, I can 
# connect to psql with specifying an existing database.
psql postgres
#
# - As we have seen before we can specify port number with -p switch, host 
# name with -h switch. We can also specify postgres user with -U switch.
# Full list of arguments can be seen with --help switch
psql --help
#
#-- 5.3. psql Commands
# - You can run SQL commands at psql shell. You can also run psql commands, 
# some of which are very useful.
# \x	Toggles expanded display
# \c	Connect to a database
# \d	List tables
# \du 	List roles (users)
# \?	psql command help

6. Bonus: Postgres 15 and Postgres 14 together

# - For testing purposes we will install Postgresql 14 on the same server. 
# That way we will have different postgres clusters with different versions.
# - Debian 12 has Postgres 15 in its repositories. For Postgres 14 we 
# need to add Postgres repositories.
#-- 6.1. Add Postgresql Repositories
# We are going to need, gpg and curl. Let's install them:
sudo apt install gpg curl --yes
# Add keys
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
    | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg
# Add repository
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt \
       $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
#
#-- 6.2. Install Postgresql 14
sudo apt update
sudo apt install postgresql-14
#
#-- 6.3. List clusters:
pg_lsclusters
# - Output will be like below, now we have 3 clusters namely 14-main, 15-
# main, and 15-secondary running on the same computer:
Ver Cluster   Port Status Owner    Data directory                   Log file
14  main      5434 online postgres /var/lib/postgresql/14/main      /var/..
15  main      5432 online postgres /var/lib/postgresql/15/main      /var/..
15  secondary 5433 online postgres /var/lib/postgresql/15/secondary /var/..
#
#-- 6.4. Connecting to the clusters with psql
# Connect to the first cluster (15-main), remember it runs on port 5432
sudo -u postgres psql -p 5432
# Connect to the second cluster (15-secondary), remember it runs on port 
# 5433
sudo -u postgres psql -p 5433
# Connect to the third cluster (14-main), remember it runs on port 5434
sudo -u postgres psql -p 5434




Postgresql On Ubuntu

PostgresqlOnUbuntu: Postgresql Tutorial On Ubuntu

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.0. Notes
# - Debian 12 and Ubuntu 22.04 LTS Server has packages for different 
# versions of Postgresql (15 and 14). 
# - For the ease of following the tutorials, I prepared different versions 
# for Debian and Ubuntu.
#
#-- 0.1. Infrastructure
# Server:      Ubuntu 22.04 LTS Server IP: 192.168.1.182
# Workstation: Ubuntu 22.04 LTS Server IP: 192.168.1.232
#
#-- 0.2. Resources
https://www.postgresql.org/docs
https://www.postgresqltutorial.com/
ISBN: 978-1-80324-897-4 PostgreSQL 14 Administration Cookbook by Simon Riggs & Gianni Ciolli
ISBN: 978-1-83898-528-8 Learn PostgreSQL by Luca Ferrari & Enrico Pirozzi 

1. Introduction

#-- 1.1. Terminology:
# Cluster  : A PostgreSQL Instance. Can contain many databases
# Database : Accessed by allowed users. Can contain schemas (namespaces)
# Schema   : Used for organizing database objects. Can contain database 
# objects.
# Database Objects: Tables, functions, triggers, data types etc.
#
#-- 1.2. Basic Information
# 2 types of users: Normal and Superuser
# All the data and configuration information is kept in PGDATA directory.
# PostgreSQL supports information schema, but has catalog which is more 
# detailed.
# Postmaster: The first process, responsible for all the executions.
# WAL (Write Ahead Logs): Database change log, mainly used for recovering.
#
#-- 1.3. Software Components:
# PostgreSQL server  : Database server.
# PostgreSQL client  : Client tools
# PostgreSQL contrib : Extensions.
# PostgreSQL docs    : Documentation.
# PostgreSQL PL/Perl, PL/Python, and PL/Tcl: Programming interface.
# Ubuntu postgresql package installs postgresql-client by default

2. Installation and Basic Management

#-- 2.1. Installation
# Update repositories
sudo apt update
# Install necessary packages
# Ubuntu 22.04 installs Postgresql version 14
sudo apt install --yes postgresql
# Check status
systemctl status postgresql
#
#-- 2.2. Cluster Management
# Ubuntu allows running more than 1 clusters (instances) on a server.
# See the list of clusters on a server:
pg_lsclusters
# Sample output:
Ver Cluster Port Status Owner    Data directory              Log file
14  main    5432 online postgres /var/lib/postgresql/14/main /var/log/...
# - Values of Ver anf Cluster is important for us. We'll use them for 
# pg_ctlcluster command. Ours are 14 and main.
# pg_ctlcluster is a wrapper command for the original pg_ctl command of 
# postgres.
# See the status of a cluster:
sudo pg_ctlcluster 14 main status
# Start a cluster
sudo pg_ctlcluster 14 main start
# Stop a cluster
sudo pg_ctlcluster 14 main stop
# - There are 3 modes of stop: smart (wait for connections to stop), fast 
# (stop all connections), immediate (immediately). immediate option may
# cause database to crash. Default mode is fast.
sudo pg_ctlcluster 14 main stop -m smart
sudo pg_ctlcluster 14 main stop -m fast
sudo pg_ctlcluster 14 main stop -m immediate
# Restart, reload a cluster
sudo pg_ctlcluster 14 main restart
sudo pg_ctlcluster 14 main reload
#
#-- 2.3. Adding and Deleting Clusters
# - There might be more than 1 clusters on a server. At the first sight it 
# may not make sense, but for example if you need of 2 different admins for 
# 2 different databases this solution could be very useful.
# - Currently we only have main cluster. We will add a second one with the 
# name second. 
# Create another Postgres 14 cluster with the name second
sudo pg_createcluster 14 second
# Start it
sudo pg_ctlcluster 14 second start
# Create another Postgres 14 cluster with the name third and start it
sudo pg_createcluster 14 third --start
# Delete (drop) third cluster
sudo pg_dropcluster 14 third --stop
# Rename second cluster to secondary
sudo pg_renamecluster 14 second secondary
# List clusters:
pg_lsclusters
# Sample output:
Ver Cluster   Port Status Owner    Data directory                   Log file
14  main      5432 online postgres /var/lib/postgresql/14/main      /var/log/...
14  secondary 5433 online postgres /var/lib/postgresql/14/secondary /var/log/...
#
# - Here we can understand that, our 14 main cluster listens on port 5432 
# (default postgres listening port), and 14 secondary cluster listens on
# port 5433.
# - Directory of configuration files for both clusters:
# /var/lib/postgresql/14/main/ and /var/lib/postgresql/14/secondary.
#
#-- 2.4. Service vs Cluster Management
# Postgres and its clusters can be managed by systemctl command too.
# Stop postgres (all the clusters)
sudo systemctl stop postgresql
# Stop 14-main postgres cluster
sudo systemctl stop postgresql@14-main
# - Other systemctl options (like restart, stop, enable, disable, reload) 
# can be used too.
#
#-- 2.5. Login to Postgres shell
# - With the default installation; postgres linux user can login to psql 
# shell without the need of password authentication. 
sudo -u postgres psql
# Type exit to quit from postgres shell
# - As you may guess, you logged in to 14 Main cluster. To login 14 
# secondary cluster:
sudo -u postgres psql -p 5433

3. User and Connection Management

# - After installing Postgres, postgres user is able to login psql shell 
# with Linux authentication. No other users are defined and noone can login 
# remotely.
# - We will implement a scenario for user management.
#
#-- 3.0. Backup Configuration Files
cd /etc/postgresql/14/main/
sudo cp postgresql.conf postgresql.conf.backup
sudo cp pg_hba.conf pg_hba.conf.backup
# 
#-- 3.1. Scenario
# - Leave postgres user as it is (will be used as DB admin)
# - Create a database named test1
# - Create a user (role) rwuser with read and write permission at all the 
# test1 tables. Can access only from 1 IP (192.168.1.232). 
# - Create a user (role) rouser with read only permissons at all the test1 
# tables.
# Can access from a network (192.168.1.1/24).
#
#-- 3.2. Create users
# Give their passwords too
sudo -u postgres createuser --pwprompt rwuser
sudo -u postgres createuser --pwprompt rouser
#
#-- 3.3. Create test1 database and give R/W and R/O permissions. 
# Create database
sudo -u postgres createdb test1
# Create a sample table and fill it with sample data.
# Run psql to connect test1 database
sudo -u postgres psql test1
# Run on psql shell
CREATE TABLE Employees (Name char(15), Age int, Occupation char(15));
INSERT INTO Employees VALUES ('Joe Smith', '26', 'Ninja');
GRANT ALL ON ALL TABLES IN SCHEMA public to rwuser;
GRANT SELECT ON ALL TABLES IN SCHEMA public to rouser;
exit
#
#-- 3.4. Configure Postgres to allow remote connections
# Edit postgres.conf file to allow network connections
sudo nano /etc/postgresql/14/main/postgresql.conf
# Uncomment and change the line below (around line 60)
#listen_addresses = 'localhost'         # what IP address(es) to listen on;
# as below
listen_addresses = '*'                  # what IP address(es) to listen on;
#
# - Edit pg_hba.conf file to allow rwuser and rouser to allow connections 
# from specified ip/networks.
sudo nano /etc/postgresql/14/main/pg_hba.conf
# Add following lines to the file
host    test1           rwuser          192.168.1.232/32        scram-sha-256
host    test1           rouser          192.168.1.0/24          scram-sha-256
#
# Restart our cluster
sudo pg_ctlcluster restart 14 main
#
#-- 3.5. Connection test from Workstation (192.168.1.232)
# !! Run on workstation !!
# Install Postgres Client to the workstation
sudo apt update
sudo apt install postgresql-client --yes	
# 
# Connect with rwuser and test adding data (test must be successfull)
psql -h 192.168.1.182 -U rwuser test1
# Run on psql shell
INSERT INTO Employees VALUES ('John Doe', '33', 'Kedi');
exit
#
# - Connect with rouser and test reading and adding data 
# (reading test must be successfull, adding test must fail)
psql -h 192.168.1.182 -U rouser test1
# Run on psql shell
SELECT * from Employees;
INSERT INTO Employees VALUES ('Halim Selim', '41', 'Hirsiz');
exit
# - If you try to use psql from another workstation in 192.168.1.0/24 
# network, you will see that rwuser cannot connect and rouser can connect.

4. Backup and Restore

# - You can backup a database or a whole cluster. When backing up a 
# database, users (roles) and any other clusterwide data is not backed up.
# So if you backup a database and restore it on another cluster, you have to
# create users and (if necessary) access permissions there too.
#
#-- 4.0. Considerations
# - We need to use postgres user for backup and restore, when we sudo for
# this user; we need to change the directory to /tmp, because postgres user
# does not have permissions on our home directory.
#
#-- 4.1. Backup a database
# - Backing up a database is performed with pg_dump command:
#    pg_dump dbname > dumpfile
# - pg_dump command's connection parameters are like psql command's. 
# Move to /tmp directory
cd /tmp
# Backup test1 database on 14 main cluster to test1.pg file
sudo -u postgres pg_dump test1 > /tmp/test1.pg
# Backup postgres database on 14 secondary cluster to sdb.pg
#    We need to specify the port of 14 secondary cluster
sudo -u postgres pg_dump -p 5433 postgres > /tmp/sdb.pg
#
#-- 4.2. Restore a database
# You can restore a database dump with psql command:
psql dbname < dumpfile
# Restore test1 database back on 14 main cluster
sudo -u postgres psql test1 < /tmp/test1.pg
#
# Lets restore test1 db to secondary cluster
# We need an empty test1 database. 
# Create test1 database on 14 secondary
sudo -u postgres createdb -p 5433 test1
# Create users rwuser and rouser on secondary cluster. 
# createuser command's connection parameter are like psql command's too. So 
# we need to specify port number 5433 for secondary cluster.
sudo -u postgres createuser -p 5433 --pwprompt rwuser
sudo -u postgres createuser -p 5433 --pwprompt rouser
# Import the database
sudo -u postgres psql -p 5433 test1 < /tmp/test1.pg
#
#-- 4.3. Backup and Restore Whole Cluster
# - When we backup a cluster, all clusterwide data including users and 
# access rights are backed up too. But remember, you have to change the 
# configuration files by yourself.
# - Cluster dump is made by pg_dumpall command. This command too has the 
# same connection parameters as psql command. 
# Backup 14 main cluster to main.pg file
sudo -u postgres pg_dumpall > /tmp/main.pg
# Restore main.pg file to 14 secondary cluster
sudo -u postgres psql -p 5433 -f /tmp/main.pg

5. psql – PostgreSQL Shell

#-- 5.1. The Command
# - psql command is used to open a Postgres shell. At the fresh install, 
# only postgres Linux user has the right to connect to Postgres shell. So 
# we need to run it by impersonating postgres user:
sudo -u postgres psql
# - If we want another Linux user to login to psql shell, we have to create 
# them using createuser command and add connection permission to them at
# pg_hba.conf configuration file. I don't prefer that method. In my very
# humble opinion, 1 database admin is enough.
# 
#-- 5.2. The command arguments
# - psql command has a lot of arguments. If no argument is given; it tries 
# to connect with the current Linux user name as the user name and again
# current Linux user name as the database name. My Linux user name is
# exforge, so when I run psql command, I get the following error message.
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432"
failed: FATAL:  role "exforge" does not exist
# - If I go beyond and create exforge user (role actually, user=role in 
# postgres) only I have a different error message:
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: FATAL:  database "exforge" does not exist
# -- If I go even beyond and create a database named exforge then everything 
# goes fine.
# - Well, of course instead of creating a database with my user name, I can 
# connect to psql with specifying an existing database.
psql postgres
#
# - As we have seen before we can specify port number with -p switch, host 
# name with -h switch. We can also specify postgres user with -U switch.
# Full list of arguments can be seen with --help switch
psql --help
#
#-- 5.3. psql Commands
# - You can run SQL commands at psql shell. You can also run psql commands, 
# some of which are very useful.
# \x	Toggles expanded display
# \c	Connect to a database
# \d	List tables
# \du 	List roles (users)
# \?	psql command help

6. Bonus: Postgres 14 and Postgres 15 together

# - For testing purposes we will install Postgresql 15 on the same server. 
# That way we will have different postgres clusters with different versions.
# - Ubuntu 22.04 has Postgres 14 in its repositories. For Postgres 15 we 
# need to add a PPA.
#-- 6.1. Add Postgresql PPA
# Add keys
curl -fSsL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
    | gpg --dearmor \
    | sudo tee /usr/share/keyrings/postgresql.gpg > /dev/null
# Add PPA
echo deb [arch=amd64,arm64,ppc64el \
    signed-by=/usr/share/keyrings/postgresql.gpg] \
    http://apt.postgresql.org/pub/repos/apt/ jammy-pgdg main \
    | sudo tee -a /etc/apt/sources.list.d/postgresql.list
#
#-- 6.2. Install Postgresql 15
sudo apt update
sudo apt install postgresql-15
#
#-- 6.3. List clusters:
pg_lsclusters
# - Output will be like below, now we have 3 clusters namely 14-main, 14-
# secondary, and 15-main running on the same computer:
Ver Cluster   Port Status Owner    Data directory                   Log file
14  main      5432 online postgres /var/lib/postgresql/14/main      /var/log/...
14  secondary 5433 online postgres /var/lib/postgresql/14/secondary /var/log/...
15  main      5433 online postgres /var/lib/postgresql/15/main      /var/log/...
#
#-- 6.4. Connecting to the clusters with psql
# Connect to the first cluster (14-main), remember it runs on port 5432
sudo -u postgres psql -p 5432
# Connect to the second cluster (14-secondary), remember it runs on port 
# 5433
sudo -u postgres psql -p 5433
# Connect to the third cluster (15-main), remember it runs on port 5434
sudo -u postgres psql -p 5434
# 
#-- 6.5. Drop Postgres 15 Main cluster
sudo pg_dropcluster 15 main
# If it is still running, a stop parameter is required
sudo pg_dropcluster --stop 15 main
#
#-- 6.6. Upgrade Cluster
# Upgrade 14 secondary cluster to Postgresql 15 
sudo pg_upgradecluster 14 secondary -v 15




UFW on Debian/Ubuntu

UFWOnDebianOnUbuntu: Basic UFW (Uncomplicated Firewall) Tutorial On Ubuntu and Debian

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

1. Firewall Architecture

#-- 1.1. Netfilter
# - Netfilter represents a set of hooks for network packets, it is 
# integrated to the
# Linux kernel. It supplies a framework for packet filtering, NAT, and port 
# translation.
# It is the first (deepest) layer for Linux firewalls.
#
#-- 1.2. Nftables and Iptables
# - Nftables, which is the successor of Iptables, is the second layer of 
# Linux firewalls. It can be considered as a generic firewall. It allows 
# defining rulesets based on network packets.
# - We can use nftables (or iptables, at the older Linux distros) to supply 
# firewall functionality, but because it is very complex; linux distros 
# supply a higher level firewall tools for easy manipulation.
#
#-- 1.3. Ufw
# Ufw is the higher level firewall program supplied by Ubuntu (Canonical).
# Other distros can supply other higher level firewalls (like firewalld and 
# firewall-cmd from Red Hat).

2. Ufw Basics

#-- 2.1. Installation
# ufw is installed and inactive by default on Ubuntu server. For Debian :
sudo apt update
sudo apt install ufw --yes
#
#-- 2.2. Status
# Check ufw status (must be inactive)
sudo ufw status
# in verbose mode:
sudo ufw status verbose
#
#-- 2.3. Enabling/Disabling
# - ufw is disabled by default. 
# - When you enable ufw, all incoming traffic is denied, and all outgoing
# traffic is allowed.
# - So if you enable it while connected with ssh it may break your 
# connection. That means you have to allow ssh before enabling it.
# Add ssh for everyone
sudo ufw allow ssh
# Now we can enable it:
sudo ufw enable
# Disable ufw
sudo ufw disable
# Clear all rules and disable ufw
sudo ufw reset
# Enable/disable logging
sudo ufw logging on
sudo ufw logging off
# 
#-- 2.4. Simple Manipulation
# Rule addition can be simple or complex
# Both following commands are basically do the same thing and enables incoming HTTP.
sudo ufw allow 80
sudo ufw allow in proto tcp from any to any port 80
#
# Remove added port 80
sudo ufw delete allow 80
# List rules as numbered
sudo ufw status numbered
# Rules can be deleted by referencing its number
sudo ufw delete 2
#
# Show added rules
sudo ufw show added
# Show in raw format
sudo ufw show raw

3. Allowing and Denying in Detail

#-- 3.1. Long Format
sudo ufw allow in on enp0s3 proto tcp from any to any port 22
# allow: could be allow or deny
# in: could be in or out, specifies incoming or outgoing traffic
# on: if we want to specify the network interface card
# enp0s3: network interface card name, used with on
# proto: if we want to specify TCP or UDP protocol 
# tcp: used with proto, could be tcp or udp
# from: used to specify from address 
# any: means all IPs, could be IP address or network too
# to: used to specify to address
# port: used to specify port number
# 22: port number, could be any port number
#
#-- 3.2. Short Forms and Some Examples
# Most of (if not all) the parameters can be omitted from the long format.
# Some examples:
# Allow/deny from an IP
sudo ufw deny from 192.168.1.11
sudo ufw allow from 192.168.1.11
#
# Allow/deny from a network
sudo ufw allow from 192.168.0.0/24
sudo ufw deny from 192.168.0.0/24
#
# Allow/deny incoming udp packets on port 53 
sudo ufw allow 53/udp
sudo ufw deny 53/udp
#
# Allow all incoming HTTP and HTTPS (TCP)
sudo ufw allow proto tcp from any to any port 80,443
#
# Allow from one IP to MySQL
sudo ufw allow from 192.168.1.11 to any port 3306
#
# Allow from a network to Postgres
sudo ufw allow from 192.168.1.0/24 to any port 5432
#
# Block outgoing SMTP
sudo ufw deny out 25
#
# Allow a port range
sudo ufw allow 6000:6007/tcp
sudo ufw allow 6000:6007/udp
#
# Allow incoming HTTP for an interface
sudo ufw allow in on enp0s3 to any port 80
#
#-- 3.3. Rule Order
# - Rules are processed from the top to the bottom. When an applicable rule 
# is is found, the remaining rules are skipped.
# When you add a new rule, it is added to the bottom. 
#
# Inserting a rule to the top
sudo ufw insert 1 deny from 192.168.1.0/24 to any
# We can use service name instead of a port number. ufw reads services from 
# /etc/services file.
sudo ufw allow ssh

4. Case Study 1

#-- 4.0. Specs
# - Allow SSH for 1 IP - 192.168.1.108
# - Allow MariaDB for 1 network except 1 IP - 192.168.1.0/24 - 192.168.1.231
# - Allow HTTP, HTTPS for everyone 
# - Deny outgoing SMTP - Port 25 TCP
# - Add one more IP for deny MariaDB exception  - 192.168.1.232
#
#-- 4.1. Always Add SSH First 
# Allow incoming SSH (Port 22/TCP) from 192.168.1.108
sudo ufw allow in proto tcp from 192.168.1.108 to any port 22
# Enable ufw
sudo ufw enable
# Now we enabled our firewall, it only allows ssh, we're going to add the 
# other rules.
#
#-- 4.2. Add Mariadb Rules
# Add MariaDB deny exception, it has to be before MariaDB allowing
sudo ufw deny in proto tcp from 192.168.1.231 to any port 3306
# Add Mariadb allow network
sudo ufw allow in proto tcp from 192.168.1.0/24 to any port 3306
#
#-- 4.3. Add HTTP(S) Rules
# Add allow HTTP and HTTPS
sudo ufw allow in proto tcp from any to any port 80
sudo ufw allow in proto tcp from any to any port 443
#
#-- 4.4. Outgoing SMTP
# Deny outgoing SMTP
sudo ufw deny out proto tcp from any to any port 25
#
#-- 4.5. Additional Mariadb Exception
# Add one more deny exception for Mariadb
# Before going on let's see our rules
sudo ufw status numbered
Status: active
     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    192.168.1.108             
[ 2] 3306/tcp                   DENY IN     192.168.1.231             
[ 3] 3306/tcp                   ALLOW IN    192.168.1.0/24            
[ 4] 80/tcp                     ALLOW IN    Anywhere                  
[ 5] 443/tcp                    ALLOW IN    Anywhere                  
[ 6] 25/tcp                     DENY OUT    Anywhere                   (out)
[ 7] 80/tcp (v6)                ALLOW IN    Anywhere (v6)             
[ 8] 443/tcp (v6)               ALLOW IN    Anywhere (v6)             
[ 9] 25/tcp (v6)                DENY OUT    Anywhere (v6)              (out)
#
#
# - As you can see, rules are added to the end as you add them. First come 
# the TCP/IP version 4 rules, then come the version 6 rules.
# If we add another rule with the following command, rule list will be like 
# the following:
sudo ufw deny in proto tcp from 192.168.1.232 to any port 3306
Status: active
     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    192.168.1.108             
[ 2] 3306/tcp                   DENY IN     192.168.1.231             
[ 3] 3306/tcp                   ALLOW IN    192.168.1.0/24            
[ 4] 80/tcp                     ALLOW IN    Anywhere                  
[ 5] 443/tcp                    ALLOW IN    Anywhere                  
[ 6] 25/tcp                     DENY OUT    Anywhere                   (out)
[ 7] 3306/tcp                   DENY IN     192.168.1.232             
[ 8] 80/tcp (v6)                ALLOW IN    Anywhere (v6)             
[ 9] 443/tcp (v6)               ALLOW IN    Anywhere (v6)             
[10] 25/tcp (v6)                DENY OUT    Anywhere (v6)              (out)
#
# - Because the rules are processed in order, our new rule (number 7) will
# never be reached, because the rule number 3 will allow the connection.
# Delete our useless new rule
sudo ufw delete 7
# Now we insert our new rule to the 3rd place
sudo ufw insert 3 deny in proto tcp from 192.168.1.232 to any port 3306
# Now our new rule is at the right place:
sudo ufw status numbered
Status: active
     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    192.168.1.108             
[ 2] 3306/tcp                   DENY IN     192.168.1.231             
[ 3] 3306/tcp                   DENY IN     192.168.1.232             
[ 4] 3306/tcp                   ALLOW IN    192.168.1.0/24            
[ 5] 80/tcp                     ALLOW IN    Anywhere                  
[ 6] 443/tcp                    ALLOW IN    Anywhere                  
[ 7] 25/tcp                     DENY OUT    Anywhere                   (out)
[ 8] 80/tcp (v6)                ALLOW IN    Anywhere (v6)             
[ 9] 443/tcp (v6)               ALLOW IN    Anywhere (v6)             
[10] 25/tcp (v6)                DENY OUT    Anywhere (v6)              (out)

5. Case Study 2

#-- 5.0. Specs
# - Two network interfaces - enp0s3 and enp0s8
# - Allow SSH for 1 IP on interface 1 - port 22/TCP 192.168.1.108
# - Allow SSH for all on interface 2 - port 22
# - Allow HTTP, HTTPS for all on interface 1 - ports 80 and 443/TCP
# 
#-- 5.1. First SSH Rule
# Allow SSH for 1 IP for the 1st network interface enp0s3
sudo ufw allow in on enp0s3 proto tcp from 192.168.1.108 to any port 22
# Enable ufw
sudo ufw enable
#
#-- 5.2. Second SSH Rule
# Allow SSH for all for the 2nd network interface enp0s8
sudo ufw allow in on enp0s8 proto tcp from any to any port 22
#
#-- 5.3. HTTP(S) Rules
# Allow HTTP and HTTPS for all for the 1st network interface enp0s3
sudo ufw allow in on enp0s3 proto tcp from any to any port 80
sudo ufw allow in on enp0s3 proto tcp from any to any port 443
#
# See the rules
sudo ufw status numbered
Status: active
     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp on enp0s3           ALLOW IN    192.168.1.108             
[ 2] 22/tcp on enp0s8           ALLOW IN    Anywhere                  
[ 3] 80/tcp on enp0s3           ALLOW IN    Anywhere                  
[ 4] 443/tcp on enp0s3          ALLOW IN    Anywhere                  
[ 5] 22/tcp (v6) on enp0s8      ALLOW IN    Anywhere (v6)             
[ 6] 80/tcp (v6) on enp0s3      ALLOW IN    Anywhere (v6)             
[ 7] 443/tcp (v6) on enp0s3     ALLOW IN    Anywhere (v6)                 




.deb Packaging On Debian/Ubuntu

DebPackagingOnDebianUbuntu: Creating and Using .deb Packages On Debian and Ubuntu

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.0. Abstract
# - This tutorial deals with creating a .deb package. A .deb package is a 
# compressed collection of files for installing a software. Mainly used by
# Debian GNU/Linux and Ubuntu. As a Debian or Ubuntu user, we normally use
# apt command to install programs (or services), but in the background .deb
# files are used.
# - Our aim is to create and use a .deb package. Creating a new Debian 
# package is another thing, actually a superset of this operation. It is a 
# subject of another tutorial.
# - This tutorial is a simple one, it does not cover every details. Its aim 
# is to help you create a simple package.
#
#-- 0.1. Configuration
# - Workstation: Debian 12 or Ubuntu 22.04 LTS
# - Test Servers: Ubuntu 22.04 LTS, Ubuntu 20.04 LTS, Ubuntu 18.04 LTS, 
# Debian 9, Debian 10, Debian 11, Debian 12
#
#-- 0.2. Sources
https://www.debian.org/doc/debian-policy/
https://www.debian.org/doc/manuals/maint-guide/dother.en.html
https://tldp.org/HOWTO/html_single/Debian-Binary-Package-Building-HOWTO/
https://github.com/rsm-gh/build-deb/blob/master/DEBIAN_BASICS.md

1. Basic Information

#-- 1.1. Package Types:
# - .deb packages may be source or binary packages. As their names imply, 
# they contain source or executable binaries (or scripts). 
# - As Debian Policy Manual states; A Debian source package contains the 
# source material used to construct one or more binary packages. 
# - At this tutorial, we are going to concentrate on binary packages.
# 
#-- 1.2. Package Structure
# - A .deb package has the following naming format and contains 3 files.
# packagename_version-revision_architecture.deb
# apache2_2.4.52-1debian4.4_amd64.deb
# 
# 1.2.1. debian-binary
# .deb package version information. Mostly just contains 2.0.
#
# 1.2.2. data.tar.zst
# An archive of compressed files in directories. When the .deb file is
# installed, the files will be copied to the directories where they are.
# The extension may be a different one if another compression type is used.
#
# 1.2.3. control.tar.zst
# An archive of compressed files. The extension may be a different one if 
# another compression type is used. The most used files are:
# - control: Metadata for the package, like package name, version, etc.
# - conffiles: A list of configuration files. These files are not 
# overwritten when the package is upgraded. 
# - preinst: Scripts to run before unpacking the package, like stopping the 
# services before upgrading.
# - postinst: Scripts to run after unpacking the package, like starting the 
# installed services.
# - prerm: Scripts to run before removing the package, like stopping the 
# services.
# - postrm: Scripts to run after removing the package, like removing created 
# files.
#
#-- 1.3. .deb Package Manipulation
# .deb packages can be installed with apt command too. 
# install a package:
sudo apt install ./<package>
sudo apt install ./test.deb
# remove a package:
sudo apt remove <appname>
sudo apt remove test
# purge a package:
sudo apt purge <appname>
sudo apt purge test

2. Package Control Files

# - Control files exist in control.tar.zst archive. Some of the files are 
# listed in 1.2.3. A (nearly) full list is below with brief descriptions, 
# though some important ones have detailed descriptions.
#
#-- 2.1. control
# - This file contains the values that package managers use. It has fields 
# and values for the fields.
# - Most of the fields have single line values, but some may have multi line 
# values.
# When entering multi line fields, the lines other than the first one must 
# start with a space or a tab.
# - The fields of a binary package are:
# 
# - Package : Mandatory field. Name of the package. Can contain alphanumeric 
# characters and *,- and . (period). Ex: openssh-server
# - Source : Source package name. Ex: openssh
# - Version : Mandatory field. Version number. Format is: 
# epoch:upstream_ver-debian_ver. 
# epoch can be omitted. Ex: 1:8.9p1-3
# - Section : Recommended field. Software category. For a Debian package, 
# there are many software categories like admin, database, httpd, java, etc. 
# - Priority : Recommended field. Could be one of the followings:
# required: Necessary for the proper functioning of the system. 
# important: Packages that are expected to be in every Linux system.
# standard: Packages that are installed by default. Standard packages must 
# not conflict with each other.
# optional: All others. Most of the packages fall into this category. 
# Optional packages may conflict with each other.
# - Architecture : Mandatory field. Architecture that the package is 
# prepared for. 
# Examples: amd64, arm64, i386, powerpc, sparc, all
# - Essential: If set to yes, the package management software would refuse 
# to remove this package. Normally you should set it as no, or skip this 
# field.
# - Depends: The packages that this package depends absolutely. This package 
# is not configured unless all the depended packages are configured. 
# - Pre-Depends: Not advised to use. Like Depends, but depended package 
# should be configured before unpacking the package.
# - Recommends: Declares a strong but not absolute dependancy.
# - Suggests: Declares that this package would be more useful with the 
# listed packages.
# - Enhances: Opposite of Suggests. Declares that listed packages would be 
# more useful with this package.
# - Breaks: This package breaks the listed packages. They must be 
# unconfigured before this package can be installed.
# - Conflicts: Similar but stronger than Breaks. They must be unpacked 
# before this package can be installed.
# - Installed-Size: An estimate of the total amount of disk space required 
# to install the package.
# - Maintainer : Mandatory field. Name and email of the maintainer. Ex: 
# Exforge <exforge@x386.org>
# - Description : Mandatory field. Description of the package. The first 
# line is the short description, the others are the long version. 
# - Homepage: The url of the website of the package.
# - Built-Using: The list of packages that this package depended at build 
# time, but no more.
# - Also there might be some user defined fields. Ubuntu adds a field named 
# "Original Maintainer" to keep Debian Maintainers info while giving theirs.
#
# Contents of Ubuntu 22.04 LTS' apache2 package control file:
Package: apache2
Version: 2.4.52-1ubuntu4.4
Architecture: amd64
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Installed-Size: 533
Pre-Depends: init-system-helpers (>= 1.54~)
Depends: apache2-bin (= 2.4.52-1ubuntu4.4), apache2-data (= 2.4.52-1ubuntu4.4), apache2-utils (= 2.4.52-1ubuntu4.4), lsb-base, mime-support, perl:any, procps
Recommends: ssl-cert
Suggests: apache2-doc, apache2-suexec-pristine | apache2-suexec-custom, www-browser, ufw
Conflicts: apache2.2-bin, apache2.2-common
Replaces: apache2.2-bin, apache2.2-common
Provides: httpd, httpd-cgi
Section: httpd
Priority: optional
Homepage: https://httpd.apache.org/
Description: Apache HTTP Server
 The Apache HTTP Server Project's goal is to build a secure, efficient and
 extensible HTTP server as standards-compliant open source software. The
 result has long been the number one web server on the Internet.
 .
 Installing this package results in a full installation, including the
 configuration files, init scripts and support scripts.
Original-Maintainer: Debian Apache Maintainers <debian-apache@lists.debian.org>
#
# Contents of Ubuntu 22.04 LTS' openssh package control file:
Package: openssh-server
Source: openssh
Version: 1:8.9p1-3
Architecture: amd64
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Original-Maintainer: Debian OpenSSH Maintainers <debian-ssh@lists.debian.org>
Installed-Size: 1501
Pre-Depends: init-system-helpers (>= 1.54~)
Depends: adduser (>= 3.9), dpkg (>= 1.9.0), libpam-modules (>= 0.72-9), libpam-runtime (>= 0.76-14), lsb-base (>= 4.1+Debian3), openssh-client (= 1:8.9p1-3), openssh-sftp-server, procps, ucf (>= 0.28), debconf (>= 0.5) | debconf-2.0, libaudit1 (>= 1:2.2.1), libc6 (>= 2.34), libcom-err2 (>= 1.43.9), libcrypt1 (>= 1:4.1.0), libgssapi-krb5-2 (>= 1.17), libkrb5-3 (>= 1.13~alpha1+dfsg), libpam0g (>= 0.99.7.1), libselinux1 (>= 3.1~), libssl3 (>= 3.0.1), libsystemd0, libwrap0 (>= 7.6-4~), zlib1g (>= 1:1.1.4)
Recommends: default-logind | logind | libpam-systemd, ncurses-term, xauth, ssh-import-id
Suggests: molly-guard, monkeysphere, ssh-askpass, ufw
Conflicts: sftp, ssh-socks, ssh2
Replaces: openssh-client (<< 1:7.9p1-8), ssh, ssh-krb5
Provides: ssh-server
Section: net
Priority: optional
Multi-Arch: foreign
Homepage: http://www.openssh.com/
Description: secure shell (SSH) server, for secure access from remote machines
 This is the portable version of OpenSSH, a free implementation of
 the Secure Shell protocol as specified by the IETF secsh working
 group.
 .
 Ssh (Secure Shell) is a program for logging into a remote machine
 and for executing commands on a remote machine.
 It provides secure encrypted communications between two untrusted
 hosts over an insecure network. X11 connections and arbitrary TCP/IP
 ports can also be forwarded over the secure channel.
 It can be used to provide applications with a secure communication
 channel.
 .
 This package provides the sshd server.
 .
 In some countries it may be illegal to use any encryption at all
 without a special permit.
 .
 sshd replaces the insecure rshd program, which is obsolete for most
 purposes.
#
#-- 2.2. conffiles
# - This file contains the list of configuration files of the package. The 
# files listed here will be considered as conf files. If the user has 
# changed any of the conf files listed here, she/he will be warned by the 
# system.
#
# Contents of Ubuntu 22.04 LTS' openssh package conffiles file:
/etc/default/ssh
/etc/init.d/ssh
/etc/pam.d/sshd
/etc/ssh/moduli
/etc/ufw/applications.d/openssh-server
# 
#-- 2.3. preinst
# - This is the script (or program, but script is recommended) to run before
# unpacking the package. 
# The script can be called in the following ways:
# - new-preinst install : Before the package is installed.
# - new-preinst install old-version new-version : Before a removed package 
# is upgraded.
# - new-preinst upgrade old-version new-version : Before the package is 
# upgraded.
# -  old-preinst abort-upgrade new-version : If postrm fails during upgrade 
# or fails on failed upgrade.
#
# - This script must be idempotent, that is there mustn't be any problems if 
# it runs more than 1 time. 
# This script must start with #! 
# Also this script must return 0 for success and nonzero for error 
# conditions.
# 
# An excerpt from Ubuntu 22.04 LTS' apache2 package preinst file:
case "$1" in
    upgrade|install)
	if dpkg --compare-versions "$2" lt-nl "2.4.23-3~" ; then
		list_fixup_conffiles | replace_broken_conffiles
	fi
    ;;
    abort-upgrade)
		list_fixup_conffiles | revert_broken_conffiles
    ;;
    *)
	echo "preinst called with unknown argument \`$1'" >&2
	exit 1
    ;;
esac
#
#-- 2.4. postinst
# - This is the script (or program, but script is recommended) to run after 
# unpacking the package. 
# The script can be called in the following ways:
# - postinst configure old-version: After the package was installed.
# - old-postinst abort-upgrade new-version : If prerm fails during upgrade 
# or fails on failed-upgrade.
# - old-postinst abort-remove: If prerm fails during remove.
# - postinst abort-deconfigure in-favour new-package new-version [ removing 
# old-package old-version ]: If prerm fails during deconfigure in-favour of
# a package.
# - postinst abort-remove: If prerm fails during remove in-favour for 
# replacement due to conflict.
#
# - This script must be idempotent, that is there mustn't be any problems if 
# it runs more than 1 time. 
# This script must start with #! 
# Also this script must return 0 for success and nonzero for error conditions.
# 
# Two excerpts from Ubuntu 22.04 LTS' apache2 package postinst file:
is_fresh_install()
{
	if [ -z "$2" ] ; then
		return 0
	fi
	return 1
}
#
case "$1" in
	configure)
		enable_default_mpm $@
		install_default_files $@
		enable_default_modules $@
		enable_default_conf $@
		install_default_site $@
		execute_deferred_actions
	;;
	abort-upgrade)
	;;
	abort-remove|abort-deconfigure)
	;;
	*)
		echo "postinst called with unknown argument \`$1'" >&2
		exit 1
	;;
esac
#
#-- 2.5. prerm
# - This is the script (or program, but script is recommended) to run before 
# removing the package. 
# The script can be called in the following ways:
# - prerm remove: Before the package is removed.
# - old-prerm upgrade new-version: Before an upgrade.
# - new-prerm failed-upgrade old-version new-version: If the above upgrade 
# fails.
# - prerm deconfigure in-favour new-package new-version: Before package is 
# deconfigured while dependency is replaced due to conflict.
# - prerm remove in-favour new-package new-version: Before the package is 
# replaced due to conflict.
#
# - This script must be idempotent, that is there mustn't be any problems if 
# it runs more than 1 time. 
# This script must start with #! 
# Also this script must return 0 for success and nonzero for error 
# conditions.
# 
# Contents of Ubuntu 22.04 LTS' mariadb-server package prerm file:
#!/bin/sh
set -e
# Modified dh_systemd_start snippet that's not added automatically
if [ -d /run/systemd/system ]; then
	deb-systemd-invoke stop mariadb.service >/dev/null
# Modified dh_installinit snippet to only run with sysvinit
elif [ -x "/etc/init.d/mariadb" ]; then
	invoke-rc.d mariadb stop || exit $?
fi
#
#-- 2.6. postrm
# - This is the script (or program, but script is recommended) to run after 
# removing the package. 
# The script can be called in the following ways:
# - postrm remove: After the package was removed.
# - postrm purge: After the package was purged.
# - old-postrm upgrade new-version: After the package was upgraded.
# - new-postrm failed-upgrade old-version new-version: If the above upgrade 
# call fails.
# - postrm disappear overwriter-package overwriter-version: After all of the 
# package files have been replaced.
# - new-postrm abort-install: If preinst fails during install.
# - new-postrm abort-install old-version new-version: If preinst fails 
# during install for an upgrade of a removed package.
# new-postrm abort-upgrade old-version new-version: If preinst fails during 
# upgrade.
#
# - This script must be idempotent, that is there mustn't be any problems if 
# it runs more than 1 time. 
# This script must start with #! 
# Also this script must return 0 for success and nonzero for error 
# conditions.
# 
# An excerpt of Ubuntu 22.04 LTS' openssh-server package postrm file:
if [ "$1" = "remove" ]; then
	if [ -x "/usr/bin/deb-systemd-helper" ]; then
		deb-systemd-helper mask 'ssh.service' >/dev/null || true
	fi
fi
if [ "$1" = "purge" ]; then
	if [ -x "/usr/bin/deb-systemd-helper" ]; then
		deb-systemd-helper purge 'ssh.service' >/dev/null || true
		deb-systemd-helper unmask 'ssh.service' >/dev/null || true
	fi
fi
#
#-- 2.7. config
# - config is an additional script that runs before preinst, before any 
# predependencies are satisfied. This script can be used for any information 
# that should be prompted to the user.
# Contents of Ubuntu 22.04 LTS' mariadb-server package prerm file:
#!/bin/bash
set -e
. /usr/share/debconf/confmodule
if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
# Beware that there are two ypwhich one of them needs the 2>/dev/null!
if test -n "`which ypwhich 2>/dev/null`"  &&  ypwhich >/dev/null 2>&1; then
  db_input high mariadb-server-10.6/nis_warning || true
  db_go
fi
#
#-- 2.8. templates
# This file contains templates for user prompting. 
#
# An excerpt from Ubuntu 22.04 LTS' openssh-server package templates file:
Template: openssh-server/password-authentication
Type: boolean
Default: true
Description: Allow password authentication?
 By default, the SSH server will allow authenticating using a password.
 You may want to change this if all users on this system authenticate using
 a stronger authentication method, such as public keys.
#
#-- 2.9. md5sums
# This file contains md5 hashes of files of the package.
#
# Content Ubuntu 22.04 LTS' openssh-server package md5sums file:
8ec138e332aa1fbc3f081c17e81b62f9  lib/systemd/system/rescue-ssh.target
3841c38ccbff81c6bcab65bfd307c41c  lib/systemd/system/ssh.service
3f25171928b9546beb6a67bf51694eb3  lib/systemd/system/ssh.socket
bc5513f9fb433034b2986886e1af71df  lib/systemd/system/ssh@.service
4b50d38888a7c2093ea4928dca327287  usr/lib/openssh/ssh-session-cleanup
d9f4348145691919611bc60c3212d4a8  usr/sbin/sshd
f410eed89eecfb2bcf29440141a49d4f  usr/share/apport/package-hooks/openssh-server.py
77862d01cdeb1232790155687382fdad  usr/share/doc/openssh-client/examples/ssh-session...
b3cce9472de613cc6cb967aa63a7e28f  usr/share/man/man5/moduli.5.gz
d6f0d424d86f689708da000cfd8b9c0c  usr/share/man/man5/sshd_config.5.gz
ac7abad4e73226affab0c56e47cf8b68  usr/share/man/man8/sshd.8.gz
30e0fe758429c57d35a5e71dbd8dd2f8  usr/share/openssh/sshd_config
cb02155c6c0d5678ef2e827ebb983a3d  usr/share/openssh/sshd_config.md5sum
#
#-- 2.10. triggers
# A package declares its relationship to some triggers by including a 
# triggers file.
# There are following trigger directives:
# - interest <trigger>: The package is interested in the trigger.
# - interest-await <trigger>: Puts the triggering package in awaited state.
# - interest-noawait <trigger>: Does not put the triggering package in awaited state.
# - activate <trigger>: Any change in this package activates the trigger
# - activate-await <trigger>: Only puts the package in awaited state.
# - activate-noawait <trigger>: Never puts the package in awaited state.
#
# Content Ubuntu 22.04 LTS' mariadb-server package triggers file:
interest-noawait /etc/mysql
interest-noawait /etc/systemd/system/mariadb.service.d
#
#-- 2.11. symbols and shlibs
# This files contain information about used shared libraries.
#
https://man7.org/linux/man-pages/man5/deb-symbols.5.html
https://man7.org/linux/man-pages/man5/deb-shlibs.5.html
#
# Content Ubuntu 22.04 LTS' slapd package shlibs file:
libslapi-2.5 0 libslapi-2.5-0

3. Package Data Files

#-- 3.1. Basics
# - Data files exist in data.tar.zst archive. The archive contains the files 
# in their corresponding directories. Every file in this archive is unpacked
# to its corresponding directory.
# 
# Files in Ubuntu 22.04 LTS' openssh-server package:
├── etc
│   ├── default
│   │   └── ssh
│   ├── init.d
│   │   └── ssh
│   ├── pam.d
│   │   └── sshd
│   ├── ssh
│   │   ├── moduli
│   │   └── sshd_config.d
│   └── ufw
│       └── applications.d
│           └── openssh-server
├── lib
│   └── systemd
│       └── system
│           ├── rescue-ssh.target
│           ├── ssh.service
│           ├── ssh@.service
│           └── ssh.socket
└── usr
    ├── lib
    │   └── openssh
    │       └── ssh-session-cleanup
    ├── sbin
    │   └── sshd
    └── share
        ├── apport
        │   └── package-hooks
        │       └── openssh-server.py
        ├── doc
        │   ├── openssh-client
        │   │   └── examples
        │   │       └── ssh-session-cleanup.service
        │   └── openssh-server -> openssh-client
        ├── man
        │   ├── man5
        │   │   ├── authorized_keys.5.gz -> ../man8/sshd.8.gz
        │   │   ├── moduli.5.gz
        │   │   └── sshd_config.5.gz
        │   └── man8
        │       └── sshd.8.gz
        └── openssh
            ├── sshd_config
            └── sshd_config.md5sum
#
#-- 3.2. File Locations
# - Data files consists binaries, static files, dynamic files, 
# configurations, etc. 
# Every file must be placed on an appropriate place. Some examples:
# - Architecture-independent, application-specific files --> /usr/share
# - User specific configuration files --> ~/.packagename. File or directory.
# - Configuration files --> /etc/packagename
# - Systemd unit files --> /lib/systemd/system
# - Log files --> /var/log/packagename
# - Cron jobs --> Regarding the time period, one of the following:
#     /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
#     If the time period is different: /etc/cron.d

4. Package Installation Process

#  If there is a previous version of the package:
#    Call for the old package: "old-prerm upgrade new-version"
#    If return status is not 0:
#      Call for the current package: "new-prerm failed-upgrade old-version new-version"
#      If return status is not 0:
#        Call for the old package: "old-postinst abort-upgrade new-version"
#          If return status is 0:
#            Upgrade unsuccessfull, old version works
#            Exit
#          Else:
#            Upgrade unsuccessfull, old version is broken too
#            Exit
#  If there are conflicting and/or broken packages
#    For each of these packages run:
#      # Unconfigure them
#      deconfigured's-prerm deconfigure in-favour package-being-installed version
#      If return status is not 0:
#        deconfigured's-postinst abort-deconfigure in-favour \
#            package-being-installed-but-failed version
#      # Remove them
#      conflictor's-prerm remove in-favour package new-version
#      If return status is not 0:
#        conflictor's-postinst abort-remove in-favour package new-version
#      If there are any packages that depend of the conflicting or broken packages
#        For each of these packages run:
#          # Unconfigure them
#          deconfigured's-prerm deconfigure in-favour package-being-installed \
#              version removing conflicting-package version
#          If return status is not 0:
#            deconfigured's-postinst abort-deconfigure in-favour \
#               package-being-installed-but-failed version \
#               removing conflicting-package version
#      # Prepare to remove conflicting packages
#      conflictor's-prerm remove in-favour package new-version
#      If return status is not 0:
#        conflictor's-postinst abort-remove in-favour package new-version
#
#  # Run the preinst of the new package
#  If the package is being upgraded:
#    new-preinst upgrade old-version new-version
#    If return status is not 0:
#      new-postrm abort-upgrade old-version new-version
#        If return status is 0:
#          Upgrade unsuccessfull, old version works
#          Exit
#        Else:
#          Upgrade unsuccessfull, old version is broken too
#          Exit
#  Else if the package is new but there are old conf files:
#    new-preinst install old-version new-version
#    If return status is not 0:
#      new-postrm abort-install old-version new-version
#      Install unsuccessfull
#      Exit
#  Else:    # New install with no conf files
#    new-preinst install
#    If return status is not 0:
#      new-postrm abort-install
#      Install unsuccessfull
#      Exit
#  Unpack all the files
#  # A package cannot write another package's file unless Replaces is used
#
#  If the package is being upgraded:
#    old-postrm upgrade new-version
#    If return condition is not 0:
#      new-postrm failed-upgrade old-version new-version
#      If return condition is 0:
#        Upgrade failed, old version works
#        Exit
#      Else
#        # Upgrade failed, try to cover up
#        old-preinst abort-upgrade new-version
#        If return condition is 0:
#          new-postrm abort-upgrade old-version new-version
#          If return condition is 0:
#            old-postinst abort-upgrade new-version
#            Upgrade failed, old version works
#            Exit
#          Else:
#            Upgrade failed, old version broken
#            Exit
#        Else:
#          Upgrade failed, old version broken
#          Exit
#  Files in old version but not in new version removed
#  New file list replaces the old one
#  New scripts replaces the old ones
#  For each package, whose files are overwritten and not required for dependencies:
#    # Remove them
#    disappearer's-postrm disappear overwriter overwriter-version
#    Remove package scripts
#    Update their status as "Not-Installed"
#  If Any files of the new package is also listed in the other packages:
#    Remove them
#  Remove temporary and backup files made during installation
#  Set the status of the package as "Unpacked"
#  If there were conflicting packages:
#    Remove them

5. Package Removal/Purge Process

#  prerm remove
#  If return status is not 0:
#    If failure is due to conflict:
#      conflictor's-postinst abort-remove in-favour package new-version
#    Else: 
#      postinst abort-remove
#    If return status is 0:
#      Remove aborted, package is still installed
#      Exit
#    Else:
#      Remove aborted, package is broken
#      Exit
#  Remove package files (except conffiles)    
#  Remove all scripts except postrm
#  If Purge
#    Remove conffiles and temporary and backup files made during process
#    postrm purge
#    Remove package's file list    

6. .deb Package Preparation Checklist

#-- 6.1. Create File and Folder Structure for the Package
# A minimal set would include the following:
ProgramName-Version/
ProgramName-Version/DEBIAN
ProgramName-Version/DEBIAN/control
ProgramName-Version/usr/
ProgramName-Version/usr/bin/
ProgramName-Version/usr/bin/ProgramName
#
# You may also need following files/folder:
ProgramName-Version/DEBIAN/control
ProgramName-Version/DEBIAN/preinst
ProgramName-Version/DEBIAN/postinst
ProgramName-Version/DEBIAN/prerm
ProgramName-Version/DEBIAN/postrm
ProgramName-Version/etc/
ProgramName-Version/etc/ProgramName.conf
ProgramName-Version/etc/ProgramName/
ProgramName-Version/usr/share/applications/ProgramName.desktop
ProgramName-Version/usr/share/ProgramName/ProgramFiles
#
#-- 6.2. Copy Files
# - You need to copy program executable, control file, script files and 
# other files to their appropriate locations. 
#
# - /usr/share/ProgramName/ is used if you have more than 1 files for the 
# program. 
# - You can use /etc or /etc/ProgramName folders if you have 1 or more 
# configuration files respectively. 
# - You can use /usr/share/applications/ folder for creating desktop 
# launchers.
#
#-- 6.3. Preparing and Building The Package
# When all files are ready, you have to set permissions of the executable 
# files
# 
chmod a+x ProgramName-Version/..
#
# And build the package:
dpkg-deb -Z xz --build --root-owner-group ProgramName-Version
# 
# The resulting .deb file is your package.

7. A Very Simple Package

# - Now, we are going to create a very simple package, namely "distro". Our 
# package is a python script which displays the Unix distro name and the version information.
# - The package will only have the executable script and the control file. 
# No configuration file or maintenance scripts are needed.
#
#-- 7.1. Create Folder Structure
# - We are going to create a packages folder at our home folder. All the 
# packages will reside on this folder with their own folders.
mkdir ~/packages
# Remember a package has this format for its name: 
#   packagename_version-revision_architecture.deb
mkdir ~/packages/distro_1.0.0-1_all
# /usr/bin folder to put the executable
mkdir -p ~/packages/distro_1.0.0-1_all/usr/bin
# DEBIAN folder for control file
mkdir ~/packages/distro_1.0.0-1_all/DEBIAN
#
#-- 7.2. Executable File
# Copy, or in our case, fill the executable file:
nano ~/packages/distro_1.0.0-1_all/usr/bin/distro
# Fill as below:
#!/usr/bin/env python3
def distro_version():
    d = {}
    try:
        with open("/etc/os-release") as f:
            for line in f:
                line = line.replace('"', '')
                line = line.replace('\n', '')
                if line == "":
                    continue
                (key, val) = line.split("=")
                d[(key)] = val
        distro = d["NAME"]
        version = d["VERSION_ID"]
    except:
        distro = "Other"
        version = "Other"
    return distro, version
distro, version = distro_version()
print(distro, version)
#
# make it executable
chmod +x ~/packages/distro_1.0.0-1_all/usr/bin/distro
#
#-- 7.3. control File
# Copy, or in our case, fill the control file:
nano ~/packages/distro_1.0.0-1_all/DEBIAN/control
# Fill as below:
Package: distro
Version: 1.0.0-1
Architecture: all
Maintainer: Exforge <exforge@x386.org>
Depends: python3
Homepage: https://github.com/enatsek/
Description: Prints Linux Distribution and Name
  A python script to print linux distro and version of the distro. I do not know what 
  it does on other OSs.
#
#-- 7.4. Build the package
cd ~/packages
dpkg-deb -Z xz --build --root-owner-group distro_1.0.0-1_all 
#
# Your package distro_1.0.0-1_all.deb is in your ~/packages folder.
#
# - A note: dpkg-deb normally use zst compression, but we override it with
# -Z xz flag for xz compression. Because, the packages made in Ubuntu 22.04
# with zst compression does not work on Debian distributions.

8. A Bit More Complicated Package

# - Our next package named as watchbox is a bit more complicated.
# - It is a python script too, but it is aimed to run as a service.
# - Our package must install it as a systemd service, enable and start it 
# after the installation. Also the service must be stopped before removing 
# or upgrading the package. 
# - As control files, beside the control file we will have conffiles, 
# postinst, and prerm.
# - As data files, we will have the script itself, configuration file, and 
# the service unit file.
#
#-- 8.0. About Watchbox
# - Watchbox is a service demonstration program, which allow periodic checks 
# for network connectivity for hosts, web pages, files, or services.
# - It has an application named watchbox, configuration file named 
# watchbox.conf, and a systemd service unit file named watchbox.service.
# For more details, please see:
https://github.com/enatsek/watchbox
#
#-- 8.1. Copy Watchbox Files to a Temporary Place
# Get watchbox files from github
wget https://raw.githubusercontent.com/enatsek/watchbox/main/watchbox -P /tmp
wget https://raw.githubusercontent.com/enatsek/watchbox/main/watchbox.conf -P /tmp
wget https://raw.githubusercontent.com/enatsek/watchbox/main/watchbox.service -P /tmp
#
#-- 8.1. Folder Structure
# Again we will use the folder ~/packages
~/packages/
~/packages/watchbox_0.9-1_all/
~/packages/watchbox_0.9-1_all/DEBIAN/
~/packages/watchbox_0.9-1_all/DEBIAN/control
~/packages/watchbox_0.9-1_all/DEBIAN/conffiles
~/packages/watchbox_0.9-1_all/DEBIAN/postinst
~/packages/watchbox_0.9-1_all/DEBIAN/prerm
~/packages/watchbox_0.9-1_all/etc/
~/packages/watchbox_0.9-1_all/etc/watchbox.conf
~/packages/watchbox_0.9-1_all/lib/
~/packages/watchbox_0.9-1_all/lib/systemd/
~/packages/watchbox_0.9-1_all/lib/systemd/system/
~/packages/watchbox_0.9-1_all/lib/systemd/system/watchbox.service
~/packages/watchbox_0.9-1_all/usr/
~/packages/watchbox_0.9-1_all/usr/bin/
~/packages/watchbox_0.9-1_all/usr/bin/watchbox
#
#-- 8.2. Create Folder Structure
mkdir -p ~/packages/watchbox_0.9-1_all/DEBIAN/
mkdir -p ~/packages/watchbox_0.9-1_all/etc
mkdir -p ~/packages/watchbox_0.9-1_all/lib/systemd/system/
mkdir -p ~/packages/watchbox_0.9-1_all/usr/bin/
#
#-- 8.3. Copy Watchbox Files to Their Places
cp /tmp/watchbox.conf ~/packages/watchbox_0.9-1_all/etc/
cp /tmp/watchbox.service ~/packages/watchbox_0.9-1_all/lib/systemd/system/
cp /tmp/watchbox -p ~/packages/watchbox_0.9-1_all/usr/bin/
# Make it executable too:
chmod +x ~/packages/watchbox_0.9-1_all/usr/bin/watchbox
#
#-- 8.4. Create Control Files and Maintenance Scripts
# control file (package metadata)
nano ~/packages/watchbox_0.9-1_all/DEBIAN/control
# Fill as below
Package: watchbox
Version: 0.9-1
Architecture: amd64
Maintainer: Exforge <exforge@x386.org>
Homepage: https://github.com/enatsek/watchbox/
Depends: python3, python3-systemd
Description: Automated Service Checking Tool
  WatchBox (AKA watchbox) is planned to be a Systemd service for starting at the power-up and making periodic checks.
  Currently it has 6 types of checks:
  - IPPing: Checks if an IP address or hostname can be pinged
  - IPPort: Checks if an IP address or hostname can be connected through a TCP Port
  - Webpage: Checks if a webpage exists
  - WebpageContent: Checks if a webpage has a content
  - LocalPath: Checks if a path exists
  - LocalService: Checks if a systemd service is active
  Check status results can be collected to systemd journal, text file, and/or sqlite db file.
  Configuration file watchbox.conf is expected to be in /etc directory. It is well documented inside.
  Disclaimer: This program is far from being optimized, so it is not adviced to use it on production environments.
#
# conffiles (Configuration files, stay after remove, removed at purge)
nano ~/packages/watchbox_0.9-1_all/DEBIAN/conffiles
# Fill as below
/etc/watchbox.conf
#
# postinst (script to run after installing)
nano ~/packages/watchbox_0.9-1_all/DEBIAN/postinst
# Fill as below (Enables and runs watchbox service)
systemctl enable watchbox
systemctl start watchbox
# Make it executable
chmod +x ~/packages/watchbox_0.9-1_all/DEBIAN/postinst
#
# prerm (script to run before removing and upgrading)
nano ~/packages/watchbox_0.9-1_all/DEBIAN/prerm
# Fill as below (Stops watchbox service)
systemctl stop watchbox
# Make it executable
chmod +x ~/packages/watchbox_0.9-1_all/DEBIAN/prerm
#
#-- 8.5. Build the Package
cd ~/packages
dpkg-deb -Z xz --build --root-owner-group watchbox_0.9-1_all 
#
# Your package watchbox_0.9-1_all.deb is in your ~/packages folder.




Systemd On Debian/Ubuntu

SystemdOnDebianUbuntu systemd Tutorial On Debian and Ubuntu

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.0. Intro 
# - systemd is a suite of basic building blocks for a Linux system. It 
# provides a system and service manager that runs as PID 1 and starts the 
# rest of the system (from systemd.io site).
# - systemd is a software suite that provides an array of system components 
# for Linux operating systems (from wikipedia).
# - systemd is an init system for Linux. It replaces SysV init. There are a 
# lot of distros that use it as an init system, like Debian, Ubuntu, RHEL.
# Also there are a lot of distros that don't use systemd, like Slackware,
# Devuan, Alpine, Gentoo.
# - A strong alternative of systemd is OpenRC (you may expect a tutorial for 
# OpenRC).
# 
#-- 0.1. Definitions
# - D-Bus (Desktop Bus) is a message-oriented middleware mechanism that 
# allows communication between multiple processes running concurrently on 
# the same machine (from wikipedia).
# - cgroups: A part built into kernel, that allows setting resource 
# utilization limits for processes. Like; cpu shares, memory usage, block 
# I/O per process. Developed by Google.
#
#-- 0.2. Sources
https://wiki.debian.org/systemd/documentation
https://www.digitalocean.com/community/tutorials/systemd-essentials-working-with-services-units-and-the-journal
https://www.digitalocean.com/community/tutorials/how-to-use-systemctl-to-manage-systemd-services-and-units
https://www.digitalocean.com/community/tutorials/how-to-use-journalctl-to-view-and-manipulate-systemd-logs
https://www.redhat.com/sysadmin/cgroups-part-one
https://en.wikipedia.org/wiki/Systemd
https://en.wikipedia.org/wiki/D-Bus
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/chap-managing_services_with_systemd
https://www.howtogeek.com/675569/why-linuxs-systemd-is-still-divisive-after-all-these-years/
https://systemd.io/
Book:ISBN: 979-10-91414-20-3 The Debian Administrator’s Handbook by Raphaël Hertzog and Roland Mas
Book:ISBN 978-1-80181-164-4 Linux Service Management Made Easy with systemd by Donald A. Tevault

1. systemd Units

# Units are the resources that systemd knows how to manage and to operate.
#-- 1.1. Unit Locations
# Locations of unit files (in increasing precedence):
# - /lib/systemd/system
# - /run/systemd/system
# - /etc/systemd/system
#
#-- 1.2. Unit Types:
# - .service: Contains information on managing a service or application. 
# Managing includes starting, stopping, automatic starting, dependencies 
# etc.
# - .socket: Describes a socket for systemd's socket based activation. It 
# must have an associated .service file for a service.
# - .device: Describes a device that needs systemd management. Not all 
# devices has a .device file.
# - .mount: Mountpoints needed to be managed by systemd.
# - .automount: Configures a mountpoint to be automatically mounted. Must 
# have a .mount unit.
# - .swap: Describes swap space on the system.
# - .target: Used to provide syncronization with other units. 
# - .path: Defines a path for path based activation. A matching unit is 
# started depending on the path existence or inexistence.
# - .timer: Defines a timer to be managed by systemd. A matching unit is 
# started when the timer is reached.
# - .snapshot: Created with systemctl snapshot command. Saves a state of the 
# system. Does not survive among sessions.
# - .slice: Associated with cgroups (Linux Control Group nodes). Allows 
# resources to be restricted.
# - .scope: Created automatically by systemd from information received from 
# its bus interfaces. Used to manage sets of system processes that are 
# created externally.
#
#-- 1.3. Sample Unit Files
# Contents of /lib/systemd/system/apache2.service
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=https://httpd.apache.org/docs/2.4/
[Service]
Type=forking
Environment=APACHE_STARTED_BY_SYSTEMD=true
ExecStart=/usr/sbin/apachectl start
ExecStop=/usr/sbin/apachectl graceful-stop
ExecReload=/usr/sbin/apachectl graceful
KillMode=mixed
PrivateTmp=true
Restart=on-abort
[Install]
WantedBy=multi-user.target
#
# Contents of /lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Alias=sshd.service
#
#
# Contents of /lib/systemd/system/ssh.socket
[Unit]
Description=OpenBSD Secure Shell server socket
Before=ssh.service
Conflicts=ssh.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Socket]
ListenStream=22
Accept=yes
[Install]
WantedBy=sockets.target
#
# 
# Contents of /etc/systemd/system/snap-firefox-2356.mount
[Unit]
Description=Mount unit for firefox, revision 2356
After=snapd.mounts-pre.target
Before=snapd.mounts.target
Before=local-fs.target
[Mount]
What=/var/lib/snapd/snaps/firefox_2356.snap
Where=/snap/firefox/2356
Type=squashfs
Options=nodev,ro,x-gdu.hide,x-gvfs-hide
LazyUnmount=yes
[Install]
WantedBy=snapd.mounts.target
WantedBy=multi-user.target
#
#-- 1.4. Unit File Structure
# - Unit files are made of sections. Unit and Install sections can exist in 
# all types of units. Also there are some other sections which can exist in 
# certain unit types. They are Socket, Mount, Automount, Swap, Path, Timer, 
# and Slice.
# - Sections contain directives. Some directives are unit type specific and 
# some are general.
# For a full list of directives see:
https://www.freedesktop.org/software/systemd/man/systemd.directives.html
#
# 1.4.1. Unit Section Directives (Applies to all unit types)
# - Description: A short description of the unit.
# - Documentation: Location of documentation.
# - Requires: The units that this unit depends. All of them must be 
# activated for this unit to be activated.
# - Wants: Similar to Requires, but not strict. Systemd tries to activate 
# the list of units before activating this unit.
# - BindsTo: Similar to Requires, also stops this unit when the listed unit 
# stops.
# - Before: This unit must be started before the listed units. Does not 
# imply dependency.
# - After: The list of units must be started before this unit. Does not 
# imply dependency.
# - Conflicts: This unit can not be run at the same time with the listed 
# unit. If this unit starts, other units stop.
# - Condition: This unit starts if the conditions are met. If conditions are 
# not met, this unit is skipped.
# - Assert: Similar to condition. But if conditions are not met, a failure 
# is caused.
# - ConditionPathExists: Unit starts if this path exists. Start the path 
# with ! to negate.
#
# 1.4.2. Install Section Directives (Applies to all unit types)
# - WantedBy: Similar to Wants directive of the Unit section. Mostly used 
# with targets.
# - RequiredBy: Similar to WantedBy but is more strict. Causes a failure if 
# the dependency is not met.
# - Alias: Allows the unit have an alias name. (Like ssh, sshd).
# - Also: Additional units to install/deinstall when this unit is installed/
# deinstalled,
# - DefaultInstance: Only used with template units. Default instance name of 
# the unit enabled from a template.
#
# 1.4.3. Service Section Directives (Applies to Service unit types)
# - Type: Could be one of the following
# -- simple: Systemd considers that the service starts immediately.
# -- exec: Similar to simple, but systemd waits for binary to execute.
# -- forking: The service forks a child process and exists.
# -- oneshot: The service live for a short time and then exit.
# -- dbus: The service will take a name on the D-Bus bus.
# -- notify: The service will notify when finishes starting up.
# -- idle: This indicates that the service will not be run until all jobs 
# are dispatched.
# - RemainAfterExit: Commonly used with the oneshot type. Indicates that the 
# service isactive even after the process exits.
# - PIDFile: For forking type, file to contain the PID of the child process.
# - BusName: For dbus type, name to acquire as D-Bus name.
# - NotifyAccess: Takes none, main, exec or none values. Controls which 
# service status messages are notified. 
# - Environment: Environment values to set.
# - EnvironmentFile: Read a list of environment values from this file. (-) 
# sign before the file name means, ignore if the file is not found.
# - Killmode: How to stop the service. process means only to kill the main 
# process, mixed means to kill the main process and the others, none means 
# just run ExecStop.
# - ExecStart: Command to start the service. If starts with -, ignore 
# failure.
# - ExecStartPre: Additional commands to run before the main process. 
# - ExecStartPost: Additional commands to run after the main process.
# - ExecReload: Command to reload the service.
# - ExecStop: Command to stop the service.
# - ExecStopPost: Additional commands to run after stopping the process.
# - RestartSec: Amount of time to wait before restart.
# - Restart: Circumstances to automatically restart the service. Could be: 
# always, on-success, on-failure, on-abnormal, on-abort, on-watchdog etc.
# - RestartPreventExitStatus: Prevents the service from automatically 
# restarting if the given exit code is received.
# - RuntimeDirectory: Directory to run the service (under /run).
# - RuntimeDirectoryMode: Permissions of the runtime directory (Default 
# 0755).
# - TimeoutSec: Amount of time to wait before starting or stopping the 
# service before marking as failed (or killing it).
# - TimeoutStartSec: Amount of time to wait before starting service before 
# marking as failed (or killing it).
# - TimeoutStopSec: Amount of time to wait before starting service before 
# marking as failed (or killing it).
#
# 1.4.3. Socket Section Directives (Applies to Socket unit types)
# - ListenStream: Address to listen on for a TCP stream.
# - ListenDatagram: Address to listen on for a UDP stream.
# - ListenSequentialPacket: Address to listen on for a Unix socket stream.
# - ListenFIFO: File system FIFO to listen on.
# - Accept: If yes, a service instance is spawned for each incoming 
# connection, if no, all listening sockets are passed to the started service
# unit.
# - SocketUser: Unix user name for the socket (default root).
# - SocketGroup: Unix group name for the socket (default root).
# - SocketMode: System access permissions for the socket (default 0666).
# - Service: Connected service name (if different than the socket name).
#
# 1.4.4. Mount Section Directives (Applies to Mount unit types)
# - What: Path to be mounted.
# - Where: Path to mount.
# - Type: The filesystem type of the mount.
# - Options: A comma-separated list of the mount options.
# - SloppyOptions: Boolean to determine whether the mount will fail if there 
# is an unrecognized mount option.
# - DirectoryMode: Permission mode for the parent dirs of the mount point.
# - TimeoutSec: Amount of time to wait before the operation is marked as 
# failed.
#
# 1.4.5. Automount Section Directives (Applies to Automount unit types)
# - Where: Path to mount.
# - DirectoryMode: Permission mode for the parent dirs of the mount point.
#
# 1.4.6. Swap Section Directives (Applies to Swap unit types)
# - What: Path of the location of swap (file or device).
# - Priority: Swap priority in integer form.
# - Options: Comma separated list of options for /etc/fstab file.
# - TimeoutSec: Amount of time to wait before the operation is marked as 
# failed.
#
# 1.4.7. Path Section Directives (Applies to Path unit types)
# - PathExists: If this path exists, associated unit will be activated.
# - PathExistsGlob: Similar to PathExists, supports file glob expressions.
# - PathChanged: Activates the associated unit when the file in the path is 
# saved and closed.
# - PathModified: Similar to PathChanged but also activates the unit when 
# the file is changed.
# - DirectoryNotEmpty: Activates the associated unit when the specified 
# directory is not empty.
# - Unit: Connected unit name (if different than the path name).
# - MakeDirectory: If true, the directories to watch are created before 
# watching.
# - DirectoryMode: Permissions to use if MakeDirectory is true (Default 755)
#
# 1.4.8. Timer Section Directives (Applies to Timer unit types)
# - OnActiveSec: Activate the associated unit after this amount of time  
# after the activation time of the timer unit.
# - OnBootSec: Activate the associated unit after this amount of the time 
# after the boot.
# - OnStartupSec: Activate the associated unit after this amount of the time 
# after systemd process started.
# - OnUnitActiveSec: Activate the associated unit after this amount of the 
# time after the associated unit last activated.
# - OnUnitInactiveSec: Activate the associated unit after this amount of the 
# time after the associated unit last marked as inactive.
# - OnCalendar: Absolute time to activate the associated unit.
# - AccuracySec: Level of accuracy of the timer.
# - Unit: Associated unit name (if different than the timer name).
# - Persistent: If true, the time when the service unit was last triggered 
# is stored on disk. When the timer is activated, the service unit is 
# triggered immediately if it would have been triggered at least once during
# the time when the timer was inactive. 

2. Targets

#-- 2.1. Definition and List
# - Similar to SysV init runlevel. Their purpose is to group together other 
# systemd units through a chain of dependencies.
# A fresh install Ubuntu 22.04 server has the following targets:
systemctl list-unit-files --type=target
UNIT FILE                     STATE           VENDOR PRESET
basic.target                  static          -            
blockdev@.target              static          -            
bluetooth.target              static          -            
boot-complete.target          static          -            
cloud-config.target           static          -            
cloud-init.target             enabled-runtime enabled      
cryptsetup-pre.target         static          -            
cryptsetup.target             static          -            
ctrl-alt-del.target           alias           -            
default.target                alias           -            
emergency.target              static          -            
exit.target                   disabled        disabled     
final.target                  static          -            
first-boot-complete.target    static          -            
friendly-recovery.target      static          -            
getty-pre.target              static          -            
getty.target                  static          -            
graphical.target              static          -            
halt.target                   disabled        disabled     
hibernate.target              static          -            
hybrid-sleep.target           static          -            
initrd-fs.target              static          -            
initrd-root-device.target     static          -            
initrd-root-fs.target         static          -            
initrd-switch-root.target     static          -            
initrd-usr-fs.target          static          -            
initrd.target                 static          -            
kexec.target                  disabled        disabled     
local-fs-pre.target           static          -            
local-fs.target               static          -            
multi-user.target             static          -            
network-online.target         static          -            
network-pre.target            static          -            
network.target                static          -            
nss-lookup.target             static          -            
nss-user-lookup.target        static          -            
paths.target                  static          -            
poweroff.target               disabled        disabled     
printer.target                static          -            
reboot.target                 disabled        enabled      
remote-cryptsetup.target      disabled        enabled      
remote-fs-pre.target          static          -            
remote-fs.target              enabled         enabled      
remote-veritysetup.target     disabled        enabled      
rescue-ssh.target             static          -            
rescue.target                 static          -            
rpcbind.target                static          -            
runlevel0.target              alias           -            
runlevel1.target              alias           -            
runlevel2.target              alias           -            
runlevel3.target              alias           -            
runlevel4.target              alias           -            
runlevel5.target              alias           -            
runlevel6.target              alias           -            
shutdown.target               static          -            
sigpwr.target                 static          -            
sleep.target                  static          -            
slices.target                 static          -            
smartcard.target              static          -            
snapd.mounts-pre.target       static          -            
snapd.mounts.target           static          -            
sockets.target                static          -            
sound.target                  static          -            
suspend-then-hibernate.target static          -            
suspend.target                static          -            
swap.target                   static          -            
sysinit.target                static          -            
system-update-pre.target      static          -            
system-update.target          static          -            
time-set.target               static          -            
time-sync.target              static          -            
timers.target                 static          -            
umount.target                 static          -            
usb-gadget.target             static          -            
veritysetup-pre.target        static          -            
veritysetup.target            static          -            
#
# Target configuration files reside in /lib/systemd/system/
#
#-- 2.2. Sample Target Files
# network.target
[Unit]
Description=Network
Documentation=man:systemd.special(7)
Documentation=https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget
After=network-pre.target
RefuseManualStart=yes
#
# multi-user.target
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
#
# graphical.target
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes

3. Unit Management: systemctl Command

# Start a service
sudo systemctl start apache2.service
#
# Stop a service
sudo systemctl stop apache2.service
#
# Reload a service
sudo systemctl reload apache2.service
#
# Restart a service
sudo systemctl restart apache2.service
#
# Try to reload if possible, otherwise restart a service
sudo systemctl reload-or-restart apache2.service
#
# Enable a service (starts at boot)
sudo systemctl enable apache2.service
#
# Disable a service (does not start at boot)
sudo systemctl disable apache2.service
#
# Show status of a service
sudo systemctl status apache2.service
#
# Show if service is active
systemctl is-active apache2.service
#
# Show if service is enabled
systemctl is-enabled apache2.service
#
# Show if service is failed
systemctl is-failed apache2.service
#
# Mask a service (completely unstartable)
sudo systemctl mask apache2.service
#
# Unmask a service
sudo systemctl unmask apache2.service
#
# List all active units
sudo systemctl list-units
#
# Including loaded and attempted to load
sudo systemctl list-units --all
#
# Including all installed
sudo systemctl list-unit-files
#
# List services only
systemctl list-units --type=service
#
# See contents of a unit file
systemctl cat apache2.service
#
# See dependencies of a unit
systemctl list-dependencies apache2.service
#
# See dependencies of a unit recursively
systemctl list-dependencies apache2.service --all
#
# See low level details of a unit
systemctl show apache2.service
#
# Append or modify settings in a unit file
sudo systemctl edit apache2.service
#
# Edit entire contents of a unit file
sudo systemctl edit --full apache2.service
#
# Reload systemd
sudo systemctl daemon-reload
#
# Show default target (run level) of a system
systemctl get-default
#
# Set default target
sudo systemctl set-default graphical.target
sudo systemctl set-default multi-user.target
#
# List of available targets
systemctl list-unit-files --type=target
#
# List of units tied to a target
systemctl list-dependencies multi-user.target
#
# Poweroff and reboot
sudo systemctl poweroff
sudo systemctl reboot
#
# Boot into rescue mode
sudo systemctl rescue
#
# Halt (Does not poweroff the machine)
sudo systemctl halt
#
# Control systemd of a remote system
systemctl --host user_name@host_name command

4.Log Management: journal-ctl Command

# See all log entries
journalctl
#
# See all log entries for the current boot
journalctl -b
#
# See only kernel entries
journalctl -k
#
# See only kernel entries for the current boot
journalctl -k -b
#
# See only apache log entries
journalctl -u apache2.service
#
# See only apache log entries for the current boot
journalctl -b -u apache2.service
#
# See logs from previous boot
journalctl -b -1
#
# List boots
journalctl --list-boots
#
# Logs in a time interval
journalctl --since "2023-01-10 17:15:00"
journalctl --since "2023-01-10" --until "2023-01-11 03:00"
journalctl --since yesterday
journalctl --since 09:00 --until "1 hour ago"
journalctl -u apache2.service --since today
#
# Log entries for an executable
journalctl /usr/bin/bash
#
# Log in json format
journalctl -b -u apache2 -o json
journalctl -b -u apache2 -o json-pretty
#
# Most recent 10 entries
journalctl -n
#
# Most recent 20 entries
journalctl -n 20
#
# Actively follow logs (like tail -f). Press Ctrl-C to exit.
journalctl -f
#
# Disk usage
journalctl --disk-usage
#
# Delete old logs up to size
sudo journalctl --vacuum-size=1G
#
# Delete old logs up to time
sudo journalctl --vacuum-time=1years

5. Other systemd Components

# systemd has some other components too. Some of them:
#
# - systemd-boot: UEFI boot manager. Supports basic boot manager 
# configuration. 
# Integrates with systemctl command. Has the command bootctl.
# - systemd-cat: Adds a record to the systemd log with a pipeline.
echo "Test" | systemd-cat -p info
# - systemd-localed: Manages system locale settings. Has the command 
# localectl.
# - systemd-logind: Manages user logins. Keeps track of users and sessions. 
# Handles device access management for users.
# - systemd-machined: Detects and monitors virtual machines and containers. 
# Has machinectl command.
# - systemd-mount: Handles .mount and .automount units.
# - systemd-networkd: Network configuration management. Configuration files 
# are in /lib/systemd/network, /run/systemd/network, and /etc/systemd/network 
# in increasing precedence.
# - systemd-nspawn: May be used to run a command or OS in a light-weight
# namespace container. In many ways it is similar to chroot
# - systemd-resolved: Provides network name resolution. Has resolvectl 
# command.
# - systemd-sysusers: Creates system users and groups.
# - systemd-timesyncd: Provides system time synchronization across the 
# network with a remote NTP server. Has timedatectl command.
# - systemd-tmpfiles: Creates, deletes, and cleans up volatile and temporary 
# files and directories.
# - systemd-udevd: Manages physical devices.

6. Creating a Service

# - We will create a very simple service. Our service will ping an IP 
# address in every 10 minutes. It will create an info log if the ping is OK, 
# otherwise it will create and error log.
# - The application will be a shell script, the script will be put into 
# /usr/local/bin, a unit file will be created, enabled, started and tested.
#
#-- 6.1. Create Shell Script
nano ipcheck.sh
# Fill as below
#!/bin/bash
echo "ipcheck.service: Start. $(date)" | systemd-cat -p info
while true ; do
  ping -q -w 1 192.168.1.1 > /dev/null
  if [ $? = 0 ] ; then
     echo "ipcheck.service: Ping to IP is OK. $(date)" | systemd-cat -p info
  else
     echo "ipcheck.service: Error cannot ping IP. $(date)" | systemd-cat -p err
  fi
  sleep 600
done
#
#-- 6.2. Copy it into /usr/local/bin
# Make it executable
chmod +x ipcheck.sh
# Copy
sudo cp ipcheck.sh /usr/local/bin
#
#-- 6.3. Create Unit File
sudo systemctl edit --force --full ipcheck.service
# The command will open a nano editor
# Fill it as below, save and exit
[Unit]
Description=IPCheck Demo Service
Wants=network.target
After=syslog.target network-online.target
[Service]
ExecStart=/usr/local/bin/ipcheck.sh
Restart=on-failure
RestartSec=20
KillMode=process
[Install]
WantedBy=multi-user.target
#
#-- 6.4. Enable and Start The Service
sudo systemctl enable ipcheck.service
sudo systemctl start ipcheck.service
#
#-- 6.5. Test it
sudo journalctl -n 20




Nginx On Debian/Ubuntu

NginxOnDebianUbuntu: Basic Nginx Configuration On Debian and Ubuntu

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

Specs

# - Basic Nginx configuration, installation, SSL, LEMP stack, sample site
# configurations, 
# 
# Server: Debian 12/11 or Ubuntu 22.04/20.04 LTS Server
# srv1, srv2, srv3, srv4 all has the server's IP address.
#
# Sources:
Book:ISBN 978-1-80323-424-3 Mastering Ubuntu Server 4th Ed. by Jay LaCroix
https://nginx.org/en/docs/
https://www.geeksforgeeks.org/how-to-retrieve-data-from-mysql-database-using-php/

1. Installation and Configuration Files

#-- 1.1. Installation
# Update repositories
sudo apt update
# Install nginx
sudo apt install nginx --yes
# A simple website is ready at http://srv1/
#
#-- 1.2. Configuration Files
# Configuration files reside in /etc/nginx.
# See main configuration file:
sudo nano /etc/nginx/nginx.conf
# 
# Available sites are in /etc/nginx/sites-available/
#  They must be enabled, that is linked to /etc/nginx/sites-enabled/ 
# - To enable a site conf named mysite in /etc/nginx/sites-available/ :
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite
# And to disable it:
sudo rm /etc/nginx/sites-enabled/mysite
# - There is a default configuration which is already enabled
sudo nano /etc/nginx/sites-available/default
#
# - After enabling or disabling a site, we need to reload nginx:
sudo systemctl reload nginx
# 
#-- 1.3. Site enable and disable scripts
# - You may remember Ubuntu (and Debian) Apache installations has a2ensite 
# and a2dissite scripts. We will create very (actually very very) simple 
# nginx scripts like them. 
#
# 1.3.1. Create ~/bin Directory
# - This directory is in the search list of the executable files. You may 
# already have it. If it is so, skip this step.
mkdir ~/bin
# You have to logoff and logon again.
#
# 1.3.2. Scripts
# Create site enable script
nano ~/bin/ngensite
# Fill it as below
#/bin/bash
sudo ln -s /etc/nginx/sites-available/$1 /etc/nginx/sites-enabled/$1
#
# Create site disable script
nano ~/bin/ngdissite
# Fill it as below
#/bin/bash
sudo rm /etc/nginx/sites-enabled/$1
#
# Make scripts executable
chmod +x ~/bin/ngensite
chmod +x ~/bin/ngdissite
#
# Now we can disable or enable a site with these scripts:
ngensite default
ngdissite default
# 
#-- 1.4. Redesign Our Site
# - We will disable default configuration, leave it at sites-available as a 
# template, create a new conf with the name srv1 (my hostname) and enable 
# it.
#
# 1.4.1. Disable default Conf
sudo rm /etc/nginx/sites-enabled/default
# or simply
ngdissite default
#
# 1.4.2. Create the New Conf
sudo nano /etc/nginx/sites-available/srv1
# Fill it as below
server {
   listen 80;
   listen [::]:80;
   root /var/www/html;
   index index.html index.htm index.nginx-debian.html;
   server_name srv1;
   location / {
      try_files $uri $uri/ =404;
   }
   server_tokens off;
}
#
# Explanations:
# - Listen IP version 4 at port 80
# - Listen IP version 6 at port 80
# - Root directory is /var/www/html
# - Index file (default file) is one of the following in order
# - Server name is srv1 (can be more than 1 - after srv1)
# - For the location in root (and subfolders), try the given name as a file,
# then as a folder, if can't find, send 404 error message.
# - Don't display server version at error (and other) messages.
#
# 1.4.3. Enable the New Conf
ngensite srv1
# It is necessary to reload nginx
sudo systemctl reload nginx

2. SSL Configuration

# - We will test SSL configuration with self signed certificates. Later on 
# the tutorial, we are going to test getting certificates with certbot tool 
# too.
#
#-- 2.1. Create a Self Signed Certificate
# Create a place for the certificates
sudo mkdir /etc/nginx/certs
# Create certificates
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/nginx/certs/srv1.key -out /etc/nginx/certs/srv1.crt
# You can give default answers to all the questions.
# Key and certificate files are copied to /etc/nginx/certs/
#
#-- 2.1. Create SSL Conf
sudo nano /etc/nginx/sites-available/srv1-ssl
# Fill it as below
server {
   listen 443 ssl;
   listen [::]:443 ssl;
   root /var/www/html;
   index index.html index.htm index.nginx-debian.html;
   server_name srv1;
   ssl_certificate /etc/nginx/certs/srv1.crt;
   ssl_certificate_key /etc/nginx/certs/srv1.key;
   ssl_session_timeout 5m;
   location / {
      try_files $uri $uri/ =404;
   }
   server_tokens off;
}
#
# Enable it
ngensite srv1-ssl
#
#-- 2.2. HTTPS Redirection
# - We have to add a redirection to srv1 conf to automatically redirect 
# http://srv1/ to https://srv1/
sudo nano /etc/nginx/sites-available/srv1
# Add the line below after the listen lines
   return 301 https://$host$request_uri;
#
# Reload nginx
sudo systemctl reload nginx
#
#-- 2.3. SSL Site is Ready
https://srv1/
# - Your firefox will complain as "Warning: Potential Security Risk Ahead", 
# because our certificate is a self signed one. You can click "Advanced" and
# "Accept the Risk and Continue" to reach the SSL site.

3. LEMP Stack

# L: Linux (Debian or Ubuntu in our case)
# E: Nginx (Enginx actually)
# M: Mariadb (or Mysql if you love Or*cle so much)
# P: PHP, Python, or Perl (PHP in our case)
#
# So not a big deal, we'll install Mariadb and PHP and connect them with 
# Nginx.
#
#-- 3.1. Install mariadb, php, and necessary dependancies.
# php-cli   : PHP client package
# php-fpm   : to run php as a cgi, nginx doesn't have a native support for 
# php-mysql : for php to connect to mariadb
sudo apt install --yes mariadb-server php-cli php-fpm php-mysql
#
#-- 3.2. Update srv1-ssl Conf for PHP
sudo nano /etc/nginx/sites-available/srv1-ssl
# Add the following part after the end of the location stanza.
   location ~ \.php$ {
      fastcgi_pass unix:/run/php/php-fpm.sock;
      include fastcgi.conf;
   }
#
# Restart nginx
sudo systemctl restart nginx
# 
#-- 3.3. Test it
# - We'll create a test database, a table in that database, add some rows to 
# the table on Mariadb. We will also create a test PHP file with the PHP 
# code to retrieve the data from the database and display it as HTML. 
#
# 3.3.1. DB Operations
# Connect to Mariadb shell
sudo mariadb
# - Create mysampledb database, connect to it, create a table, fill the 
# table, create a user with the access permission to that database and the 
# table.
# !!! BEGIN Run on Mariadb shell. !!!
CREATE DATABASE mysampledb;
USE mysampledb;
CREATE TABLE Employees (Name char(15), Age int(3), Occupation char(15));
INSERT INTO Employees VALUES ('Joe Smith', '26', 'Ninja');
INSERT INTO Employees VALUES ('John Doe', '33', 'Sleeper');
INSERT INTO Employees VALUES ('Mariadb Server', '14', 'RDBM');
GRANT ALL ON mysampledb.* TO 'appuser'@'localhost' IDENTIFIED BY 'password';
exit
# !!! END Run on Mariadb shell. !!!
# 
# 3.3.2. Create Test PHP
sudo nano /var/www/html/test.php
# Fill it as below
<?php
   $mycon = new mysqli("localhost", "appuser", "password", "mysampledb");
   if ($mycon->connect_errno)
   {
      echo "Connection Error";
      exit();
   }
   $mysql = "SELECT * FROM Employees";
   $result = ($mycon->query($mysql));
   $rows = [];
   if ($result->num_rows > 0)
    {
        $rows = $result->fetch_all(MYSQLI_ASSOC);
    }
?>
<!DOCTYPE html>
<html>
<body>
    <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>Age</th>
                <th>Occupation</th>
            </tr>
        </thead>
        <tbody>
            <?php
               if(!empty($rows))
               foreach($rows as $row)
              {
            ?>
            <tr>
                <td><?php echo $row['Name']; ?></td>
                <td><?php echo $row['Age']; ?></td>
                <td><?php echo $row['Occupation']; ?></td>
            </tr>
            <?php } ?>
        </tbody>
    </table>
</body>
</html>
<?php
    mysqli_close($conn);
?>
# Now go to below address to see if it is working
https://srv1/test.php

4. Sample Configs

#-- 4.1. Three Sites in One Conf File
# srv2, srv3, and srv4 all have their directories and served in the same 
# server
server {
   listen 80;
   listen [::]:80;
   root /var/www/srv2;
   index index.html index.htm index.nginx-debian.html;
   server_name srv2;
   location / {
      try_files $uri $uri/ =404;
   }
}
server {
   listen 80;
   listen [::]:80;
   root /var/www/srv3;
   index index.html index.htm index.nginx-debian.html;
   server_name srv3;
   location / {
      try_files $uri $uri/ =404;
   }
}
server {
   listen 80;
   listen [::]:80;
   root /var/www/srv4;
   index index.html index.htm index.nginx-debian.html;
   server_name srv4;
   location / {
      try_files $uri $uri/ =404;
   }
}
#
#-- 4.2. Site Only Allowing 2 IPs to connect
server {
   listen 80;
   listen [::]:80;
   root /var/www/srv2;
   index index.html index.htm index.nginx-debian.html;
   server_name srv2;
   allow 192.168.1.108;
   allow 192.168.1.109;
   deny all;
   location / {
      try_files $uri $uri/ =404;
   }
}
#
#-- 4.3. IP Access Control on One Directory Only
# Site is open to all IPs. Admin folder is restricted to 1 IP.
server {
   listen 80;
   listen [::]:80;
   root /var/www/srv2;
   index index.html index.htm index.nginx-debian.html;
   server_name srv2;
   deny all;
   location / {
      try_files $uri $uri/ =404;
   }
   location /admin {
      allow 192.168.1.108;
      deny all;
   }
}
#
#-- 4.4. Https Redirection with Certbot Access
# - Redirect to Https site except the certbot (Letsencrypt acme challenge) 
# accessing /.well-known/acme-challenge/. So that certbot can renew 
# certificates by connecting to the Http site.
#
server {
   listen 80;
   listen [::]:80;
   index index.html index.htm index.nginx-debian.html;
   server_name srv1;
   location ^~ /.well-known/acme-challenge {
       allow all; 
       root /var/www/html;
   }
    location / {
       return 301 https://$host$request_uri;
    }
   server_tokens off;
}

5. HTTPS With Free Let's Encrypt Certificates

# - This section is performed on a VPS on internet. To get free Let's 
# Encrypt certificates, our hostname must be in a DNS in internet. 
#
#-- 5.0. Specs
# Server   : Debian 12/11 or Ubuntu 22.04/20.04 LTS Server
# Hostname : x11.xyz
# Server is fresh installed.
# 
# - Remember to change all the occurences of x11.xyz and www.x11.xyz with 
# your server names.
#
#-- 5.1. Install Nginx
sudo apt update
sudo apt install nginx --yes
#
#-- 5.2. Create ngensite and ngdissite scripts as in 1.3.
#
#-- 5.3. Disable default Site and Create a New One Named as x11.xyz
ngdissite default
sudo nano /etc/nginx/sites-available/x11.xyz
# Fill it as below
server {
   listen 80;
   listen [::]:80;
   root /var/www/x11.xyz;
   index index.html index.htm index.nginx-debian.html;
   server_name x11.xyz www.x11.xyz;
   location / {
      try_files $uri $uri/ =404;
   }
   server_tokens off;
}
#
# Create /var/www/x11.xyz folder. Put some test HTMLs into it.
#
# Enable the new conf
ngensite x11.xyz
# Reload nginx
sudo systemctl reload nginx
# Your site is ready
# 
#-- 5.4. Install certbot and Get a Free Certificate
# Install certbot
sudo apt install certbot --yes
#
# - Run certbot to get certificates. For authentication method question; 
# select the option 2 (Place files ...), and enter root directory 
# (/var/www/x11.xyz for my server).  Enter an email address and accept TOS.
sudo certbot certonly -d x11.xyz -d www.x11.xyz
# Certificates are installed to /etc/letsencrypt/live/x11.xyz/
# Certificates will auto renew, you can check the process with:
sudo certbot renew --dry-run
#
#-- 5.5. Create a conf for the SSL site
sudo nano /etc/nginx/sites-available/x11.xyz-ssl
server {
   listen 443 ssl;
   listen [::]:443 ssl;
   root /var/www/x11.xyz;
   index index.html index.htm index.nginx-debian.html;
   server_name x11.xyz www.x11.xyz;
   ssl_certificate /etc/letsencrypt/live/x11.xyz/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/x11.xyz/privkey.pem;
   ssl_session_timeout 5m;
   location / {
      try_files $uri $uri/ =404;
   }
   server_tokens off;
}
# Enable it
ngensite x11.xyz-ssl
#
#-- 5.5. Update HTTP conf
# Our http conf must redirect to https site with the exception of certbot
# renew process
sudo nano /etc/nginx/sites-available/x11.xyz
# Change as below
server {
   listen 80;
   listen [::]:80;
   index index.html index.htm index.nginx-debian.html;
   server_name x11.xyz www.x11.xyz;
   location ^~ /.well-known/acme-challenge {
       allow all; 
       root /var/www/x11.xyz;
   }
    location / {
       return 301 https://$host$request_uri;
    }
   server_tokens off;
}
#
# Reload Nginx
sudo systemctl reload nginx
#
# Your HTTPS site is ready:
https://x11.xyz/

6. Nginx and Apache Together

# !!! This section starts with a fresh installed server !!!
# - Nginx is very good at static content, Apache is very good at dynamic 
# content. So we can use them together for the maximum performance.
#-- 6.0. Specs
# - Nginx will run at port 80 and listen to the outside.
# - Apache will run at port 8080 and listen to only inside. That is it can 
# be connected by only the localhost. So that only Nginx will listen to it.
# - PHP and Mariadb will be connected to Apache only.
# - All the HTML (and other static content) will be served by Nginx.
# - All the PHP (and other dynamic content) will be served by Apache.
#
#-- 6.1. Install nginx And Reconfigure the Default Site
# Of course you may disable the default site and configure a new one
# Install nginx
sudo apt update
sudo apt install nginx --yes
# Backup default conf
sudo cp /etc/nginx/sites-available/{default,default.backup}
# Update default conf
sudo nano /etc/nginx/sites-available/default
# Fill as below
server {
   listen 80;
   listen [::]:80;
   server_name .x11.xyz;
   index index.html index.htm index.nginx-debian.html;
   root /var/www/html;
   location ~ \.php {
      proxy_pass http://127.0.0.1:8080;
   }
   location / {
      try_files $uri $uri/ =404;
   }
   server_tokens off;
}
# Reload nginx
sudo systemctl reload nginx
#
#-- 6.2. Install apache2, php, mariadb, and dependencies
sudo apt install --yes apache2 php mariadb-server libapache2-mod-php php-mysql
# Apache doesn't start automatically, because port 80 is busy with nginx.
# Change Apache's default listening port from 80 to 8080.
sudo nano /etc/apache2/ports.conf
# Change the following line from: 
Listen 80
# to as below
Listen 8080
# Update the default conf to listen to 8080 and only from local
sudo nano /etc/apache2/sites-available/000-default.conf
# Change the first line from:
<VirtualHost *:80>
# to as below
<VirtualHost 127.0.0.1:8080>
# Restart Apache
sudo systemctl restart apache2
#
# You can test the combination using steps at 3.3.




Other Linuxes On Debian/Ubuntu

OtherLinuxesOnDebianUbuntu – Other Linuxes for Debian/Ubuntu Admins

Copyright (C) 2023 Exforge exforge@x386.org

# - This document is free text: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# - This document is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# - You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

0. Specs

#-- 0.1. Information
# - Although my tutorials (and my learning curve) contain Debian and 
# Ubuntu Linux distributions; Time to time, an admin may need to handle
# other Linuxes too. In this tutorial, my aim is to help with other linuxes,
# namely Red Hat, Opensuse, Alpine, and Devuan.
#
# - Main subjects are:
# -- Package Management
# -- Network Configuration
# -- Installing LAMP Stack
# -- Service Management
# - Main Distributions:
# -- Debian 12 and 11
# -- Ubuntu 22.04 and 20.04 LTS
# -- RHEL (Centos, Alma, Rocky) 9.x, 8.x
# -- OpenSuse Leap 15.x
# -- Alpine 3.17
# -- Devuan 4
#
#-- 0.2. Resources:
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9
https://wiki.alpinelinux.org/wiki/Main_Page
https://doc.opensuse.org/
https://wiki.debian.org/
https://www.geeksforgeeks.org/how-to-retrieve-data-from-mysql-database-using-php/

1. Debian 12 & 11

#-- 1.1. Package Management
# Commands require root or sudo.
# 1.1.1. Update Cache
apt update
# 1.1.2. Upgrade Packages
apt upgrade
# 1.1.3. Install a Package
apt install apache2
# 1.1.4. Remove a Package
apt remove apache2
# 1.1.5. Search a Package
apt search apache2
# 1.1.6. Clean Unused Packages
apt autoremove
# 1.1.7. Show Package Info
apt show apache2
# 
#-- 1.2. Network Configuration
# 1.2.1. Get the name of the network adapter
# - The name of the network adapter will be something like enp0s3, but we 
# need the exact name. 
# - The following command lists the network interface name(s). The one in 
# en* format should be the name of your network adapter.
ls /sys/class/net
# In any case you cannot get the name, you can try to following command:
ip a
#
# 1.2.2. IP configuration. 
sudo nano /etc/network/interfaces
# I assume that your network adapter name is enp0s3, otherwise change it.
# Fill the file like below (change to your IP addresses)
auto enp0s3
iface enp0s3 inet static
address 192.168.0.3/24
broadcast 192.168.0.255
network 192.168.0.0
gateway 192.168.0.1
# If you want to use DHCP, fill the file as below
auto enp0s3
iface enp0s3 inet dhcp
# 
# 1.2.3. DNS Addresses
sudo nano /etc/resolv.conf
# Add your DNS addresses as below
nameserver 46.196.235.35
nameserver 178.233.140.110
nameserver 46.197.15.60
#
# 1.2.4. Restart Network Adapter
# Assuming your network adapter name is enp0s3
sudo ifdown enp0s3 && sudo ifup enp0s3
# or
sudo systemctl restart networking.service
# - If you are connecting through SSH, your connection would break up. You 
# need to connect with the new IP again.
#
#-- 1.3. Installing LAMP Stack
# 1.3.1. Install packages
sudo apt update
sudo apt install --yes apache2 mariadb-server php libapache2-mod-php php-mysql
# - This is all we need actually. But if you are like me, that is you have 
# to see it to believe it; you are going to want to test it. So let's test 
# it.
#
# 1.3.2. Test LAMP
# - We'll create a test database on Mariadb, we'll create a table in that 
# database, add some rows to the table. We will also create a test PHP file
# with the PHP code to retrieve the data from the database and display it as 
# HTML. That way we'll be able to test the PHP-Mariadb and PHP-Apache 
# connections.
sudo mariadb
# - Create mysampledb database, connect to it, create a table, fill the 
# table, create a user with the access permission to that database and the 
# table.
# !!! BEGIN Run on Mariadb shell. !!!
CREATE DATABASE mysampledb;
USE mysampledb;
CREATE TABLE Employees (Name char(15), Age int(3), Occupation char(15));
INSERT INTO Employees VALUES ('Joe Smith', '26', 'Ninja');
INSERT INTO Employees VALUES ('John Doe', '33', 'Sleeper');
INSERT INTO Employees VALUES ('Mariadb Server', '14', 'RDBM');
GRANT ALL ON mysampledb.* TO 'appuser'@'localhost' IDENTIFIED BY 'password';
exit
# !!! END Run on Mariadb shell. !!!
# 
# Create test PHP
sudo nano /var/www/html/test.php
# Fill it as below
<?php
   $mycon = new mysqli("localhost", "appuser", "password", "mysampledb");
   if ($mycon->connect_errno)
   {
      echo "Connection Error";
      exit();
   }
   $mysql = "SELECT * FROM Employees";
   $result = ($mycon->query($mysql));
   $rows = [];
   if ($result->num_rows > 0)
    {
        $rows = $result->fetch_all(MYSQLI_ASSOC);
    }
?>
<!DOCTYPE html>
<html>
<body>
    <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>Age</th>
                <th>Occupation</th>
            </tr>
        </thead>
        <tbody>
            <?php
               if(!empty($rows))
               foreach($rows as $row)
              {
            ?>
            <tr>
                <td><?php echo $row['Name']; ?></td>
                <td><?php echo $row['Age']; ?></td>
                <td><?php echo $row['Occupation']; ?></td>
            </tr>
            <?php } ?>
        </tbody>
    </table>
</body>
</html>
<?php
    mysqli_close($conn);
?>
#
# - Now, from your workstation's browser, load the page (replace srv with 
# your server's IP: 
http:/srv/test.php
# You can use the same steps for testing LAMP stack on other distros too.
#
#-- 1.4. Service Management
# - Conventionally, when a package with a service is installed on Devuan, it
# is enabled and started by default.
#
# 1.4.1. Status of a Service
systemctl status apache2
# 
# 1.4.2. Start/Stop a Service
sudo systemctl stop apache2
sudo systemctl start apache2
# To force to stop
sudo systemctl kill apache2
#
# 1.4.3. Reload a Service
# Reads configuration file again
sudo systemctl reload apache2
#
# 1.4.4. Restart a Service
# Stops and Starts
sudo systemctl restart apache2
#
# 1.4.5. Enable/Disable a Service
sudo systemctl enable apache2
sudo systemctl disable apache2

2. Ubuntu 22.04 LTS & 20.04 LTS

#-- 2.1. Package Management
# Commands require root or sudo.
# 2.1.1. Update Cache
apt update
# 2.1.2. Upgrade Packages
apt upgrade
# 2.1.3. Install a Package
apt install apache2
# 2.1.4. Remove a Package
apt remove apache2
# 2.1.5. Search a Package
apt search apache2
# 2.1.6. Clean Unused Packages
apt autoremove
# 2.1.7. Show Package Info
apt show apache2
# 
#-- 2.2. Network Configuration
# 2.2.1. Get the name of the network adapter
# - The name of the network adapter will be something like enp0s3, but we 
# need the exact name. 
# - The following command lists the network interface name(s). The one in 
# en* format should be the name of your network adapter.
ls /sys/class/net
# In any case you cannot get the name, you can try to following command:
ip a
#
# 2.2.2. Network configuration. 
# By default Ubuntu uses netplan for network configuration.
sudo nano /etc/netplan/00-installer-config.yaml
# The file name might be different, in that case, use that file.
# I assume that your network adapter name is enp0s3, otherwise change it.
# Fill the file like below (change to your IP addresses)
network:
  ethernets:
    enp0s3:
      addresses:
      - 192.168.1.182/24
      routes:
      - to: default
        via: 192.168.1.1
      nameservers:
        addresses:
        - 8.8.8.8
        - 192.168.1.1
        search:
        - x11.xyz
  version: 2
#
# 2.2.3. Restart Netplan
# Assuming your network adapter name is enp0s3
sudo netplan apply
# - If you are connecting through SSH, your connection would break up. You 
# need to connect with the new IP again.
#
#-- 2.3. Installing LAMP Stack
# 2.3.1. Install packages
sudo apt update
sudo apt install --yes apache2 mariadb-server php libapache2-mod-php php-mysql
#
# 2.3.2. Test LAMP
# You can use the test scenario at 1.3.2 to test RHEL LAMP stack.
#
#-- 2.4. Service Management
# - As Ubuntu being a derivative of Debian, when a package with a service is 
# installed, it is enabled and started by default.
#
# 2.4.1. Status of a Service
systemctl status apache2
# 
# 2.4.2. Start/Stop a Service
sudo systemctl stop apache2
sudo systemctl start apache2
# To force to stop
sudo systemctl kill apache2
#
# 2.4.3. Reload a Service
# Reads configuration file again
sudo systemctl reload apache2
#
# 2.4.4. Restart a Service
# Stops and Starts
sudo systemctl restart apache2
#
# 2.4.5. Enable/Disable a Service
sudo systemctl enable apache2
sudo systemctl disable apache2

3. RHEL (Centos, Alma, Rocky) 9.x, 8.x

# - Centos (upto 8.x version), Alma and Rocky Linux are compatible 
# with Red Hat. That is, they are same other than brandings and names. So 
# if something works in RHEL, it works in Centos, Alma, and Rocky too.
# - RHEL gives free licenses for testing purposes, I have 2 VMs running for
# testing purposes (versions 8.x and 9.x).
#
#-- 3.1. Package Management
# Commands require root or sudo.
# 3.1.1. Update Cache
dnf check-update   
# It is always called when installing or updating packages
# So it is not necessary
# 3.1.2. Upgrade Packages
dnf upgrade
# 3.1.3. Install a Package
dnf install httd
# 3.1.4. Remove a Package
dnf remove httpd
# 3.1.5. Search a Package
dnf search httpd
# 3.1.6. Clean Unused Packages
dnf autoremove
# 3.1.7. Show Package Info
dnf info httpd
# 
#-- 3.2. Network Configuration
# 3.2.1. Get the name of the network adapter
# - The name of the network adapter will be something like enp0s3, but we 
# need the exact name. 
# - The following command lists the network interface name(s). The one in 
# en* format should be the name of your network adapter.
ls /sys/class/net
# In any case you cannot get the name, you can try to following command:
ip a
#
# 3.2.2. IP and DNS configuration. 
# I assume that your network adapter name is enp0s3, otherwise change it.
# Change IP and Gateway, change DNS
sudo nmcli con modify 'enp0s3' ifname enp0s3 ipv4.method manual \
   ipv4.addresses 192.168.0.210/24 gw4 192.168.0.1
sudo nmcli con modify 'enp0s3' ipv4.dns 8.8.8.8
#
# 3.2.3. Restart Network Adapter
sudo nmcli con down 'enp0s3' && sudo nmcli con up 'enp0s3'
#
#-- 3.3. Installing LAMP Stack
# - As you might expect package names are different in RHEL (e.g. httpd 
# instead of apache2).
# 3.3.1. Install packages
sudo dnf -y install httpd mariadb-server php php-mysqlnd
#
# 3.3.2. Enable and Start Apache and Mariadb
sudo systemctl enable --now httpd
sudo systemctl start httpd
sudo systemctl enable --now mariadb
sudo systemctl start mariadb
#
# 3.3.3. Opening Firewall Ports
# - RHEL activates firewall by default. We have to open http and https ports
# permanently.
sudo firewall-cmd --add-service=http --add-service=https
sudo firewall-cmd --add-service=http --add-service=https --permanent
#
# 3.3.4. Test
# You can use the test scenario at 1.3.2 to test RHEL LAMP stack. For RHEL 
# 8, you should run "sudo mysql" instead of "sudo mariadb".
#
#-- 3.4. Service Management
# - RHEL and derivatives does not enable and start services by default.
#
# 3.4.1. Status of a Service
systemctl status httpd
# 
# 3.4.2. Start/Stop a Service
sudo systemctl stop httpd
sudo systemctl start httpd
# To force to stop
sudo systemctl kill httpd
#
# 3.4.3. Reload a Service
# Reads configuration file again
sudo systemctl reload httpd
#
# 3.4.4. Restart a Service
# Stops and Starts
sudo systemctl restart httpd
#
# 3.4.5. Enable/Disable a Service
sudo systemctl enable httpd
sudo systemctl disable httpd

4. OpenSuse Leap 15.x

# - As far as I know, OpenSuse Leap is binary compatible with Suse Linux. So 
# anything works in OpenSuse, must work in Suse too.
#-- 4.1. Package Management
# Commands require root or sudo.
# 4.1.1. Update Cache
zypper refresh
# 4.1.2. Upgrade Packages
zypper update
# 4.1.3. Install a Package
zypper install apache2
# 4.1.4. Remove a Package
zypper remove apache2
# 4.1.5. Search a Package
zypper search apache2
# 4.1.6. Clean Unused Packages
# Not available as much as I know.
# 4.1.7. Show Package Info
zypper info apache2
# 
#-- 4.2. Network Configuration
# - OpenSuse has a configuration utility, you can configure a lot of things 
# including the network. Usage is easy and intuitive:
sudo yast
# But we will also handle it the classical way.
#
# 4.2.1. Get the name of the network adapter
# - The name of the network adapter will be something like eth0 or eth1, but 
# we need the exact name. 
# - The following command lists the network interface name(s). The one in 
# eth* format should be the name of your network adapter.
ls /sys/class/net
# In any case you cannot get the name, you can try to following command:
ip a
#
# 4.2.2. IP and DNS configuration. 
# I assume that your network adapter name is eth0, otherwise change it. 
# Change IP address:
sudo nano /etc/sysconfig/network/ifcfg-eth0
# File contents will be like below
BOOTPROTO='static'
STARTMODE='auto'
IPADDR='192.168.0.248'
NETMASK='255.255.255.0'
# Change Routes:
sudo nano /etc/sysconfig/network/routes
# File contents will be like below
default 192.168.0.1 - -
# Change DNS Addresses:
sudo nano /etc/resolv.conf
# File contents will be like below
nameserver 192.168.0.1
nameserver 8.8.8.8
#
# 4.2.3. Restart Network Adapter
sudo ifdown eth0 && sudo ifup eth0
#
#-- 4.3. Installing LAMP Stack
# 4.3.1. Install packages
sudo zypper -n install apache2 mariadb php8 php8-cli php8-mysql \
    apache2-mod_php8 mariadb
#
# 4.3.2. Enable and Start Apache and Mariadb
sudo systemctl enable apache2
sudo systemctl start apache2
sudo systemctl enable mariadb
sudo systemctl start mariadb
#
# 4.3.3. Test
# - You can use the test scenario at 1.3.2 to test OpenSuse LAMP stack. Just 
# remember, default web site directory is /srv/www/htdocs/ in OpenSuse.
#
#-- 4.4. Service Management
# - OpenSUSE does not enable and start services by default.
#
# 4.4.1. Status of a Service
systemctl status apache2
# 
# 4.4.2. Start/Stop a Service
sudo systemctl stop apache2
sudo systemctl start apache2
# To force to stop
sudo systemctl kill apache2
#
# 4.4.3. Reload a Service
# Reads configuration file again
sudo systemctl reload apache2
#
# 4.4.4. Restart a Service
# Stops and Starts
sudo systemctl restart apache2
#
# 4.4.5. Enable/Disable a Service
sudo systemctl enable apache2
sudo systemctl disable apache2

5. Alpine Linux 3.17 & 3.18

#-- 5.1. Package Management
# Commands require root or sudo.
# 5.1.1. Update Cache
apk update
# 5.1.2. Upgrade Packages
apk upgrade
# 5.1.3. Install a Package
apk add apache2
# 5.1.4. Remove a Package
apt del apache2
# 5.1.5. Search a Package
apk search apache2
# 5.1.6. Clean Unused Packages
# Not available as much as I know.
# 5.1.7. Show Package Info
apk info apache2
# 
#-- 5.2. Network Configuration
# 5.2.1. Get the name of the network adapter
# - The name of the network adapter will be something like eth0, but we need 
# the exact name. 
# - The following command lists the network interface name(s). The one in 
# eth* format should be the name of your network adapter.
ls /sys/class/net
# In any case you cannot get the name, you can try to following command:
ip a
#
# 5.2.2. IP and DNS Configuration
# - I assume that your network adapter name is eth0, otherwise change it. 
# - Change IP address and Gateway:
sudo nano /etc/network/interfaces
# File contents will be like below
auto lo
iface lo inet loopback
#auto eth0
#iface eth0 inet dhcp
auto eth0
iface eth0 inet static
        address 192.168.0.247/24
        gateway 192.168.0.1
        hostname alpine
# Change DNS Addresses:
sudo nano /etc/resolv.conf
# File contents will be like below
nameserver 192.168.0.1
nameserver 8.8.8.8
#
# 5.2.3. Restart Network Adapter
sudo ifdown eth0 && sudo ifup eth0
#
#-- 5.3. Installing LAMP Stack
# 5.3.1. Install Packages
sudo apk add apache2 php php-mysqli php-apache2 mariadb mariadb-client
#
# 5.3.2. Enable Apache
sudo rc-update add apache2 default
sudo rc-service apache2 restart
#
# 5.3.3. Initialize and Enable Mariadb
sudo mysql_install_db --user=mysql --datadir=/var/lib/mysql
sudo rc-update add mariadb default
sudo rc-service mariadb start
#
# 5.3.4. Test
# - You can use the test scenario at 1.3.2 to test Alpine Linux LAMP stack. 
# Just remember, default web site directory is /var/www/localhost/htdocs in 
# Alpine.
#
#-- 5.4. Service Management
# Alpine Linux uses OpenRC as the init system. 
# 5.4.1. Status of a Service
rc-service apache2 status
# 
# 5.4.2. Start/Stop a Service
sudo rc-service apache2 stop
sudo rc-service apache2 start
#
# 5.4.3. Reload a Service
# Reads configuration file again
sudo rc-service apache2 reload
#
# 5.4.4. Restart a Service
# Stops and Starts
sudo rc-service apache2 restart
#
# 5.4.5. Enable/Disable a Service
sudo rc-update add apache2 default
sudo rc-update del apache2 default

6. Devuan 5 & 4

# - Devuan is a derivative of Debian without systemd. Devuan 5 & 4 is based 
# on Debian 12 & 11.
#-- 6.1. Package Management
# Commands require root or sudo.
# 6.1.1. Update Cache
apt update
# 6.1.2. Upgrade Packages
apt upgrade
# 6.1.3. Install a Package
apt install apache2
# 6.1.4. Remove a Package
apt remove apache2
# 6.1.5. Search a Package
apt search apache2
# 6.1.6. Clean Unused Packages
apt autoremove
# 6.1.7. Show Package Info
apt show apache2
# 
#-- 6.2. Network Configuration
# 6.2.1. Get the name of the network adapter
# - The name of the network adapter will be something like enp0s3, but we 
# need the exact name. 
# - The following command lists the network interface name(s). The one in 
# eth* format should be the name of your network adapter.
ls /sys/class/net
# In any case you cannot get the name, you can try to following command:
ip a
#
# 6.2.2. IP configuration. 
sudo nano /etc/network/interfaces
# I assume that your network adapter name is eth0, otherwise change it.
# Fill the file like below (change to your IP addresses)
auto eth0
iface eth0 inet static
address 192.168.0.3/24
broadcast 192.168.0.255
network 192.168.0.0
gateway 192.168.0.1
# If you want to use DHCP, fill the file as below
auto eth0
iface eth0 inet dhcp
# 
# 6.2.3. DNS Addresses
sudo nano /etc/resolv.conf
# Add your DNS addresses as below
nameserver 46.196.235.35
nameserver 178.233.140.110
nameserver 46.197.15.60
#
# 6.2.4. Restart Network Adapter
# Assuming your network adapter name is enp0s3
sudo ifdown eth0 && sudo ifup eth0
# - If you are connecting through SSH, your connection would break up. You 
# need to connect with the new IP again.
#
#-- 6.3. Installing LAMP Stack
# 6.3.1. Install packages
sudo apt update
sudo apt install --yes apache2 mariadb-server php libapache2-mod-php php-mysql
# - This is all we need actually. But if you are like me, that is you have 
# to see it to believe it; you are going to want to test it. So let's test 
# it.
#
# 6.3.2. Test LAMP
# - You can use the test scenario at 1.3.2 to test Alpine Linux LAMP stack. 
# Just remember, default web site directory is /var/www/localhost/htdocs in 
# Alpine.
#
#-- 6.4. Service Management
# - Conventionally, when a package with a service is installed on Debian, it
# is enabled and started by default.
#
# - At Devuan installation, user can choose from 3 init systems:
# sysvinit (default option), runit, or OpenRC. 
# 
# At this tutorial, I assume our Devuan server has sysvinit system.
#
# 6.4.1. Status of a Service
sudo service apache2 status 
# 
# 6.4.2. Start/Stop a Service
sudo service apache2 stop
sudo service apache2 start
#
# 6.4.3. Reload a Service
# Reads configuration file again
sudo service apache2 reload
#
# 6.4.4. Restart a Service
# Stops and Starts
sudo service apache2 restart
#
# 6.4.5. Enable/Disable a Service
sudo update-rc.d apache2 defaults
sudo update-rc.d apache2 remove