Table of Contents

Verschlüsselter Docker-Server thinc

Siehe ritter.local

Hardware: HP t520 thin client mit 120GB SSD

OS: debian-bookworm

apt update && apt upgrade
apt install \
  vim \
  openssh-server \
  dropbear-initramfs \
  apache2-utils \
  mc \
  rcs \
  rsync \
  swaks \
  ufw \
  inetutils-tools \
  net-tools \
  fuse \
  at \
  samba \
  nullmailer \
  mailutils \
  hdparm \
  sudo \
  golang \
  ethtool \
  hwinfo \
  hdparm \
  pv \
  gdu \
  iw wpasupplicant wireless-tools

springm zur Gruppe sudoers hinzufügen

su -
usermod -aG sudo springm

Achtung: wird erst nach ausloggen wirksam

Netzwerk: *.zalmoxis.aberdoch.de registriert
Boot-Disk verschlüsseln

ssh passwordless login

ssh-copy-id -i .ssh/id_ecdsa.pub 192.168.2.251
ssh zalmoxis
sudo cp ~/.ssh/authorized_keys /root/.ssh

dropbear-initramfs

Entsprechend c't-Artikel luks_verschluesselte_linux-systeme_ueber_ssh_entsperren_c_t_magazin.pdf

Die ssh-public-keys der Benutzer, die das System per ssh entsperren sollen können, liegen in /etc/dropbear/initramfs/authorized_keys (kopieren von hermes…).

Minimum-Inhalt für die Konfigurationsdatei:

bash
#
# Command line options to pass to dropbear(8)
#
DROPBEAR_OPTIONS="-p 20022 -c cryptroot-unlock"

Die .ssh/authorizedkeys von springm nach /root/.ssh kopieren
sudo cp ~springm/.ssh/authorized_keys /root/.ssh

Nach Änderung muss das initramfs aktualisiert werden:

update-initramfs -u

Entsperren mit
ssh -v -p 20022 <rechnername lt. Fritzbox>

Das ganze mit Wifi:
* https://www.marcfargas.com/2017/12/enable-wireless-networks-in-debian-initramfs/
* https://www.dwarmstrong.org/remote-unlock-dropbear/
===== Wifi in initramfs einschalten =====
Wird gebraucht um später die Platte nach dem Booten über WLAN entschlüsseln zu können.

Rezept von https://www.marcfargas.com/2017/12/enable-wireless-networks-in-debian-initramfs/ ( enable_wireless_networks_in_debian_initramfs_marcfargas.com.pdf )

wlan0 beim Boot bekanntmachen:
<file bash /etc/default/grub>

GRUBCMDLINELINUX=“net.ifnames=0 ip=:::::wlan0:dhcp”

</file>

Benötigte Module für das initramfs
<file bash /etc/initramfs-tools/modules>
rtlwifi
rtl8xxxu
mac80211
usbcore
rtl8192eu_nic.bin
</file>

<file bash /etc/initramfs-tools/scripts/init-premount/aenablewireless>
#!/bin/sh
PREREQ=“”
prereqs()
{
echo “$PREREQ”
}

case $1 in
prereqs)
prereqs
exit 0
;;
esac

. /scripts/functions

AUTHLIMIT=30
INTERFACE=“wlan0”
alias WPACLI=“/sbin/wpa
cli -p /tmp/wpa_supplicant -i $INTERFACE ”

logbeginmsg “Starting WLAN connection”
### mws
rmmod rtl8xxxu
modprobe rtl8xxxu
sleep 2
### end mws
/sbin/wpasupplicant -i $INTERFACE -c /etc/wpasupplicant.conf -P /run/initram-wpasupplicant.pid -B -f /tmp/wpasupplicant.log

# Wait for AUTHLIMIT seconds, then check the status
limit=${AUTH
LIMIT}

echo -n “Waiting for connection (max ${AUTHLIMIT} seconds)”
while [ $limit -ge 0 -a WPACLI status | grep wpa_state != “wpa
state=COMPLETED” ]
do
sleep 1
echo -n “.”
limit=expr $limit - 1
done
echo “”

