
-
Tired of looking for all pieces of the puzzle yourself?
-
Tired of fighting through an endless djungle of (obsolete) HowTos and Information
just to discover that you only needed a small piece of all that information
maybe because most of it is written for big infrastructures like Facebook
instead for a common environment? -
Tired of trying out every tool yourself
and just want to know which are the tried-and-true ones?

Then maybe this book could be for you.
- Pragmatic solutions, tips, tricks and tools for common SysAdmin work
- Written from the Admin for the Admin
During my career I wished there was such a book.
There was none, so I write it myself:a) to use it as my own reference
b) to give back what I learned from others and my own experience
Target Audience
- Basic knowledge with the CLI and some SysAdmin experience
What is a sysadmin ?
"Aside from the rigors of setting up all the usual software and hardware,
your primary job as a sysadmin is to find solutions.There will be times when you encounter a problem outside your job description,
and it may not even be possible for you to fix it, but it'll be up to you to find a workaround."
What is a pragmatic one ?
Setting up and maintaining all these solutions
in the most efficient (hopefully also elegant) way
with minimal overhead (progressive enhancement design principle)
so that you have time to improve and learn the other new stuff-- swick
progressive enhancement design principle:
The "progressive enhancement" design principle
requires minimal functionality using what is available
and progressively upgrading based on what is detected-- rwxrob
Debian Packaging
-
There are countless (often deprecated) tutorials
and different variants about how to create a Debian package -
Quite a difficult djungle to fight through even with a Machete
only to discover that from all that information you only need a small amount. -
Most HowTos start with Getting the Upstream Tarball
but most of the time you don't have or need this. -
Very often you only have a shell skript, binary or JAR file or something similar
which you just want to get into a package
so that you can take advantage of the system's package manager and not bypass it. -
What follows is a guide to quickly create packages with some optional variants.
-
You should always make sure, that a package is in good shape, but applying all the rules
of the Debian Policy would be overkill (Remember: We are pragmatic here)If you want to get your package into Debian,
then of course you should follow their advice and policies...
Creating
There are many ways to create Debian packages.
I show you the standard way with some variants which are also pragmatic.
The Standard Way
Install necessary tools
apt-get install build-essential debhelper devscripts
List files
find ~/packaging/foo/ -type f | sort
/home/swick/packaging/foo/debian/changelog
/home/swick/packaging/foo/debian/control
/home/swick/packaging/foo/debian/install
/home/swick/packaging/foo/debian/rules
/home/swick/packaging/foo/foo
~/packaging/foo/foo
#!/usr/bin/env bash
echo "foo"
~/packaging/foo/debian/control
Source: foo
Section: utils
Priority: optional
Maintainer: Sven Wick <sven.wick@gmx.de>
Build-Depends: debhelper-compat (= 12)
Standards-Version: 4.6.0
Homepage: https://github.com/foo/
Package: foo
Architecture: all
Depends: ${misc:Depends}
Description: short description for foo
Longer description with more information
.
and a second paragraph
~/packaging/foo/debian/rules
#!/usr/bin/make -f
%:
dh $@
- The rules file is a Makefile and MUST be executable ( chmod +x )
- The line with dh MUST be indented with a TAB (not spaces)
~/packaging/foo/debian/install
foo usr/bin
~/packaging/foo/debian/changelog
foo (0.1-1) unstable; urgency=medium
* Initial release
-- Sven Wick <sven.wick@gmx.de> Fri, 17 Dec 2021 00:29:27 +0100
cd ~/packaging/foo
dpkg-buildpackage -uc -us
dpkg-deb -c ~/packaging/foo_0.1-1_all.deb
drwxr-xr-x root/root 0 2021-12-17 00:29 ./
drwxr-xr-x root/root 0 2021-12-17 00:29 ./usr/
drwxr-xr-x root/root 0 2021-12-17 00:29 ./usr/bin/
-rwxr-xr-x root/root 34 2021-12-17 00:29 ./usr/bin/foo
drwxr-xr-x root/root 0 2021-12-17 00:29 ./usr/share/
drwxr-xr-x root/root 0 2021-12-17 00:29 ./usr/share/doc/
drwxr-xr-x root/root 0 2021-12-17 00:29 ./usr/share/doc/foo/
-rw-r--r-- root/root 134 2021-12-17 00:29 ./usr/share/doc/foo/changelog.Debian.gz
dpkg-deb -I ~/packaging/foo_0.1-1_all.deb
new Debian package, version 2.0.
size 1172 bytes: control archive=524 bytes.
281 bytes, 12 lines control
118 bytes, 2 lines md5sums
Package: foo
Version: 0.1-1
Architecture: all
Maintainer: Sven Wick <sven.wick@gmx.de>
Installed-Size: 9
Section: utils
Priority: optional
Homepage: https://github.com/foo/
Description: short description for foo
Longer description with more information
.
and a second paragraph
Create a little helper
Let's create a little script which creates the minimum of files we need for a package.
Works well if you just want to package a bunch of files
mkdir -p ~/packaging/mkdeb/
~/packaging/mkdeb/mkdeb
#!/usr/bin/env bash
#
# Usage
#
if [[ $1 == "-h" ]] || [[ $1 == "--help" ]]; then
echo
echo " mkdeb [package_name] (default: basename of \$PWD)"
echo
exit
fi
TAB="$(printf '\t')"
#
# Package name
#
if [[ -z ${1} ]]; then
PKG=$(basename ${PWD})
else
PKG=${1}
fi
#
# Email
#
if [[ ${DEBEMAIL} == *@* ]]; then
EMAIL=${DEBEMAIL}
else
EMAIL="${USER}@${HOSTNAME}"
fi
#
# Fullname
#
NAME=$(getent passwd ${USER} | awk -F: '{print $5}')
if [[ ${NAME} =~ [0-9a-zA-Z] ]]; then
FULL_NAME=${NAME}
else
FULL_NAME=${USER}
fi
#
# debian/
#
if [[ -d debian ]]; then
echo "There is already a debian folder"
exit
fi
echo
echo "Creating debian/"
mkdir debian
#
# debian/rules
#
echo "Creating debian/rules"
cat << EOF > debian/rules
#!/usr/bin/make -f
%:
${TAB}dh \$@
EOF
chmod +x debian/rules
#
# debian/install
#
echo "Creating debian/install"
cat << EOF > debian/install
${PKG} usr/bin
EOF
#
# debian/changelog
#
echo "Creating debian/changelog"
cat << EOF > debian/changelog
${PKG} (0.1-1) unstable; urgency=medium
* Initial release
-- ${FULL_NAME} <${EMAIL}> $(date "+%a, %d %b %Y %T %z")
EOF
#
# debian/control
#
echo "Creating debian/control"
cat << EOF > debian/control
Source: ${PKG}
Section: utils
Priority: optional
Maintainer: ${FULL_NAME} <${EMAIL}>
Build-Depends: debhelper-compat (= 12)
Standards-Version: 4.6.0
Homepage: https://${PKG}.de
Package: ${PKG}
Architecture: all
Depends: \${misc:Depends}
Description: short description of ${PKG}
Long description of ${PKG}
EOF
You could use this shell script as is
but of course we make a package out of it
~/packaging/mkdeb/debian/control
Source: mkdeb
Section: utils
Priority: optional
Maintainer: Sven Wick <sven.wick@gmx.de>
Build-Depends: debhelper-compat (= 12)
Standards-Version: 4.6.0
Homepage: https://vaporup.github.io/books/the-pragmatic-sysadmin
Package: mkdeb
Architecture: all
Depends: bash
Description: quickly create the files for a deb package
mkdeb creates the minimum of files
to quickly prepare a Debian package
~/packaging/mkdeb/debian/install
mkdeb usr/bin
~/packaging/mkdeb/debian/changelog
mkdeb (0.1-1) unstable; urgency=medium
* Initial release
-- Sven Wick <sven.wick@gmx.de> Sun, 12 Dec 2021 02:14:45 +0100
~/packaging/mkdeb/debian/rules
#!/usr/bin/make -f
%:
dh $@
- The rules file is a Makefile and MUST be executable ( chmod +x )
- The line with dh MUST be indented with a TAB (not spaces)
cd ~/packaging/mkdeb
dpkg-buildpackage -uc -us
Variants
Now some variants if for some reason the standard way is not possible.
Variant 1
apt-get install equivs
mkdir -p ~/packaging/foo/
~/packaging/foo/foo
#!/usr/bin/env bash
echo "foo"
~/packaging/foo/control
Package: foo
Version: 0.1-1
Architecture: all
Maintainer: Sven Wick <sven.wick@gmx.de>
Homepage: https://github.com/foo/
Files: foo usr/bin
Description: short description for foo
equivs-build ~/packaging/foo/control
dpkg-deb -c foo_0.1-1_all.deb
drwxr-xr-x root/root 0 2021-12-17 01:21 ./
drwxr-xr-x root/root 0 2021-12-17 01:21 ./usr/
drwxr-xr-x root/root 0 2021-12-17 01:21 ./usr/bin/
-rwxr-xr-x root/root 34 2021-12-17 01:21 ./usr/bin/foo
drwxr-xr-x root/root 0 2021-12-17 01:21 ./usr/share/
drwxr-xr-x root/root 0 2021-12-17 01:21 ./usr/share/doc/
drwxr-xr-x root/root 0 2021-12-17 01:21 ./usr/share/doc/foo/
-rw-r--r-- root/root 741 2021-12-17 01:21 ./usr/share/doc/foo/README.Debian
-rw-r--r-- root/root 131 2021-12-17 01:21 ./usr/share/doc/foo/changelog.Debian.gz
-rw-r--r-- root/root 936 2021-12-17 01:21 ./usr/share/doc/foo/copyright
dpkg-deb -I foo_0.1-1_all.deb
new Debian package, version 2.0.
size 2176 bytes: control archive=556 bytes.
232 bytes, 10 lines control
246 bytes, 4 lines md5sums
Package: foo
Version: 0.1-1
Architecture: all
Maintainer: Sven Wick <sven.wick@gmx.de>
Installed-Size: 11
Section: misc
Priority: optional
Multi-Arch: foreign
Homepage: https://github.com/foo/
Description: short description for foo
Variant 2
This variant uses the same package format as Arch Linux,
so your source package very likely also works for Arch-based Distros
mkdir -p ~/packaging/foo/
~/packaging/foo/foo
#!/usr/bin/env bash
echo "foo"
chmod +x ~/packaging/foo/foo
~/packaging/foo/PKGBUILD
# Maintainer: Sven Wick <sven.wick@gmx.de>
pkgname=foo
pkgver=0.1
pkgrel=1
pkgdesc="short description for foo"
arch=("any")
url="https://github.com/foo/"
depends=("bash")
changelog=
package() {
mkdir -p $pkgdir/usr/bin/
cp ../foo $pkgdir/usr/bin/
}
cd ~/packaging/foo/
makedeb
dpkg-deb -c foo_0.1-1_all.deb
drwxr-xr-x root/root 0 2021-12-17 01:33 ./usr/
drwxr-xr-x root/root 0 2021-12-17 01:33 ./usr/bin/
-rw-r--r-- root/root 34 2021-12-17 01:33 ./usr/bin/foo
dpkg-deb -I foo_0.1-1_all.deb
new Debian package, version 2.0.
size 650 bytes: control archive=270 bytes.
193 bytes, 8 lines control
Package: foo
Version: 0.1-1
Description: short description for foo
Architecture: all
Maintainer: Sven Wick <sven.wick@gmx.de>
Homepage: https://github.com/foo/
Installed-Size: 14
Depends: bash
More Variants
- https://fpm.readthedocs.io
# https://stackoverflow.com/a/17413767 export GEM_HOME=$HOME/.local/gems gem install fpm ~/.local/gems/bin/fpm - https://antumdeluge.github.io/debreate-web/
- Packaging Applications via JDeb
- https://packages.ubuntu.com/python3-stdeb
With minimal Tools
- This is the most basic variant with minimal tools involved (
quick-n-dirty). - You can go even more low-level with
arbut that is not pragmatic anymore... - This variant should only be used if all other variants are not possible...
Install necessary tools
apt-get install fakeroot
fakeroot is needed so that the files in the package are owned by "root"
and not by the user who builds the package.root (UID 0) exists on every linux system, but the current user's ID very likely does not
mkdir -p ~/packaging/foo/DEBIAN
This is the only time the DEBIAN folder needs to be in uppercase
since we use some lower level tools which still expect this...Tools like debhelper and others use the lowercase variant.
mkdir -p ~/packaging/foo/usr/bin/
~/packaging/foo/usr/bin/foo
#!/usr/bin/env bash
echo "foo"
chmod +x ~/packaging/foo/usr/bin/foo
~/packaging/foo/DEBIAN/control
Package: foo
Version: 0.1-1
Architecture: all
Maintainer: Sven Wick <sven.wick@gmx.de>
Description: short description for foo
fakeroot dpkg-deb --build ~/packaging/foo/
dpkg-deb -c ~/packaging/foo.deb
drwxr-xr-x root/root 0 2021-12-17 01:01 ./
drwxr-xr-x root/root 0 2021-12-17 01:01 ./usr/
drwxr-xr-x root/root 0 2021-12-17 01:01 ./usr/bin/
-rwxr-xr-x root/root 34 2021-12-17 01:01 ./usr/bin/foo
dpkg-deb -I ~/packaging/foo.deb
new Debian package, version 2.0.
size 740 bytes: control archive=304 bytes.
126 bytes, 5 lines control
Package: foo
Version: 0.1-1
Architecture: all
Maintainer: Sven Wick <sven.wick@gmx.de>
Description: short description for foo
Testing
To make sure your packages are in good shape
there are some ways to test them:
- debspawn
- DUE
- VM using Snapshots
- piuparts
- lintian
Hosting
To fully integrate your packages
with your system's package manager
provide an APT repo:
-
aptly
- https://packages.debian.org/sid/aptly
- https://www.aptly.info
Prefer
aptlyif possible, since it also supports- Mirroring
- Snapshots
- Multiple versions of a package
-
reprepro
Providing an APT repo with aptly and Apache
To see an working example of this setup:
Install aptly
apt-get install aptly
Create an extra user
adduser dhl
Full Name []: User for APT repo using aptly
Make sure there is enough disk space for all the files
Eventually put the home of this user on a separate mount
Create a GPG Key
Creating a GPG key which signs the files in the APT repo
so apt clients do not complainUsing ed25519 as SSH Key type here, but other types (RSA), work as well
-
Switch to your new user
-
Create the key
dhl@host: gpg --expert --full-generate-key(9) ECC and ECC (1) Curve 25519 0 = key does not expire Real name: APT REPO Email address: dhl@your-domain.com skip password -
Check the new GPG key
gpg --list-secret-keys --keyid-format=long -
Export the new GPG key
gpg --armor --export dhl@your-domain.com > dhl-repo-keyring.asc gpg --export dhl@your-domain.com > dhl-repo-keyring.gpg
Prepare aptly
Example for Ubuntu 20.04 (Focal)
Remember: Do everything as your new aptly user (here dhl)
-
Create repo
aptly repo create -distribution=focal -component=main focal-main -
Import some example package
Can be a .deb (binary package) or .dsc (source package)
aptly repo add focal-main example_1.14.1_amd64.deb aptly repo add focal-main example_1.14.1.dsc -
Publish your packages
Importing a package does not make it available for apt yet.
It is available only after the repo was published.
The following step is only done once to initialize the repo.For
originandlabeluse some unique string which identifiers your repoaptly publish repo \ -architectures=amd64,i386,source \ -origin=some-string-which-identifies-your-repo \ -label=some-string-which-identifies-your-repo focal-mainIf you import more packages, you do:
aptly publish update focal
Providing an APT repo with aptly and Apache
/etc/apache2/sites-available/apt.your-domain.de.conf
<VirtualHost *:80>
ServerName apt.your-domain.de
DocumentRoot /home/dhl/.aptly/public/
<Directory /home/dhl/.aptly/public/>
IndexIgnore HEADER.html
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
Activate
root@host: a2ensite apt.your-domain.de.conf
root@host: systemctl reload apache2
Package Overview
/home/dhl/.aptly/public/HEADER.html
/home/dhl/.aptly/public/packages/index.html
/home/dhl/bin/create-package-list.py
Upload Facility
(Server) SFTP Chroot for Incoming
root@host: mkdir -p /home/dhl/upload/incoming
root@host: chown dhl:dhl /home/dhl/upload/incoming
root@host: chown root:root /home/dhl
/etc/ssh/sshd_config
Match user dhl
ChrootDirectory /home/dhl/upload
#AuthorizedKeysFile /home/dhl/.ssh/authorized_keys
ForceCommand internal-sftp
AllowTCPForwarding no
X11Forwarding no
/home/dhl/bin/import-packages.sh
(Client) dput
Used on the PC who wants to upload packages
apt-get install dput
~/.dput.cf
[your-server-focal]
fqdn = apt.your-server.de
# With different SSH port
#fqdn = apt.your-server.de:35007
incoming = /incoming/focal
method = sftp
login = dhl
allow_unsigned_uploads = 1
progress_indicator = 2
# Allow uploads for UNRELEASED packages
allowed_distributions = .*
Now you can upload packages with dput
dput your-server-focal example_0.1-1.changes
(Client) Optional
You can also just upload a .deb file with FileZilla or similar tools
into the appropriate incoming folder
Automate with Cronjob
crontab of dhl
Bonus
/etc/apache2/sites-available/packages.your-domain.de.conf
<VirtualHost *:80>
ServerName packages.your-domain.de
DocumentRoot /home/dhl/.aptly/public/packages/
<Directory /home/dhl/.aptly/public/packages/>
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
a2ensite packages.your-domain.de.conf
systemctl reload apache2
Update Packages
Debian/Ubuntu
apt-get update
apt-get upgrade
apt-get dist-upgrade
NetBSD
pkgin upgrade
FreeBSD
pkg upgrade
OpenBSD
pkg_add -uvi
sysupgrade
DragonFlyBSD
pkg upgrade
Arch/Manjaro
pacman -Sy archlinux-keyring
pacman -Syu
Fedora/CentOS/Alma
dnf upgrade
Gentoo
emerge --sync
Alpine
apk upgrade
OpenSUSE
zypper refresh
zypper update
- https://www.cyberciti.biz/faq/update-opensuse-linux-software-kernel-command/
- https://en.opensuse.org/images/1/17/Zypper-cheat-sheet-1.pdf
- https://www.linux.com/tutorials/opensuse-package-management-cheat-sheet/
- https://en.opensuse.org/SDB:Zypper_usage
- https://en.opensuse.org/SDB:Starting_YaST
void
xbps-install -Su
Slackware
slackpkg update
slackpkg install-new
slackpkg upgrade-all
slackpkg clean-system
Guix
guix pull
guix install htop
- https://guix.gnu.org/manual/en/html_node/Upgrading-Guix.html
- https://guix.gnu.org/manual/en/html_node/Invoking-guix-pull.html
- https://guix.gnu.org/manual/en/html_node/Package-Management.html#index-packages
nixOS
nixos-rebuild switch --upgrade
- https://nixos.org/manual/nixos/stable/#sec-upgrading
- https://superuser.com/questions/1604694/how-to-update-every-package-on-nixos
Low-Budget Weiterbildung
Tools
- https://codeberg.org/vaporup/tools/src/branch/main/toolothek
- https://github.com/ibraheemdev/modern-unix
- https://zaiste.net/posts/shell-commands-rust
- https://kkovacs.eu/cool-but-obscure-unix-tools
- https://ilya-sher.org/2018/04/10/list-of-json-tools-for-command-line
- https://github.com/burningtree/awesome-json
- Die besten 20 Tools für den Sysadmin
- https://clig.dev