summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Wilken2022-12-31 13:28:51 +0100
committerTimo Wilken2022-12-31 13:28:51 +0100
commit3d331a392742d9db2f811547d122bb60d972da43 (patch)
treef975bce09ba4e5a35beaec4821faeba79a56efd8
parent336b73fd56ae24f3bd363f43263a671af92240f0 (diff)
Track system configuration
-rw-r--r--tw/system/common.scm103
-rw-r--r--tw/system/files/kitchen-pc.pub1
-rwxr-xr-xtw/system/files/nextcloud-backup68
-rw-r--r--tw/system/files/timo.pub1
-rw-r--r--tw/system/files/wilken-laptop.pub1
-rw-r--r--tw/system/lap.scm391
-rw-r--r--tw/system/lud.scm438
7 files changed, 1003 insertions, 0 deletions
diff --git a/tw/system/common.scm b/tw/system/common.scm
new file mode 100644
index 00000000..89d49281
--- /dev/null
+++ b/tw/system/common.scm
@@ -0,0 +1,103 @@
+(define-module (tw system common)
+ #:use-module (ice-9 regex)
+ #:use-module ((srfi srfi-1)
+ #:select (fold fold-right))
+ #:use-module (gnu)
+ #:use-module (gnu services)
+ #:use-module (gnu services vpn)
+ #:use-module (gnu system keyboard)
+ #:use-module (guix gexp))
+
+(use-package-modules admin avahi certs disk file-systems linux lsof man
+ moreutils search vpn)
+
+(define-public %common-system-packages
+ (list acpi btrfs-progs cpupower efibootmgr exfat-utils glibc-locales hddtemp
+ htop lshw lsof man-db man-pages man-pages-posix mlocate moreutils
+ nss-certs nss-mdns strace wireguard-tools))
+
+(define-public %british-keyboard
+ (keyboard-layout
+ "gb" #:options '("caps:swapescape"
+ "parens:swap_brackets"
+ "terminate:ctrl_alt_bksp"
+ "compose:rctrl"
+ "keypad:oss"
+ "kpdl:kposs")))
+
+(define %wireguard-peers
+ `((lap . ,(wireguard-peer
+ (name "lap.wg")
+ (public-key "lap/DvCb8xXLUCqcaPEx8kCRcoeV4ScTMVZW5hvvNzA=")
+ (preshared-key "/etc/wireguard/lap.psk")
+ (allowed-ips '("10.0.0.1/32" "fc00::1/128"))))
+ (lud . ,(wireguard-peer
+ (name "lud.wg")
+ (endpoint "lud.twilken.net:58921")
+ (public-key "lud/9sbXVdOYXxOkRgAB+b/17QxbwllfJY/pbA3/MkE=")
+ (preshared-key "/etc/wireguard/lud.psk")
+ (allowed-ips '("10.0.0.2/32" "fc00::2/128"))))
+ (vin . ,(wireguard-peer
+ (name "vin.wg")
+ (endpoint "vin.twilken.net:58921")
+ (public-key "vin/Im+sOszZFE01UF1+QlyxLP1PsPXJgTz4KmgvL3Y=")
+ (preshared-key "/etc/wireguard/vin.psk")
+ (allowed-ips '("10.0.0.3/32" "fc00::3/128"))))
+ (fp4 . ,(wireguard-peer
+ (name "fp4.wg")
+ (public-key "fp4/aLAVBADTy+UGmNh011w1CFOOwq70Df6EWlZRkAs=")
+ (preshared-key "/etc/wireguard/fp4.psk")
+ (allowed-ips '("10.0.0.4/32" "fc00::4/128"))))
+ (pi3 . ,(wireguard-peer
+ (name "pi3.wg")
+ (endpoint "pi3.twilken.net:58922")
+ (public-key "pi3/ThUH4qDTuyvNQIiiyy2dbziF/xLRTwO0+vcUoVY=")
+ (preshared-key "/etc/wireguard/pi3.psk")
+ (allowed-ips '("10.0.0.5/32" "fc00::5/128"))))))
+
+(define-public %wireguard-etc-hosts
+ (let ((basic-hosts-file "\
+# This file was generated from your Guix configuration.
+# Any changes will be lost upon reboot or reconfiguration.
+127.0.0.1 localhost
+255.255.255.255 broadcasthost
+::1 localhost ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+ff02::3 ip6-allhosts
+"))
+ (plain-file
+ "hosts"
+ (fold (lambda (peer hosts-file)
+ (apply string-append hosts-file
+ (map (lambda (allowed-ip-cidr)
+ (format #f "~16a~a~%"
+ (car (string-split allowed-ip-cidr #\/))
+ (wireguard-peer-name peer)))
+ (wireguard-peer-allowed-ips peer))))
+ basic-hosts-file
+ (map cdr %wireguard-peers)))))
+
+(define-public (wireguard-service host)
+ (let ((own-peer (assoc-ref %wireguard-peers host)))
+ (service
+ wireguard-service-type
+ (wireguard-configuration
+ (addresses
+ (map (lambda (cidr)
+ (let ((ipv4 (string-match "/32$" cidr))
+ (ipv6 (string-match "/128$" cidr)))
+ (cond
+ (ipv4 (regexp-substitute #f ipv4 'pre "/24"))
+ (ipv6 (regexp-substitute #f ipv6 'pre "/64"))
+ (#t cidr))))
+ (wireguard-peer-allowed-ips own-peer)))
+ (port
+ (let ((endpoint (wireguard-peer-endpoint own-peer)))
+ (if endpoint
+ (string->number (cadr (string-split endpoint #\:)))
+ 58921)))
+ (private-key "/etc/wireguard/private.key")
+ (peers (delq own-peer (map cdr %wireguard-peers)))))))
diff --git a/tw/system/files/kitchen-pc.pub b/tw/system/files/kitchen-pc.pub
new file mode 100644
index 00000000..cdf93db9
--- /dev/null
+++ b/tw/system/files/kitchen-pc.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDccEJMlKN1EkjIFqzpq2TEVa0q2V5eBEZ25c+sRp5an2AwOYjZ4I0UHgFq3Ro82a7EdZf3KObM7tu1EJBXaxbtp0BWDpJB2NqZELHaShnA5tcuCGGfN7qTn3o3RA3eYYSxeMC319Rt5W4sMckTayQYBt6F491bfJx7N7n4ISVWM/q2/Mss9VrZiF2bP1IVcIfdkTH3iFIMHSD7aQl5UNwPSbgmAfe0qO+c1EMxaYvUIEXOVDfd+NUilotJPOgThKEBT2iIevinGjKeNZIq+N+EVN2Np/3FzSCRQqqIYGSuA/Y62KFfmZXy0XoL1LXcHCU9DaY/afNX6NfQocBxhyIp stephan@stephan-pc
diff --git a/tw/system/files/nextcloud-backup b/tw/system/files/nextcloud-backup
new file mode 100755
index 00000000..4c533758
--- /dev/null
+++ b/tw/system/files/nextcloud-backup
@@ -0,0 +1,68 @@
+#!/bin/sh -e
+# Nextcloud backup script, to run nightly.
+# Documentation on backups:
+# https://docs.nextcloud.com/server/latest/admin_manual/maintenance/backup.html
+# https://docs.nextcloud.com/server/latest/admin_manual/maintenance/restore.html
+# https://git.mdns.eu/nextcloud/passwords/-/wikis/Administrators/Backups
+
+. /etc/default/nextcloud-backup
+: "${DATABASE_PASSWORD:?You must pass the MySQL database password as DATABASE_PASSWORD}"
+
+php_ini=$1
+backup_dir=/var/backups/nextcloud/$(date -u '+%Y-%m-%d')
+nextcloud_dir=/var/www/nextcloud
+nextcloud_data_partition=/var/data # mountpoint of the partition containing Nextcloud data dir
+nextcloud_data_path=nextcloud # relative to $nextcloud_data_partition
+snapshot=$nextcloud_data_partition/tmp-nextcloud-backup
+
+nc_maintenance () {
+ # Enable (--on) or disable (--off) Nextcloud's maintenance mode.
+ sudo -nu httpd php ${php_ini:+-c "$php_ini"} "$nextcloud_dir/occ" maintenance:mode "$@"
+}
+
+# If there is a previous backup, compare against it later (so we don't have to
+# transfer every file).
+last_backup_dir=$(ls -1d "$(dirname "$backup_dir")"/????-??-?? | LC_ALL=C sort | tail -1)
+[ -d "$last_backup_dir" ] || unset last_backup_dir
+
+# Don't overwrite existing backups. mkdir will fail if $backup_dir exists.
+mkdir -m 750 "$backup_dir"
+
+# Always turn off maintenance mode and clean up the temporary snapshot on exit,
+# whether or not the backup succeeded.
+cleanup () {
+ nc_maintenance --off || :
+ if [ -d "$snapshot" ]; then
+ btrfs subvolume delete -c "$snapshot" || :
+ fi
+}
+trap cleanup EXIT HUP INT TERM # can't trap KILL
+
+# Turn Nextcloud off temporarily so the data doesn't change during the backup.
+nc_maintenance --on
+
+# Backup the database. This can only be done offline.
+mysqldump --single-transaction --default-character-set=utf8mb4 \
+ -u nextcloud -p"$DATABASE_PASSWORD" nextcloud > "$backup_dir/nextcloud.sql"
+
+# These shouldn't be copied while Nextcloud is online.
+rsync -AUXHavx ${last_backup_dir+--link-dest="$last_backup_dir"} \
+ "$nextcloud_dir/config" "$nextcloud_dir/themes" "$backup_dir"
+
+# Make sure everything is synced to disk so it's in our snapshot.
+btrfs filesystem sync "$nextcloud_data_partition/$nextcloud_data_path"
+btrfs subvolume snapshot -r "$nextcloud_data_partition" "$snapshot"
+
+# At this point, the data directory is in the snapshot, so Nextcloud can be
+# turned on again.
+nc_maintenance --off
+
+# --link-dest is brittle (it only hardlinks to the old file if no metadata has
+# changed). Reflinks would be better, but rsync doesn't seem to support them.
+# We don't need files under preview/, as those are thumbnails from the Previews
+# "app" and can be regenerated using `php -f occ preview:pre-generate`.
+rsync -AUXHavx --exclude='appdata_*/preview' --exclude='appdata_*/passwords/*Cache' \
+ ${last_backup_dir+--link-dest="$last_backup_dir/data"} \
+ "$snapshot/$nextcloud_data_path/" "$backup_dir/data"
+# Make sure everything is written out to the backup disk before we exit.
+btrfs filesystem sync "$backup_dir"
diff --git a/tw/system/files/timo.pub b/tw/system/files/timo.pub
new file mode 100644
index 00000000..38012eb3
--- /dev/null
+++ b/tw/system/files/timo.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDGNBJNlMWGWuPYkW3nGqK078cRvsGArizQa1Aco8SRGWjabSoeazk4IjYW80dx+FJvPgXowBXmXsctB35kQfw85h1iNOkkroZKBSwFj/kWrNvW7g+cneMLyLIy2Q+1X3ths6m++L1elNryOLdvNZtCB4cYbD22IIi65dtzXK2m3MXbEucXHyTivcRWDxg0HSy3fArJVkW2vst5DBC5zci/Uf8ZnNzyObE5h9IlDARw1VGmDo6Bw25zJMYGIYb+l629mU9dlO1x39JGe/+/l+iJTLfUGbiOvZ6uKMt7c04WBsYF8jFitnKU2Nhfa820p+bSBJYsW5QyQZWG12R36qT timo.21.wilken@gmail.com
diff --git a/tw/system/files/wilken-laptop.pub b/tw/system/files/wilken-laptop.pub
new file mode 100644
index 00000000..dafd007b
--- /dev/null
+++ b/tw/system/files/wilken-laptop.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8bnrC257jNnrOo8ItOBB4uUDk/sq+C399MxSNewsbhVVHJ7W531mgLKJcX+Y34nXIyMxq10xJWlvMjw6IlE7fu2V2AOh9QGoYJeu9FkUB5DY74ynGmdrxKDRyQue3CKkNYIxH1OzKJHCFxDPpVytTKPqT1BAGAMOrQiC9nZE0TMYWH1V1YBIQrCYFPAyWzBueTAIUyLXbgfz5GBJq05pgQFI0wOEEKnkAIYc7htd/rGb0xIhcI/X4r3CdXPLwZzxQE/eO3MBClMFpx+QpV9tLeOLOcH9yubk13XUR6dpY/bzhMk2X3teqBUNLliCmIf1jv28qANwJf0J9OxfQQA3B wilken@wilken-laptop
diff --git a/tw/system/lap.scm b/tw/system/lap.scm
new file mode 100644
index 00000000..9dd81d80
--- /dev/null
+++ b/tw/system/lap.scm
@@ -0,0 +1,391 @@
+;; This is an operating system configuration file for a fairly minimal
+;; "desktop" setup with i3 where the /home partition partition is
+;; encrypted with LUKS.
+;;
+;; https://guix.gnu.org/manual/en/html_node/operating_002dsystem-Reference.html
+
+(define-module (tw system lap)
+ #:use-module (gnu)
+ #:use-module (gnu bootloader grub)
+ #:use-module (gnu system locale)
+ #:use-module (gnu system nss)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module ((guix utils) #:select (substitute-keyword-arguments))
+ #:use-module ((nongnu packages linux)
+ #:prefix nongnu:) ; don't interfere with (gnu packages linux)
+ #:use-module (nongnu packages scanner)
+ #:use-module (nongnu system linux-initrd)
+ #:use-module (nonguix licenses)
+ #:use-module (tw system common))
+
+(use-package-modules android certs cups disk docker file-systems gnome
+ kerberos linux mtools pulseaudio search shells wm xorg)
+
+(use-service-modules authentication avahi base cups dbus desktop docker
+ kerberos linux mcron networking pm syncthing vpn xorg)
+
+(define efi-system-partition ; /dev/nvme0n1p1
+ (uuid "E04A-DF05" 'fat))
+(define tilearch-root-partition ; /dev/nvme0n1p2
+ (uuid "197c7f98-c780-4017-9bf7-212175967fd0" 'btrfs))
+(define guixsd-root-partition ; /dev/nvme0n1p3
+ (uuid "2169a07b-b7b6-4e3d-8e59-bf00d0baffc4" 'btrfs))
+(define swap-partition ; /dev/nvme0n1p4
+ (uuid "2c78d507-5cd1-48da-ba8d-d1b01d6ff8f9"))
+(define data-partition-outside-luks ; /dev/sda1
+ (uuid "43108ff6-b25a-4a53-b3f7-6d03ff3e0022"))
+(define data-partition-inside-luks ; /dev/mapper/data
+ (uuid "826bb1a7-1069-46a5-897a-afa19272fbb0" 'btrfs))
+
+(define backlight-udev-rules
+ ;; The naive approach of GROUP="video", MODE="0664" doesn't seem to work.
+ ;; https://github.com/haikarainen/light/blob/master/90-backlight.rules
+ ;; https://github.com/Hummer12007/brightnessctl/blob/master/90-brightnessctl.rules
+ (udev-rule "90-backlight.rules" "\
+ACTION==\"add\", SUBSYSTEM==\"backlight\", RUN+=\"/usr/bin/env chgrp video /sys/class/backlight/%k/brightness\"
+ACTION==\"add\", SUBSYSTEM==\"backlight\", RUN+=\"/usr/bin/env chmod g+w /sys/class/backlight/%k/brightness\"
+ACTION==\"add\", SUBSYSTEM==\"leds\", RUN+=\"/usr/bin/env chgrp video /sys/class/leds/%k/brightness\"
+ACTION==\"add\", SUBSYSTEM==\"leds\", RUN+=\"/usr/bin/env chmod g+w /sys/class/leds/%k/brightness\"
+"))
+
+;; This text is added verbatim to the Xorg config file.
+(define touchpad-xorg-config "\
+# see man 4 libinput
+Section \"InputClass\"
+ Identifier \"touchpad\"
+ Driver \"libinput\"
+ MatchIsTouchpad \"true\"
+
+ Option \"DisableWhileTyping\" \"true\"
+ Option \"MiddleEmulation\" \"true\"
+ Option \"NaturalScrolling\" \"true\"
+ Option \"HorizontalScrolling\" \"true\"
+ Option \"ScrollMethod\" \"twofinger\"
+ Option \"ClickMethod\" \"clickfinger\"
+ Option \"Tapping\" \"true\"
+ Option \"TappingDrag\" \"true\"
+ Option \"TappingDragLock\" \"false\"
+ Option \"TappingButtonMap\" \"lrm\"
+EndSection
+")
+
+(define custom-xorg-config
+ (xorg-configuration
+ (keyboard-layout %british-keyboard)
+ (extra-config (list touchpad-xorg-config))))
+
+(define extra-channels
+ (plain-file "channels.scm" "\
+(use-modules (guix channels))
+(cons* (channel
+ (name 'nonguix)
+ (url \"https://gitlab.com/nonguix/nonguix\")
+ ;; Enable signature verification:
+ (introduction
+ (make-channel-introduction
+ \"897c1a470da759236cc11798f4e0a5f7d4d59fbc\"
+ (openpgp-fingerprint
+ \"2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5\"))))
+ %default-channels)
+"))
+
+;; Nonguix substitute server's signing key.
+;; From <https://substitutes.nonguix.org/signing-key.pub>.
+(define nonguix-signing-key
+ (plain-file "nonguix-signing-key.pub" "\
+(public-key
+ (ecc
+ (curve Ed25519)
+ (q #C1FD53E5D4CE971933EC50C9F307AE2171A2D3B52C804642A7A35F84F3A4EA98#)
+ )
+ )
+"))
+
+;; TODO: Nouveau claims (in dmesg) that I have a NVIDIA GM204. Maybe
+;; only use (select-firmware "^nvidia/gm204/"). linux-firmware only
+;; has a gr/ subdir for that, and acr/ symlinked from gm200. No pmu/
+;; (power management), sadly. (See WHENCE file
+;; https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/WHENCE
+;; for symlinks).
+(define nouveau-firmware
+ (package
+ (inherit nongnu:linux-firmware)
+ (name "nouveau-firmware")
+ (arguments
+ `(#:license-file-regexp "LICENSE.nvidia"
+ ,@(substitute-keyword-arguments (package-arguments nongnu:linux-firmware)
+ ((#:phases phases)
+ `(modify-phases ,phases
+ (add-after 'unpack 'select-firmware
+ ,((@@ (nongnu packages linux) select-firmware)
+ "^nvidia/(g|tu)"))))))) ; `select-firmware' is private
+ (home-page "https://www.nvidia.com/en-us/drivers/unix/")
+ (synopsis "Nonfree firmware for NVIDIA graphics chips")
+ (description "\
+Nonfree firmware for NVIDIA graphics chips. Required for nouveau to
+support extra features (acr, pmu, gr).")
+ (license
+ (nonfree
+ (string-append
+ "https://git.kernel.org/pub/scm/linux/kernel/git/firmware"
+ "/linux-firmware.git/plain/LICENSE.nvidia")))))
+
+(operating-system
+ (host-name "lap.twilken.net")
+ (timezone "Europe/Paris")
+ (locale "en_GB.utf8")
+ (locale-definitions
+ (list (locale-definition (name "en_GB.utf8") (source "en_GB"))
+ (locale-definition (name "en_US.utf8") (source "en_US"))
+ (locale-definition (name "fr_FR.utf8") (source "fr_FR"))))
+
+ (hosts-file %wireguard-etc-hosts)
+ ;; Allow resolution of '.local' host names with mDNS.
+ (name-service-switch %mdns-host-lookup-nss)
+
+ ;; Choose UK English X11 keyboard layout.
+ (keyboard-layout %british-keyboard)
+
+ ;; Use the UEFI variant of GRUB with the EFI System
+ ;; Partition mounted on /boot/efi.
+ (bootloader
+ (bootloader-configuration
+ (bootloader grub-efi-bootloader)
+ (targets '("/boot/efi"))
+ ;; Note: keyboard-layout is ignored by non-grub bootloaders.
+ (keyboard-layout keyboard-layout)
+ (menu-entries
+ (list
+ (menu-entry
+ (label "systemd-boot")
+ (device efi-system-partition)
+ (chain-loader "/EFI/systemd/systemd-bootx64.efi"))))))
+
+ ;; Use non-free kernel to load non-free firmware (e.g. for wifi).
+ (kernel nongnu:linux-lts)
+ (kernel-arguments
+ (cons* ;;"nosplash"
+ ;;"vt.global_cursor_default=0"
+ ;;"video.use_native_backlight=1"
+ ;;"nvidia-drm.modeset=1"
+ ;;"acpi_osi=\"!Windows 2015\""
+ ;;"acpi_enforce_resources=lax"
+ %default-kernel-arguments))
+ (initrd microcode-initrd)
+ ;; TODO: nouveau complains about missing firmware (see dmesg).
+ (firmware (cons* nongnu:atheros-firmware ; for atk10k/QCA6174/hw3.0 (wifi card)
+ nongnu:i915-firmware ; for Intel GPU runtime power management etc
+ nouveau-firmware ; for nouveau to use NVIDIA GPU
+ %base-firmware))
+
+ ;; Specify a mapped device for the encrypted home partition.
+ ;; The UUID is that returned by 'cryptsetup luksUUID'.
+ (mapped-devices
+ (list (mapped-device
+ (source data-partition-outside-luks)
+ (target "data")
+ (type luks-device-mapping))))
+
+ (swap-devices
+ (list (swap-space
+ (target swap-partition)
+ (discard? #t))))
+
+ (file-systems
+ (cons* (file-system
+ (device guixsd-root-partition)
+ (mount-point "/")
+ (flags '(no-atime))
+ (options (alist->file-system-options
+ '("ssd" ("compress" . "zstd"))))
+ (type "btrfs"))
+ (file-system
+ (device efi-system-partition)
+ (mount-point "/boot/efi")
+ (flags '(no-atime))
+ (type "vfat"))
+ (file-system
+ (device data-partition-inside-luks)
+ (mount-point "/home")
+ (flags '(no-atime))
+ (options (alist->file-system-options
+ '("ssd" ("compress" . "zstd")
+ ("subvol" . "home/guixsd"))))
+ (type "btrfs")
+ (dependencies mapped-devices))
+ %base-file-systems))
+
+ ;; Members of the wheel group are allowed to use sudo.
+ (users (cons* (user-account
+ (name "timo")
+ (comment "Timo Wilken")
+ (group "users")
+ (supplementary-groups
+ '("wheel" "audio" "video" "docker" "adbusers"))
+ (shell (file-append zsh "/bin/zsh")))
+ %base-user-accounts))
+
+ (sudoers-file
+ (plain-file
+ "sudoers"
+ (string-append
+ ;; We need to preserve $TERMINFO so that programs under sudo can
+ ;; find kitty's terminfo files. This is possibly unsafe; sudo
+ ;; explicitly deletes this variable by default.
+ "Defaults env_keep += \"TERMINFO\"\n"
+ (plain-file-content %sudoers-specification)
+ ;; In addition to the default rules, allow admins to power off
+ ;; the computer. They'll have to use the system binaries, not
+ ;; those from their user profile, as /etc/sudoers requires
+ ;; absolute paths to commands.
+ "%wheel ALL=(ALL) NOPASSWD: "
+ "/run/current-system/profile/sbin/halt, "
+ "/run/current-system/profile/sbin/reboot, "
+ "/run/current-system/profile/sbin/shutdown\n")))
+
+ ;; This is where we specify system-wide packages.
+ (packages
+ (cons*
+ ;; System stuff
+ cups docker mit-krb5
+ ;; File systems
+ dosfstools mtools ntfs-3g
+ ;; Printing and scanning
+ ;; SANE doesn't detect my scanner without brscan4's etc/sane.d/dll.conf.
+ brscan4
+ ;; Desktop and drivers
+ ;; FIXME: lightdm depends on python-2, but the build throws an
+ ;; error that python2 is not supported.
+ ;; TODO: Does lightdm have a service I need to enable?
+ ;;lightdm lightdm-gtk-greeter
+ pulseaudio xf86-video-intel xf86-video-nouveau
+ ;; Adds /sys/class/backlight entries for external monitors.
+ ;; Not needed for laptop display.
+ ddcci-driver-linux
+ i3-gaps ; install i3 here so gdm can see its xsession file
+ i3lock ; we need a system service to make i3lock setuid root
+ ;; We need to install gnome-keyring here so its PAM module is
+ ;; enabled properly (by its service; see below).
+ ;; nheko needs gnome-keyring to store secrets (kwallet doesn't do dbus).
+ gnome-keyring
+ ;; It's probably easiest to install geoclue system-wide, so it
+ ;; gets added to `%desktop-services' and redshift can access the
+ ;; location.
+ geoclue
+ ;; Base packages
+ (append %common-system-packages %base-packages)))
+
+ ;; Use the "desktop" services, which include the X11
+ ;; log-in service, networking with NetworkManager, and more.
+ ;; See info '(guix)Services' for useful services.
+ (services
+ (cons*
+ (service syncthing-service-type
+ (syncthing-configuration
+ (user "timo")))
+
+ (service cups-service-type
+ (cups-configuration
+ (web-interface? #t)
+ (default-shared? #f)
+ ;; See info '(guix)Printing Services' for more extensions.
+ (extensions
+ (list cups-filters foomatic-filters brlaser))))
+
+ (bluetooth-service)
+
+ (wireguard-service 'lap)
+
+ (service docker-service-type
+ (docker-configuration))
+
+ (service krb5-service-type
+ (krb5-configuration
+ (default-realm "CERN.CH")
+ (rdns? #f)
+ (realms (list (krb5-realm
+ (name "CERN.CH")
+ (default-domain "cern.ch")
+ (kdc "cerndc.cern.ch"))))))
+
+ (service tlp-service-type
+ (tlp-configuration)) ; TODO: configure properly
+
+ (service thermald-service-type
+ (thermald-configuration
+ (adaptive? #t)))
+
+ (service earlyoom-service-type
+ (earlyoom-configuration)) ; TODO: configure at least `avoid-regexp'
+
+ ;; Disabled as it doesn't work with my hardware.
+ ;; It always says "logging in with fingerprint failed" and blocks password login in gdm.
+ ;; (service fprintd-service-type)
+
+ ;; Install i3lock as a setuid binary, so it can talk to PAM.
+ (screen-locker-service i3lock "i3lock")
+
+ ;; gnome-keyring is not in `%desktop-services' by default,
+ ;; but needs to be there to add itself to /etc/pam.d/.
+ ;; If using a DM other than GDM, add it to `pam-services' in
+ ;; `gnome-keyring-configuration' (see its docs).
+ (service gnome-keyring-service-type
+ (gnome-keyring-configuration))
+
+ ;; Allow anyone in the "video" group to set the display's brightness.
+ ;; Run `udevadm info -q all /sys/class/backlight/intel_backlight'
+ ;; to see properties.
+ (udev-rules-service 'backlight backlight-udev-rules #:groups '("video"))
+ ;; According to "info '(guix) Base Services'", the above should
+ ;; have a `#:groups '("video")', but that group is already
+ ;; declared as a supplementary group for my user and guix warns
+ ;; that it's declared twice.
+
+ (udev-rules-service 'android android-udev-rules #:groups '("adbusers"))
+
+ (set-xorg-configuration custom-xorg-config)
+
+ (simple-service
+ 'cronjobs mcron-service-type
+ ;; I don't think jobs run on boot if they would have run when the
+ ;; computer was turned off, so choose a time when the computer is
+ ;; probably turned on.
+ (list #~(job "0 21 * * *" "guix gc -d 2w -F 25G")
+ #~(job "0 22 * * *" ; after guix gc
+ (string-append #$(file-append util-linux "/sbin/fstrim")
+ " --fstab --verbose"))))
+
+ ;; The nonguix channel is added to channels.scm as an `extra-special-file'.
+ ;; The gaming channel (https://gitlab.com/guix-gaming-channels) is per-user only.
+ (simple-service
+ 'nonguix guix-service-type
+ (guix-extension
+ (authorized-keys (list nonguix-signing-key))
+ (substitute-urls '("https://substitutes.nonguix.org"))))
+
+ (extra-special-file "/etc/guix/channels.scm" extra-channels)
+
+ (modify-services %desktop-services
+ (gdm-service-type
+ config =>
+ (gdm-configuration
+ (inherit config)
+ (auto-login? #f)
+ (default-user "timo")
+ (xorg-configuration custom-xorg-config)))
+
+ (geoclue-service-type
+ config =>
+ (geoclue-configuration
+ (inherit config)
+ (applications
+ (cons* (geoclue-application "redshift" #:system? #f)
+ %standard-geoclue-applications))))
+
+ (login-service-type
+ config =>
+ (login-configuration
+ (inherit config)
+ (motd (plain-file "no-motd" ""))
+ (allow-empty-passwords? #f)))))))
diff --git a/tw/system/lud.scm b/tw/system/lud.scm
new file mode 100644
index 00000000..10b5fc71
--- /dev/null
+++ b/tw/system/lud.scm
@@ -0,0 +1,438 @@
+(define-module (tw system lud)
+ #:use-module (gnu)
+ #:use-module (gnu bootloader grub)
+ #:use-module (gnu system locale)
+ #:use-module (gnu system nss)
+ #:use-module (guix gexp)
+ #:use-module (tw packages php)
+ #:use-module (tw system common))
+
+(use-package-modules admin bash certs databases linux man php rsync
+ shells version-control video)
+(use-service-modules certbot databases file-sharing mcron monitoring
+ networking pm ssh syncthing vpn web)
+
+(define efi-system-partition ; /dev/sda1
+ (uuid "51F3-FB71" 'fat32))
+(define guixsd-root-partition ; /dev/sda2
+ (uuid "c63af3e6-3c2b-43d2-b1e6-944f09a10e0f" 'btrfs))
+(define backups-partition ; /dev/sdb1
+ (uuid "c6ac4033-cce6-4365-abcc-483b79c4ca36" 'btrfs))
+(define data-partition ; /dev/sdc1
+ (uuid "4715ae0e-5cef-48f2-a59e-025321153888" 'btrfs))
+
+(define httpd-cert-deploy-hook
+ (program-file "httpd-cert-deploy-hook"
+ #~(kill (call-with-input-file "/var/run/httpd" read) SIGHUP)))
+
+(define nextcloud-php.ini
+ (computed-file
+ "nextcloud-php.ini"
+ #~(begin
+ (use-modules (ice-9 popen) (ice-9 rdelim))
+ (let* ((php-config #$(file-append php "/bin/php-config"))
+ (pipe (open-pipe* OPEN_READ php-config "--extension-dir"))
+ (php-extdir (read-line pipe)))
+ (unless (zero? (status:exit-val (close-pipe pipe)))
+ (error "Failed to get PHP extension dir"))
+ (with-output-to-file #$output
+ ;; Guix's PHP comes with the following extensions built-in,
+ ;; so no extension= line necessary:
+ ;; pdo_mysql, bcmath, bz2, exif, gd, iconv, intl
+ (lambda () (display (string-append "\
+memory_limit=512M
+extension_dir=/run/current-system/profile/lib/php/extensions/" (basename php-extdir) "
+; Caching extensions for Nextcloud
+extension=apcu
+apc.enable_cli=1
+zend_extension=opcache
+; https://www.php.net/manual/en/opcache.configuration.php
+opcache.enable=1
+opcache.interned_strings_buffer=32
+opcache.max_accelerated_files=10000
+opcache.memory_consumption=128
+opcache.save_comments=1
+; It will take up to revalidate_freq seconds for changes to config.php to be applied.
+opcache.revalidate_freq=120
+"))))))))
+
+(define httpd-intermediate-ssl-config "\
+# SSL configuration.
+# https://ssl-config.mozilla.org/#server=apache&version=2.4.53&config=intermediate&openssl=1.1.1n&ocsp=false&guideline=5.6
+SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
+SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+SSLHonorCipherOrder Off
+SSLSessionTickets Off
+SSLUseStapling On
+SSLStaplingCache \"shmcb:logs/ssl_stapling(32768)\"
+SSLSessionCache \"shmcb:logs/ssl_scache(65535)\"
+# 20 minutes -- default is 5 minutes, which is not long, and the cache
+# size is limited anyway above.
+SSLSessionCacheTimeout 1200
+")
+
+(define nextcloud-services
+ (list (simple-service
+ 'nextcloud-https-server httpd-service-type
+ ;; The certbot service redirects everything on port 80 to
+ ;; port 443 by default, modulo its own /.well-known paths.
+ (list (httpd-virtualhost "*:443" (list "\
+# For Nextcloud.
+ServerName cloud.wilkenfamily.de
+DocumentRoot /var/www/nextcloud
+SSLEngine on
+SSLCertificateFile \"/etc/letsencrypt/live/cloud.wilkenfamily.de/fullchain.pem\"
+SSLCertificateKeyFile \"/etc/letsencrypt/live/cloud.wilkenfamily.de/privkey.pem\"
+Header always set Strict-Transport-Security \"max-age=15552000\"
+
+# Don't check for .htaccess files above DocumentRoot.
+<Directory \"/\">
+ AllowOverride None
+</Directory>
+
+<Directory /var/www/nextcloud>
+ Options +FollowSymlinks
+ AllowOverride All
+ <IfModule mod_dav.c>
+ Dav off
+ </IfModule>
+ SetEnv HOME /var/www/nextcloud
+ SetEnv HTTP_HOME /var/www/nextcloud
+</Directory>
+
+# Redirect to local php-fpm if mod_php is not available
+<IfModule !mod_php7.c>
+ <IfModule proxy_fcgi_module>
+ # Enable http authorization headers
+ <IfModule setenvif_module>
+ SetEnvIfNoCase ^Authorization$ \"(.+)\" HTTP_AUTHORIZATION=$1
+ </IfModule>
+ <FilesMatch \".+\\.ph(ar|p|tml)$\">
+ <If \"-f %{REQUEST_FILENAME}\">
+ SetHandler \"proxy:unix:/var/run/php-fpm.sock|fcgi://localhost/\"
+ </If>
+ </FilesMatch>
+ # Deny access to raw PHP sources and files without filename (e.g. '.php')
+ <FilesMatch \"^\\.ph(ar|p|ps|tml)$|.*\\.phps$\">
+ Require all denied
+ </FilesMatch>
+ </IfModule>
+</IfModule>
+"))))
+
+ (service php-fpm-service-type
+ (php-fpm-configuration
+ (user "httpd")
+ (group "httpd")
+ (socket "/var/run/php-fpm.sock")
+ (socket-user "httpd")
+ (socket-group "httpd")
+ (php-ini-file nextcloud-php.ini)))
+
+ (simple-service
+ 'nextcloud-certificates certbot-service-type
+ (list (certificate-configuration
+ (domains '("cloud.wilkenfamily.de"))
+ (deploy-hook httpd-cert-deploy-hook))))
+
+ ;; Nextcloud cron
+ (simple-service
+ 'nextcloud-cron mcron-service-type
+ (list #~(job "*/5 * * * *"
+ (lambda ()
+ (chdir "/var/www/nextcloud")
+ ;; `setgid' first while we're still root
+ (setgid (group:gid (getgr "httpd")))
+ (setuid (passwd:uid (getpw "httpd")))
+ (execl #$(file-append php "/bin/php") "php"
+ "-c" #$nextcloud-php.ini "cron.php"))
+ (string-append
+ #$(file-append php "/bin/php")
+ " -c " #$nextcloud-php.ini
+ " /var/www/nextcloud/cron.php"))
+
+ ;; Nextcloud backups
+ ;; Requires: sudo, php, btrfs, mysqldump, rsync
+ (let ((backup-script (local-file "files/nextcloud-backup" #:recursive? #t)))
+ #~(job "0 6 * * *"
+ (lambda ()
+ ;; Pass through the php.ini file that allows us
+ ;; to use Nextcloud's occ script.
+ ;; Alternatively, set NEXTCLOUD_PHP_CONFIG.
+ (execl #$backup-script "nextcloud-backup" #$nextcloud-php.ini))
+ (string-append #$backup-script " " #$nextcloud-php.ini)))))))
+
+(define matrix-services
+ (list (simple-service
+ 'synapse-certificates certbot-service-type
+ (list (certificate-configuration
+ (domains '("matrix.twilken.net"))
+ (deploy-hook httpd-cert-deploy-hook))))
+
+ (simple-service
+ 'synapse-https-proxy httpd-service-type
+ ;; Synapse can't access certbot certs, but Apache/httpd
+ ;; can, so proxy HTTPS access through. It's good to have
+ ;; Synapse available on port 443 anyway.
+ (list (httpd-virtualhost "*:443" (list "\
+# Redirect to Synapse, to avoid having to specify its port number in Matrix clients.
+ServerName matrix.twilken.net
+SSLEngine on
+SSLCertificateFile \"/etc/letsencrypt/live/matrix.twilken.net/fullchain.pem\"
+SSLCertificateKeyFile \"/etc/letsencrypt/live/matrix.twilken.net/privkey.pem\"
+ProxyPass \"/\" \"https://127.0.0.1:48448/\"
+"))))
+
+ ;; TODO: Postgres for Synapse
+ ;; (service postgresql-service-type
+ ;; (postgresql-configuration
+ ;; (postgresql postgresql-15)
+ ;; (data-directory "/var/lib/postgresql/data")))
+
+ ;; (service postgresql-role-service-type
+ ;; (postgresql-role-configuration
+ ;; (roles (list (postgresql-role
+ ;; (name "synapse") ; TODO
+ ;; (create-database? #t))))))
+
+ ;; TODO: Matrix/Synapse
+ ;; TODO: Matrix bridges
+ ))
+
+(operating-system
+ (host-name "lud.twilken.net")
+ (timezone "Europe/Berlin")
+ (locale "en_GB.utf8")
+ (locale-definitions
+ (list (locale-definition (name "en_GB.utf8") (source "en_GB"))
+ (locale-definition (name "de_DE.utf8") (source "de_DE"))
+ (locale-definition (name "fr_FR.utf8") (source "fr_FR"))
+ (locale-definition (name "pt_BR.utf8") (source "pt_BR"))
+ (locale-definition (name "en_US.utf8") (source "en_US"))))
+
+ (hosts-file %wireguard-etc-hosts)
+ ;; Allow resolution of '.local' host names with mDNS.
+ (name-service-switch %mdns-host-lookup-nss)
+
+ ;; Choose UK English console keyboard layout.
+ (keyboard-layout %british-keyboard)
+
+ ;; Packages installed system-wide. Users can also install packages
+ ;; under their own account: use 'guix search KEYWORD' to search
+ ;; for packages and 'guix install PACKAGE' to install a package.
+ (packages
+ (append (list
+ ;; For nightly yt-dlp.
+ ffmpeg
+ ;; For Nextcloud backup script.
+ btrfs-progs mariadb rsync
+ ;; For Nextcloud. PHP modules must be installed in system
+ ;; profile, as that's referred to in Nextcloud's php.ini.
+ php php-apcu)
+ %common-system-packages
+ %base-packages))
+
+ ;; Below is the list of system services. To search for available
+ ;; services, run 'guix system search KEYWORD' in a terminal.
+ (services
+ (append
+ (list (service openssh-service-type
+ (openssh-configuration
+ (port-number 22022)
+ (password-authentication? #f)
+ (accepted-environment '("LANG" "LC_*"))
+ (authorized-keys
+ `(("timo"
+ ,(local-file "files/timo.pub"))
+ ("ira" ; for Duplicity backups
+ ,(local-file "files/kitchen-pc.pub")
+ ,(local-file "files/wilken-laptop.pub"))))))
+
+ (service tor-service-type)
+
+ (service dhcp-client-service-type)
+
+ (service ntp-service-type)
+
+ (service thermald-service-type
+ (thermald-configuration
+ (adaptive? #t)))
+
+ (simple-service
+ 'cronjobs mcron-service-type
+ (list #~(job "0 21 * * *" "guix gc -d 2w -F 25G")
+ #~(job "0 22 * * *" ; after guix gc
+ (string-append #$(file-append util-linux "/sbin/fstrim")
+ " --fstab --verbose"))))
+
+ ;; Transmission (torrents)
+ (service transmission-daemon-service-type
+ (transmission-daemon-configuration
+ (download-dir "/var/data/bt")
+ (incomplete-dir "/var/data/bt/incomplete")
+ (incomplete-dir-enabled? #t)
+ (speed-limit-up-enabled? #t)
+ (speed-limit-up 512) ; KiB/s
+ (encryption 'require-encrypted-connections)
+ ;; Don't try to configure port forwarding automatically.
+ (port-forwarding-enabled? #f)
+ ;; Make RPC interface only accessible via WireGuard.
+ (rpc-bind-address "10.0.0.2")
+ (rpc-whitelist-enabled? #t)
+ (rpc-whitelist '("127.0.0.1" "::1"
+ "10.0.0.*" "fc00::*"))
+ (rpc-host-whitelist-enabled? #t)
+ (rpc-host-whitelist '("lud.wg"))))
+
+ ;; TODO: Streama
+
+ ;; Syncthing
+ (service syncthing-service-type
+ (syncthing-configuration
+ (user "syncthing")
+ (group "syncthing")))
+
+ ;; certbot for Synapse + Apache/Nextcloud
+ ;; This also installs a nginx server on port 80, redirecting to port 443.
+ (service certbot-service-type
+ (certbot-configuration
+ (email "letsencrypt@twilken.net")))
+
+ (service httpd-service-type
+ (httpd-configuration
+ (config
+ (httpd-config-file
+ (listen '("443")) ; leave port 80 free for certbot/nginx
+ (modules
+ (cons* (httpd-module (name "ssl_module") (file "modules/mod_ssl.so"))
+ (httpd-module (name "proxy_module") (file "modules/mod_proxy.so"))
+ (httpd-module (name "rewrite_module") (file "modules/mod_rewrite.so"))
+ (httpd-module (name "alias_module") (file "modules/mod_alias.so"))
+ (httpd-module (name "socache_shmcb_module") ; for SSLStaplingCache
+ (file "modules/mod_socache_shmcb.so"))
+ (httpd-module (name "proxy_fcgi_module") ; for PHP/FastCGI
+ (file "modules/mod_proxy_fcgi.so"))
+ %default-httpd-modules))
+ ;; Preserve default value for `extra-config'.
+ (extra-config
+ (list "TypesConfig etc/httpd/mime.types\n"
+ "ServerAdmin webmaster@twilken.net\n"
+ httpd-intermediate-ssl-config))))))
+
+ ;; For Nextcloud (and Streama)
+ (service mysql-service-type
+ (mysql-configuration
+ (extra-content "\
+[mysqld]
+character-set-server = utf8mb4
+collation-server = utf8mb4_general_ci
+# https://wiki.archlinux.org/title/Nextcloud
+skip_networking
+transaction_isolation = READ-COMMITTED
+# https://docs.nextcloud.com/server/stable/admin_manual/installation/server_tuning.html#using-mariadb-mysql-instead-of-sqlite
+innodb_buffer_pool_size = 1G
+innodb_io_capacity = 4000
+")))
+
+ ;; Prometheus node exporter
+ (service prometheus-node-exporter-service-type
+ (prometheus-node-exporter-configuration
+ (web-listen-address "10.0.0.2:9100")))
+
+ ;; TODO: JSON exporter (Nextcloud)
+
+ ;; TODO: Syncthing exporter
+
+ ;; TODO: Transmission exporter
+
+ ;; TODO: git-daemon-service-type / cgit-service-type?
+
+ (wireguard-service 'lud))
+
+ nextcloud-services
+ matrix-services
+
+ (modify-services %base-services
+ (login-service-type
+ config =>
+ (login-configuration
+ (inherit config)
+ (motd (plain-file "no-motd" ""))
+ (allow-empty-passwords? #f))))))
+
+ ;; The list of user accounts ('root' is implicit).
+ (users
+ (cons* (user-account
+ (name "timo")
+ (comment "Timo Wilken")
+ (group "users")
+ (home-directory "/home/timo")
+ (supplementary-groups '("wheel" "netdev" "audio" "video"))
+ (shell (file-append zsh "/bin/zsh")))
+ (user-account ; TODO: merge with "timo"?
+ (name "timo-phone")
+ (comment "Backups of Timo's phone")
+ (group "users")
+ (home-directory "/var/backups/timo-phone")
+ (shell (file-append bash-minimal "/bin/sh")))
+ (user-account
+ (name "robin")
+ (comment "Robin Wilken")
+ (group "users")
+ (home-directory "/home/robin"))
+ (user-account
+ (name "ira")
+ (comment "Ira Wilken")
+ (group "users")
+ (home-directory "/home/ira"))
+ (user-account
+ (system? #t)
+ (name "syncthing")
+ (comment "Syncthing service")
+ (group "syncthing")
+ (home-directory "/var/data/syncthing"))
+ %base-user-accounts))
+
+ (groups
+ (cons* (user-group ; This is NOT implict from the "syncthing" user.
+ (system? #t)
+ (name "syncthing"))
+ %base-groups))
+
+ ;; Use the UEFI variant of GRUB with the EFI System Partition mounted
+ ;; on /boot/efi.
+ (bootloader
+ (bootloader-configuration
+ (bootloader grub-efi-bootloader)
+ (targets '("/boot/efi"))
+ (keyboard-layout keyboard-layout)))
+
+ ;; The list of file systems that get "mounted". The unique
+ ;; file system identifiers there ("UUIDs") can be obtained
+ ;; by running 'blkid' in a terminal.
+ (file-systems
+ (cons* (file-system
+ (mount-point "/")
+ (device guixsd-root-partition)
+ (flags '(no-atime))
+ (options (alist->file-system-options
+ '("ssd" ("compress" . "zstd"))))
+ (type "btrfs"))
+ (file-system
+ (mount-point "/boot/efi")
+ (device efi-system-partition)
+ (flags '(no-atime))
+ (type "vfat"))
+ (file-system
+ (mount-point "/var/backups")
+ (create-mount-point? #t)
+ (device backups-partition)
+ (flags '(no-atime))
+ (type "btrfs"))
+ (file-system
+ (mount-point "/var/data")
+ (create-mount-point? #t)
+ (device data-partition)
+ (flags '(no-atime))
+ (type "btrfs"))
+ %base-file-systems)))