if [ WPACLI status | grep wpa_state != “wpastate=COMPLETED” ]; then
ONLINE=0
log
failuremsg “WLAN offline after timeout”
panic
else
ONLINE=1
log
success_msg “WLAN online”
fi

configure_networking
</file>

<file bash /etc/initramfs-tools/scripts/local-bottom/kill_wireless>
#!/bin/sh
PREREQ=“”
prereqs()
{
echo “$PREREQ”
}

case $1 in
prereqs)
prereqs
exit 0
;;
esac

echo “Killing wpasupplicant so the system takes over later.”
kill cat /run/initram-wpa_supplicant.pid
</file>

Eintrag in /etc/network/interfaces
<file bash /etc/network/interfaces>

auto wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa
supplicant/wpa_supplicant.conf

</file>

Passwort in /etc/wpasupplicant/wpasupplicant.conf
<file bash /etc/wpasupplicant/wpasupplicant.conf>
ctrlinterface=/run/wpasupplicant
update_config=1

network={
ssid=“Your ESSID”
psk=langundverschlüsselt
}
</file>
Die wpasupplicant.conf findet sich identisch an 3 verschiedenen Stellen :(
* /etc/wpa
supplicant.conf
* /etc/wpasupplicant/wpasupplicant.conf
* /etc/initramfs-tools/wpa_supplicant.conf

==== ESSID und/oder Wifi-Passwort ändern ====

wpapassphrase “Eleven Ways” wifipassword » /etc/wpasupplicant.conf
/etc/wpa_supplicant.conf editieren und alte Konfiguration auskommentieren

rm /etc/wpasupplicant/wpasupplicant.conf
cp -l /etc/wpasupplicant.conf /etc/wpasupplicant/wpasupplicant.conf
rm /etc/initramfs-tools/wpa
supplicant.conf
cp -l /etc/wpasupplicant.conf /etc/initramfs-tools/wpasupplicant.conf
Kontrollieren auf Gleichheit mit
sum $(find / -name wpa_supplicant.conf -not -path “/backupdisk”)
Dann initramfs neu erstellen
update-initramfs -u -k all


==== Wlan als Dienst starten ====
Nach dem Entsperren wird das Wlan über einen Dienst gestartet ( https://www.skerit.com/en/configure-wifi-on-minimal-debian-11-server )
configure_wifi_on_a_minimal_debian_11_server_skeritcom.pdf

<file bash /etc/systemd/system/dhclient.service>
[Unit]
Description=DHCP Client
Before=network.target
After=wpa_supplicant.service

[Service]
Type=forking
ExecStart=/sbin/dhclient wlan0 -v
ExecStop=/sbin/dhclient wlan0 -r
Restart=always

[Install]
WantedBy=multi-user.target
</file>
Starten mit
systemctl enable dhclient
systemctl restart wpa_supplicant
systemctl restart networking
Kontrollieren mit
ip a

===== ufw =====
ufw allow proto tcp from any to any port 22,80,139,443,445
ufw allow proto udp from any to any port 137,138
ufw enable

===== email senden =====
Emails sollen für Statusmails versendet werden können. Nullmailer ist einfach, 3 Konfigurationsdateien stehen in
/etc/nullmailer
Links
* https://wiki.debian.org/nullmailer
* https://dan.langille.org/2013/10/16/using-nullmailer-instead-of-a-full-blown-mail-server/

===== debian packages sichern (und später wiederherstellen) =====
von https://unix.stackexchange.com/questions/79125/reinstalling-all-debian-packages

dpkg –get-selections | grep -v deinstall | awk '{print $1}' | awk '$1=$1' ORS=' ' > /etc/installeddebs.txt

kommt in die /etc/crontab.
Restore erfolgt dann mit
apt-get clean && apt-get update && apt-get install –reinstall $(/etc/installed
debs.txt)
===== docker =====
from https://computingforgeeks.com/how-to-install-docker-on-debian-12-bookworm/
sudo apt install -y \
lsb-release \
gnupg2 \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg –dearmor -o /etc/apt/trusted.gpg.d/debian.gpg
add-apt-repository “deb [arch=$(dpkg –print-architecture)] https://download.docker.com/linux/debian $(lsb_release -cs) stable”
apt update
apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
usermod -aG docker springm
newgrp docker


systemctl status docker
docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; preset: enabl>
Active: active (running) since Mon 2023-08-28 15:07:09 CEST; 27s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 9365 (dockerd)
Tasks: 9
Memory: 29.0M
CPU: 1.391s
CGroup: /system.slice/docker.service
└─9365 /usr/bin/dockerd -H fd: –containerd=/run/containerd/cont>

Aug 28 15:07:04 debian-thinc systemd[1]: Starting docker.service - Docker Appli>
Aug 28 15:07:04 debian-thinc dockerd[9365]: time=“2023-08-28T15:07:04.749035874>
Aug 28 15:07:06 debian-thinc dockerd[9365]: time=“2023-08-28T15:07:06.254635497>
Aug 28 15:07:08 debian-thinc dockerd[9365]: time=“2023-08-28T15:07:08.360733123>
Aug 28 15:07:08 debian-thinc dockerd[9365]: time=“2023-08-28T15:07:08.565571357>
Aug 28 15:07:08 debian-thinc dockerd[9365]: time=“2023-08-28T15:07:08.566231451>
Aug 28 15:07:09 debian-thinc dockerd[9365]: time=“2023-08-28T15:07:09.476426543>
Aug 28 15:07:09 debian-thinc systemd[1]: Started docker.service - Docker Applic>

docker version
Client: Docker Engine - Community
Version: 24.0.5
API version: 1.43
Go version: go1.20.6
Git commit: ced0996
Built: Fri Jul 21 20:35:35 2023
OS/Arch: linux/amd64
Context: default

Server: Docker Engine - Community
Engine:
Version: 24.0.5
API version: 1.43 (minimum version 1.12)
Go version: go1.20.6
Git commit: a61e2b4
Built: Fri Jul 21 20:35:35 2023
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.6.22
GitCommit: 8165feabfdfe38c65b599c4993d227328c231fca
runc:
Version: 1.1.8
GitCommit: v1.1.8-0-g82f18fe
docker-init:
Version: 0.19.0
GitCommit: de40ad0

==== lazydocker ====
https://github.com/jesseduffield/lazydocker
go install github.com/jesseduffield/lazydocker@latest
mv /root/go /usr/local
ln -s /usr/local/go/bin/lazydocker /usr/local/bin


==== Docker-Dienste ====
=== Traefik ===
=== pihole ===
=== restic-restserver ===
=== resticinfo ===
=== mailserver ===
=== calibre ===







===== Wake-on-Lan =====
* https://wiki.debian.org/WakeOnLan
* https://www.thomas-krenn.com/de/wiki/Wake_on_LAN_unter_Linux
Datei /etc/network/interfaces.d/enp1s0 erzeugen:
auto enp1s0
iface enp1s0 inet dhcp
ethernet-wol g
booten um die Änderung wirksam zu machen.

===== Zeitgesteuert schlafen/aufwachen =====
von https://www.baeldung.com/linux/auto-suspend-wake

Achtung: Mit Verschlüsselung funktioniert nur suspend-to-memory

===== Traefik =====

Traefik ist der router für die Docker-Container. Da alle Dienste nur im LAN zur Verfügung stehen, müssen dafür keine Zertifikate zur Verfügung gestellt werden.

===== pihole =====
<code yaml docker-compose.yml>
# from https://codecaptured.com/blog/self-hosting-pi-hole-with-docker-and-traefik/
# adapted for usage of .env file
version: “3”

services:
pihole:
image: pihole/pihole:latest
containername: pihole
restart: always
ports:
- “53:53/tcp”
- “53:53/udp”
dns:
- 127.0.0.1
- 9.9.9.9
environment:
TZ: 'Europe/Berlin'
WEBPASSWORD: ${WEBPASSWORD}
PIHOLE
DNS: 9.9.9.9;149.112.112.112;1.1.1.1
DNSSEC: 'true'
ServerIP: ${SERVERIP}
VIRTUAL
HOST: ${VIRTUALHOST}
DNSMASQ
LISTENING: all
DHCPACTIVE: ${DHCPACTIVE}
DHCPSTART: ${DHCPSTART}
DHCPEND: ${DHCPEND}
DHCPROUTER: ${DHCPROUTER}
DHCPLEASETIME: ${DHCPLEASETIME}
WEBTHEME: default-dark
PIHOLEDOMAIN: ${PIHOLEDOMAIN}
volumes:
- './services/pihole:/etc/pihole/'
- './services/dnsmasq.d:/etc/dnsmasq.d/'
capadd:
- NET
ADMIN
restart: unless-stopped
networks:
lan: {}
backend:
ipv4address: ${BACKENDIPV4ADDRESS}
labels:
- “traefik.enable=true”
- “traefik.http.routers.pihole.rule=Host(${VIRTUAL_HOST})”
- “traefik.http.services.pihole.loadbalancer.server.port=80”
- “traefik.http.routers.pihole.entrypoints=web”
depends
on:
- dhcphelper

dhcphelper:
image: noamokman/dhcp-helper
containername: dhcp-helper
restart: unless-stopped
network
mode: “host”
command: -s ${BACKENDIPV4ADDRESS}
capadd:
- NET
ADMIN

networks:
backend:
ipam:
config:
- subnet: ${BACKEND_SUBNET}
lan:
external: true
</code>

<code bash [enablelinenumbers=“false”] .env>
PIHOLEDOMAIN=
WEBPASSWORD=
# Actual server IP. Matches DHCP conf file IP
SERVERIP=
# Same as port traefik config
VIRTUAL
HOST=
DHCPACTIVE=
DHCP
START=
DHCPEND=
DHCP
ROUTER=
DHCPLEASETIME=
BACKEND
IPV4ADDRESS=
BACKEND
SUBNET=
</code>
* https://codecaptured.com/blog/self-hosting-pi-hole-with-docker-and-traefik/
* https://github.com/mirdaki/computer-config/blob/blog-pihole/services/local/README.md
* https://jurian.slui.mn/posts/pi-hole-web-interface-behind-traefik/

==== dnscrypt-proxy ====
Vorher die Versionsnummer von https://github.com/DNSCrypt/dnscrypt-proxy/releases holen

cd /opt/ && \
wget https://github.com/DNSCrypt/dnscrypt-proxy/releases/download/2.1.5/dnscrypt-proxy-linux_x86_64-2.1.5.tar.gz && \
tar xvzf dnscrypt-proxy-linuxx8664-2.1.5.tar.gz
cd linux-x86_64/
cp ~springm/dnscrypt-proxy/dnscrypt-proxy.toml .
sudo ./dnscrypt-proxy -service install
sudo ./dnscrypt-proxy -service start


===== Backup =====
Das Backup passiert mit Restic: https://restic.net
Das binary liegt in /usr/local/bin
Backups erfolgen in das Verzeichnis /backupdisk/restic-repo
Das restic-Passwort für das Restic-Repository wird in /root/resticpw gespeichert.

==== Eigenes Backup ====
<code bash /usr/local/sbin/resticbackup.sh>
#!/bin/bash
export RESTIC
REPOSITORY=/backupdisk/restic-repo
export RESTICPASSWORDFILE=/root/resticpw
export RESTICEXCLUDEFILE=/root/restic_exclude
export HOME=/root
/usr/local/bin/restic backup /root /etc /usr/local/bin /usr/local/sbin /home/springm/docker
</code>

Zu starten via cron, ebenso restic forget
==== Restic-Server ====


Der restic-Server läuft in einem docker-Container unter der URL http://resticserver.ritter.local

==== Restic-Info ====
Läuft in einem Docker-Containern. Liest die JSON-Datei aus /var/lib/restic/snapshots.json
/var/lib/restic/snapshots.json wird per inotify bei Änderungen im Verzeichnis /backupdisk/restic-repo/snapshots erzeugt.

Die Informationen stehen unter der URL http://resticinfo.ritter.local zur Verfügung.

=== Erzeugen der /var/lib/restic/snapshots.json ===

Ein inotify-Eintrag auf das snapshots-Verzeichnis im Restic-Repository triggert das Schreiben einer JSON-Zustandsdatei mit dem Befehl

restic snapshots -c –json > /var/lib/restic/snapshots.json

Dieser Befehl ist zusammen mit dem Restic-Passwort und dem Repository in /usr/local/sbin/resticsnapshotsjson.sh niedergelegt:

<code bash /usr/local/sbin/resticsnapshotsjson.sh>
#!/bin/bash
/usr/bin/date » /tmp/resticmonitoring.log
export RESTIC
REPOSITORY=/backupdisk/restic-repo
export RESTICPASSWORDFILE=/root/resticpw
export HOME=/root
#/usr/local/bin/restic snapshots -c –json
/usr/local/bin/restic snapshots -c –json > /var/lib/restic/snapshots.json 2»/tmp/restic_monitoring.log
</code>

Die Automatisierung erfolgt über einen systemd-Service (vgl. https://www.putorius.net/systemd-path-units.html)

<file bash /etc/systemd/system/restic-snapshots-mon.path>
[Unit]
Description=“Monitor restic snapshots for changes”

[Path]
PathModified=/backupdisk/restic-repo/snapshots/
Unit=restic-snapshots-mon.service

[Install]
WantedBy=multi-user.target
</file>

<file bash /etc/systemd/system/restic-snapshots-mon.service>
[Unit]
Description=“Recreate /var/lib/restic/snapshots.json when snapshots have changed”

[Service]
ExecStart=/usr/local/sbin/resticsnapshotsjson.sh
</file>

<file bash /usr/local/sbin/restic-json.sh>
#!/bin/bash
/usr/bin/date » /tmp/resticmonitoring.log
export RESTIC
REPOSITORY=/backupdisk/restic-repo
export RESTICPASSWORDFILE=/root/resticpw
export HOME=/root
/usr/local/bin/restic snapshots -c –json > /var/lib/restic/snapshots.json 2»/tmp/restic_monitoring.log
</file>

Analysieren mit systemd-analyze verify /etc/systemd/system/restic-snapshots-mon*
Starten mit systemctl start restic-snapshots-mon.path
Beim Systemstart hochfahren mit systemctl enable restic-snapshots-mon.path
Status überprüfen mit systemctl status restic-snapshots-mon.path
Log-Einträge ansehen mit journalctl -u restic-snapshots-mon.path

Erzeugen der /var/lib/restic/snapshots.json beim booten durch einen cron-eintrag
@reboot root /usr/local/sbin/resticsnapshotsjson.sh
==== Backuptree für Kontrolle und Restore ====
Backups werden readonly im Verzeichnis /restic_restore zur Verfügung gestellt.
Der restic-mount-Prozess wird täglich zu einer festgesetzten Zeit gekillt und neu gestartet, damit die neuesten Änderungen sichtbar werden.
/etc/crontab ruft regelmäßig folgendes Script auf:

<code bash /usr/local/sbin/mountresticrestore.sh>
#!/bin/bash
#chmod 755 /restic-restore
/usr/bin/umount /restic-restore
sleep 3
/usr/local/bin/restic -r /backupdisk/restic-repo/ \
-p /root/resticpw \
mount \
–allow-other \
–no-default-permissions \
–no-lock \
/restic-restore

</code>

Links:
* https://wiki.debian.org/Samba/ServerSimple
* https://www.thomas-krenn.com/en/wiki/Simple_Samba_Shares_in_Debian
* https://superuser.com/questions/1069044/how-to-set-up-anonymous-read-only-samba-shares