--- /dev/null
+# connectivity: ifupdown seems necessary everyhwere, isc-dhcp-client
+# unpredictably so
+ifupdown
+isc-dhcp-client
+# git for the setup directory; cloning works with ca-certificates
+ca-certificates
+git
+# to avoid constant warnings about no locale being found
+locales
+# extremely useful for basic network debugging; missed these more than once in an emergency
+netcat
+iputils-ping
--- /dev/null
+# so we can login at all …
+openssh-server
+# firewalling
+nftables
+# We want to be able to use ALL our servers as borg backup destinations.
+borgbackup
--- /dev/null
+#!/bin/sh
+# Copy files in argument-selected subdirectories of $1 to subdirectories
+# of $2 (which may be an empty string), e.g. with $1 of "etc_files", $2
+# of "" and $3 of "all", copy files below etc_files/all such as
+# etc_files/all/etc/foo/bar to equivalent locations below / such as
+# /etc/foo/bar. Create directories as necessary. Multiple arguments after
+# $3 are possible.
+#
+# CAUTION: This removes original files at the affected paths.
+set -e
+
+if [ "$#" -lt 3 ]; then
+ echo 'Need arguments: source root, target root, modules.'
+ false
+fi
+source_root="$1"
+target_root="$2"
+shift 2
+
+for target_module in "$@"; do
+ mkdir -p "${source_root}/${target_module}"
+ cd "${source_root}/${target_module}"
+ for path in $(find . -type f); do
+ target_path="${target_root}"$(echo "${path}" | cut -c2-)
+ source_path=$(realpath "${path}")
+ dir=$(dirname "${target_path}")
+ mkdir -p "${dir}"
+ cp "${source_path}" "${target_path}"
+ done
+done
# Dependencies: ssh, scp, sshpass, ~/.ssh/id_rsa.pub, properly
# configured sshd_config file in reach.
set -e
-set -x
# Location of an sshd_config with "PermitRootLogin no" and
# "PasswordAuthentication no".
--- /dev/null
+#!/bin/sh
+# Walks through the package names in the argument-selected files of
+# apt-mark/ and ensures the respective packages are installed.
+#
+# Ignores anything in an apt-mark/ file after the last newline.
+set -e
+
+config_tree_prefix="${HOME}/config/bullseye"
+aptmark_dir="${config_tree_prefix}/apt-mark"
+
+for target in "$@"; do
+ path="${aptmark_dir}/${target}"
+ # TODO: continue if file at $path not found, to get rid of dummy files
+ cat "${path}" | while read line; do
+ echo "$line"
+ if [ ! $(echo "${line}" | cut -c1) = "#" ]; then
+ DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::=--force-confold install "${line}"
+ fi
+ done
+done
--- /dev/null
+#!/bin/sh
+# This script removes all Debian packages that are not of Priority
+# "required" or not depended on by packages of priority "required"
+# or not listed in the argument-selected files of apt-mark/.
+set -e
+
+config_tree_prefix="${HOME}/config/bullseye"
+aptmark_dir="${config_tree_prefix}/apt-mark"
+
+dpkg-query -Wf '${Package} ${Priority}\n' | grep ' required' | sed 's/ required//' > /tmp/list_white_unsorted
+for target in "$@"; do
+ path="${aptmark_dir}/${target}"
+ cat "${path}" | while read line; do
+ if [ ! $(echo "${line}" | cut -c1) = "#" ]; then
+ echo "${line}" >> /tmp/list_white_unsorted
+ fi
+ done
+done
+sort /tmp/list_white_unsorted > /tmp/list_white
+dpkg-query -Wf '${Package}\n' > /tmp/list_all_packages
+sort /tmp/list_all_packages > /tmp/foo
+mv /tmp/foo /tmp/list_all_packages
+comm -3 /tmp/list_all_packages /tmp/list_white > /tmp/list_black
+apt-mark auto `cat /tmp/list_black`
+DEBIAN_FRONTEND=noninteractive apt-get -y --purge autoremove
+rm /tmp/list_all_packages /tmp/list_white_unsorted /tmp/list_white /tmp/list_black
+
+# Somehow, auto-mounts get undone by all of this, so re-mount /etc/fstab.
+# TODO: Find out why.
+mount -a
--- /dev/null
+#!/bin/sh
+# Sets hostname and optionally FQDN.
+#
+# Calls hostname, writes to /etc/hostname and /etc/hosts. For /etc/hosts
+# writing follows recommendations from Debian manual at
+# <https://www.debian.org/doc/manuals/debian-reference/ch05.en.html>
+# (section "The hostname resolution") on how to map hostname and possibly
+# FQDN to a permanent IP if present (we assume here any non-private IP
+# and non-loopback IP returned by hostname -I to fulfill that criterion
+# on our systems) or to 127.0.1.1 if not. On the reasoning for separating
+# localhost and hostname mapping to different IPs, see
+# <https://unix.stackexchange.com/a/13087>.
+#
+# Ignores IPv6s.
+set -e
+
+hostname="$1"
+fqdn="$2"
+if [ "${hostname}" = "" ]; then
+ echo "Need hostname as argument."
+ false
+fi
+echo "${hostname}" > /etc/hostname
+hostname "${hostname}"
+
+final_ip="127.0.1.1"
+for ip in $(hostname -I); do
+ if [ $(echo "${ip}" | grep ':' | wc -l) -eq 1 ]; then
+ continue
+ fi
+ range_1=$(echo "${ip}" | cut -d "." -f 1)
+ range_2=$(echo "${ip}" | cut -d "." -f 2)
+ if [ "${range_1}" -eq 127 ]; then
+ continue
+ elif [ "${range_1}" -eq 10 ]; then
+ continue
+ elif [ "${range_1}" -eq 172 ]; then
+ if [ "${range_2}" -ge 16 ] && [ "${range_2}" -le 31 ]; then
+ continue
+ fi
+ elif [ "${range_1}" -eq 192 ]; then
+ if [ "${range_2}" -eq 168 ]; then
+ continue
+ fi
+ fi
+ final_ip="${ip}"
+done
+
+echo "127.0.0.1 localhost.localdomain localhost" > /etc/hosts
+echo "${final_ip} ${fqdn} ${hostname}" >> /etc/hosts
--- /dev/null
+#!/bin/sh
+set -e
+
+# Provide maximum input for set_hostname_and_fqdn.sh.
+if [ "$#" -lt 2 ]; then
+ echo 'Need at least two arguments (hostname, FQDN).'
+ false
+fi
+hostname="$1"
+fqdn="$2"
+shift 2
+
+config_tree_prefix="${HOME}/config/bullseye"
+setup_scripts_dir="${config_tree_prefix}/setup_scripts"
+cd "${setup_scripts_dir}"
+
+# Adapt /etc/ to our needs by copying from ./etc_files. This will set
+# basic configurations affecting following steps, such as setup of APT
+# and the locale selection, so needs to be right at the beginning.
+./copy_dirtree.sh "${config_tree_prefix}/etc_files" "" all "$@"
+
+# Set hostname and FQDN.
+./set_hostname_and_fqdn.sh "${hostname}" "${fqdn}"
+
+# Ensure package installation state as defined by what packages are
+# defined as required by Debian policy and by settings in ./apt-mark/.
+apt update
+./install_for_target.sh all "$@"
+./purge_nonrequireds.sh all "$@"
+
+# Ensure our desired locale is available.
+locale-gen
+
+# Only upgrade after reducing the system to the desired minimum, so that
+# we don't need to get more data than necessary.
+apt -y dist-upgrade
+
+# Set Berlin localtime.
+ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
--- /dev/null
+#!/bin/sh
+# Next setup steps for a server whose login policy has just been set from
+# the outside via ./init_user_and_keybased_login.sh.
+set -e
+
+# Provide maximum input for set_hostname_and_fqdn.sh.
+if [ "$#" -lt 2 ]; then
+ echo 'Need exactly two arguments (hostname, FQDN).'
+ false
+fi
+hostname="$1"
+fqdn="$2"
+additional_arg="$3"
+
+# Set up system without user environment.
+config_tree_prefix="${HOME}/config/bullseye"
+setup_scripts_dir="${config_tree_prefix}/setup_scripts"
+cd "${setup_scripts_dir}"
+./setup.sh "${hostname}" "${fqdn}" server "${additional_arg}"
+
+# If we have not yet set the shell for user plom, ensure it here. This
+# is mostly for convenience.
+usermod -s /bin/bash plom
+
+# Enable firewall.
+systemctl enable nftables.service