From 3d331a392742d9db2f811547d122bb60d972da43 Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Sat, 31 Dec 2022 13:28:51 +0100 Subject: Track system configuration --- tw/system/common.scm | 103 +++++++++ tw/system/files/kitchen-pc.pub | 1 + tw/system/files/nextcloud-backup | 68 ++++++ tw/system/files/timo.pub | 1 + tw/system/files/wilken-laptop.pub | 1 + tw/system/lap.scm | 391 ++++++++++++++++++++++++++++++++++ tw/system/lud.scm | 438 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 1003 insertions(+) create mode 100644 tw/system/common.scm create mode 100644 tw/system/files/kitchen-pc.pub create mode 100755 tw/system/files/nextcloud-backup create mode 100644 tw/system/files/timo.pub create mode 100644 tw/system/files/wilken-laptop.pub create mode 100644 tw/system/lap.scm create mode 100644 tw/system/lud.scm 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 . +(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. + + AllowOverride None + + + + Options +FollowSymlinks + AllowOverride All + + Dav off + + SetEnv HOME /var/www/nextcloud + SetEnv HTTP_HOME /var/www/nextcloud + + +# Redirect to local php-fpm if mod_php is not available + + + # Enable http authorization headers + + SetEnvIfNoCase ^Authorization$ \"(.+)\" HTTP_AUTHORIZATION=$1 + + + + SetHandler \"proxy:unix:/var/run/php-fpm.sock|fcgi://localhost/\" + + + # Deny access to raw PHP sources and files without filename (e.g. '.php') + + Require all denied + + + +")))) + + (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))) -- cgit v1.2.3