summaryrefslogtreecommitdiff
path: root/hostnix/weebnix
diff options
context:
space:
mode:
Diffstat (limited to 'hostnix/weebnix')
-rw-r--r--hostnix/weebnix/Makefile7
-rw-r--r--hostnix/weebnix/boot/config.txt36
-rw-r--r--hostnix/weebnix/configuration.nix93
-rw-r--r--hostnix/weebnix/dyndns.nix78
-rw-r--r--hostnix/weebnix/hardware-configuration.nix51
-rw-r--r--hostnix/weebnix/home-assistant.nix116
-rw-r--r--hostnix/weebnix/oidc.nix51
-rw-r--r--hostnix/weebnix/privacy-frontends.nix15
-rw-r--r--hostnix/weebnix/syncthing.nix136
-rw-r--r--hostnix/weebnix/system.nix49
10 files changed, 632 insertions, 0 deletions
diff --git a/hostnix/weebnix/Makefile b/hostnix/weebnix/Makefile
new file mode 100644
index 0000000..90591a9
--- /dev/null
+++ b/hostnix/weebnix/Makefile
@@ -0,0 +1,7 @@
+push:
+ rsync --rsync-path='sudo rsync' *.nix weebnix.lan:/etc/nixos/
+
+switch: push
+ ssh weebnix.lan sudo nixos-rebuild switch
+
+.PHONY: push switch
diff --git a/hostnix/weebnix/boot/config.txt b/hostnix/weebnix/boot/config.txt
new file mode 100644
index 0000000..b407ad7
--- /dev/null
+++ b/hostnix/weebnix/boot/config.txt
@@ -0,0 +1,36 @@
+[pi3]
+kernel=u-boot-rpi3.bin
+
+[pi02]
+kernel=u-boot-rpi3.bin
+
+[pi4]
+kernel=u-boot-rpi4.bin
+enable_gic=1
+armstub=armstub8-gic.bin
+
+# Otherwise the resolution will be weird in most cases, compared to
+# what the pi3 firmware does by default.
+disable_overscan=1
+
+# Supported in newer board revisions
+arm_boost=1
+
+[cm4]
+# Enable host mode on the 2711 built-in XHCI USB controller.
+# This line should be removed if the legacy DWC2 controller is required
+# (e.g. for USB device mode) or if USB support is not required.
+otg_mode=1
+
+[all]
+# Boot in 64-bit mode.
+arm_64bit=1
+
+# U-Boot needs this to work, regardless of whether UART is actually used or not.
+# Look in arch/arm/mach-bcm283x/Kconfig in the U-Boot tree to see if this is still
+# a requirement in the future.
+enable_uart=1
+
+# Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
+# when attempting to show low-voltage or overtemperature warnings.
+avoid_warnings=1
diff --git a/hostnix/weebnix/configuration.nix b/hostnix/weebnix/configuration.nix
new file mode 100644
index 0000000..a0166f5
--- /dev/null
+++ b/hostnix/weebnix/configuration.nix
@@ -0,0 +1,93 @@
+{ config, pkgs, ... }:
+
+{
+ imports = [
+ ./dyndns.nix
+ ./hardware-configuration.nix
+ ./home-assistant.nix
+ ./oidc.nix
+ ./privacy-frontends.nix
+ ./syncthing.nix
+ ./system.nix
+ ];
+
+ nix.settings.experimental-features = [ "nix-command" "flakes" ];
+ nix.settings.trusted-users = [ "joe" ];
+
+ security.sudo.wheelNeedsPassword = false;
+
+ security.acme.acceptTerms = true;
+ security.acme.defaults.email = "hostmaster@mou.fo";
+ # TODO switch to production certs
+ security.acme.defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory";
+
+ users.users.joe = {
+ isNormalUser = true;
+ extraGroups = [ "wheel" "syncthing" ];
+ openssh.authorizedKeys.keys = [
+ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHcqQDnH0LcUWFV+cd9aABfM55+72UAn1ZY5x5bHwPL4IEgT1nagbi1X3FwCJkh2rEcDsHl4FflcNfh+IyU2VyuQfRIXl7CKP040ovXmPVzgU8JiEDrrRebpZ7aHCKk+4Q6cJ8dzAI1sRogVyYrV0hLB4yeMnVexkIcsQMt5pXQ1zodlzHfW1W7OWQDbKjIyh4pv1KJ/IIjiBIt7l+OCqi7wZK4ubmxyMhmZx1xpRC5mz2/29Mpt+1VgCmxC7Hv1SG7yu+U0s4eJ3kbzFKNcZ/bCYqFxK48dT66qhS3qZFg09omumG8IbEUcx+WqM1V7WhiJYig9x5ovmMToQXTJ5uxLtcovnxO/53IgwV7INvmr8+NhD+LlkQfSjjUAW09bhVj9sKIW2bbrIxlOT8z6CQY9zGXNXi8u1oxPt3Q7d3rMxoWhWnr2l3Ok7OIkWooOK3e0NdhgIAxZKlYJAmIYaX391sGTyiuwUy96mg5JcYsLYMfkEg/Sv+2vQp8kkvB0E= joe@sparky"
+ ];
+ };
+
+ environment.systemPackages = with pkgs; [
+ dig
+ file
+ gitFull
+ jq
+ libraspberrypi
+ sqlite-interactive
+ tmux
+ tree
+ ];
+
+ programs.vim.defaultEditor = true;
+ programs.nano.enable = false;
+
+ services.openssh.enable = true;
+
+ services.nginx = {
+ enable = true;
+ recommendedGzipSettings = true;
+ recommendedOptimisation = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+ # Slightly crazy setup to SNI reverse proxy HTTPS to multiple upstreams.
+ # We displace ourselves onto port 8443, and send requests that are not
+ # intended for us to weeber. This is done because Apache running on weeber
+ # cannot SNI reverse proxy, so we put weebnix in front of weeber on IPv4.
+ # TODO get rid of all this when replacing weeber or maybe consider HAProxy
+ defaultSSLListenPort = 8443;
+ streamConfig = ''
+ map $ssl_preread_server_name $selected_upstream {
+ hostnames;
+ weebnix.mou.fo self;
+ *.weebnix.mou.fo self;
+ default weeber;
+ }
+ upstream self { server 127.0.0.1:8443; }
+ upstream weeber { server 192.168.0.168:443; }
+ server {
+ listen 0.0.0.0:443;
+ listen [::0]:443;
+ proxy_pass $selected_upstream;
+ ssl_preread on;
+ }
+ '';
+ };
+
+ # TODO remove upon switching to production certs
+ services.oauth2_proxy.extraConfig = {
+ "ssl-insecure-skip-verify" = true;
+ "ssl-upstream-insecure-skip-verify" = true;
+ };
+
+ networking.firewall.allowedTCPPorts = [ 80 443 ];
+
+ # This value determines the NixOS release from which the default
+ # settings for stateful data, like file locations and database versions
+ # on your system were taken. It's perfectly fine and recommended to leave
+ # this value at the release version of the first install of this system.
+ # Before changing this value read the documentation for this option
+ # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+ system.stateVersion = "23.05"; # Did you read the comment?
+}
diff --git a/hostnix/weebnix/dyndns.nix b/hostnix/weebnix/dyndns.nix
new file mode 100644
index 0000000..a59c665
--- /dev/null
+++ b/hostnix/weebnix/dyndns.nix
@@ -0,0 +1,78 @@
+{ config, pkgs, ... }:
+
+{
+ # Needs to be started manually, and the key added to nameservers.
+ # Based on https://nixos.org/manual/nixos/stable/index.html#module-security-acme-config-dns
+ systemd.services.sig0-keygen = {
+ unitConfig = {
+ ConditionPathExists = "!/var/lib/secrets/${config.networking.fqdn}.id";
+ };
+ serviceConfig = {
+ Type = "oneshot";
+ };
+ path = [ pkgs.bind ];
+ scriptArgs = config.networking.fqdn;
+ script = ''
+ mkdir -p /var/lib/secrets
+ chmod 755 /var/lib/secrets
+ cd /var/lib/secrets
+ dnssec-keygen -a RSASHA512 -b 2048 -n HOST -T KEY $1. > $1.id
+ '';
+ };
+
+ systemd.services.dyndns = {
+ requires = [ "network-online.target" ];
+ after = [ "network-online.target" ];
+ unitConfig = {
+ AssertPathExists = "/var/lib/secrets/${config.networking.fqdn}.id";
+ # Defer errors for ~45min, throttle e-mails to ~hourly.
+ StartLimitIntervalSec = "1hr";
+ StartLimitBurst = "45";
+ };
+ serviceConfig = {
+ Type = "oneshot";
+ Restart = "on-failure";
+ RestartSec = "1min";
+ };
+ path = [ pkgs.dnsutils pkgs.gawk pkgs.iproute2 ];
+ scriptArgs = config.networking.fqdn;
+ script = ''
+ RR=''${1%%.*}.dynamic.''${1#*.}
+
+ IP4=`dig +short @1.1.1.1 ch txt whoami.cloudflare | tr -d \"`
+ if [ -z "$IP4" ]; then
+ echo "Missing IP: $IP4" >&2
+ exit 100
+ fi
+
+ # Follow some RFC 6724 default address guidance, excluding ULA.
+ # It might be more robust to bind a public source socket (RFC 5014).
+ IP6=`ip -6 address show scope global -deprecated | awk -F'[ /]+' '$2 == "inet6" && $3 !~ /^f[cd]/ { print $3; exit }'`
+
+ OLDIP4=`dig +short @popfresh.mou.fo $RR A 2> /dev/null`
+ OLDIP6=`dig +short @popfresh.mou.fo $RR AAAA 2> /dev/null`
+ # [ "x$IP" = "x$OLDIP4" ] && exit 0 # no update
+ if [ "x$IP4" = "x$OLDIP4" -a "x$IP6" = "x$OLDIP6" ]; then
+ exit 0
+ fi
+
+ nsupdate -v -k /var/lib/secrets/`< /var/lib/secrets/$1.id`.private <<.
+ update delete $RR. A
+ update add $RR. 300 A $IP4
+ update delete $RR. AAAA
+ ''${IP6:+update add $RR. 300 AAAA $IP6}
+ update delete $RR. TXT
+ update add $RR. 300 TXT "v=spf1 include:_spf.mou.fo ~all"
+ send
+ .
+ '';
+ };
+
+ systemd.timers.dyndns = {
+ wantedBy = [ "multi-user.target" ];
+ timerConfig = {
+ OnStartupSec = "10";
+ OnUnitActiveSec = "1min";
+ };
+ };
+}
diff --git a/hostnix/weebnix/hardware-configuration.nix b/hostnix/weebnix/hardware-configuration.nix
new file mode 100644
index 0000000..d7ce9dc
--- /dev/null
+++ b/hostnix/weebnix/hardware-configuration.nix
@@ -0,0 +1,51 @@
+# Do not modify this file! It was generated by ‘nixos-generate-config’
+# and may be overwritten by future invocations. Please make changes
+# to /etc/nixos/configuration.nix instead.
+{ config, lib, pkgs, modulesPath, ... }:
+
+{
+ imports =
+ [ (modulesPath + "/installer/scan/not-detected.nix")
+ ];
+
+ boot.initrd.availableKernelModules = [ "xhci_pci" "usbhid" "usb_storage" ];
+ boot.initrd.kernelModules = [ ];
+ boot.kernelModules = [ ];
+ boot.extraModulePackages = [ ];
+
+ fileSystems."/" =
+ { device = "/dev/disk/by-uuid/574841f9-3d47-419b-a431-e0c0c0c4ee9d";
+ fsType = "btrfs";
+ options = [ "subvol=nixos-root" ];
+ };
+
+ fileSystems."/nix" =
+ { device = "/dev/disk/by-uuid/574841f9-3d47-419b-a431-e0c0c0c4ee9d";
+ fsType = "btrfs";
+ options = [ "subvol=nix,noatime" ];
+ };
+
+ fileSystems."/home" =
+ { device = "/dev/disk/by-uuid/574841f9-3d47-419b-a431-e0c0c0c4ee9d";
+ fsType = "btrfs";
+ options = [ "subvol=home" ];
+ };
+
+ fileSystems."/boot" =
+ { device = "/dev/disk/by-uuid/8D56-48CD";
+ fsType = "vfat";
+ };
+
+ swapDevices = [ ];
+
+ # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
+ # (the default) this is the recommended approach. When using systemd-networkd it's
+ # still possible to use this option, but it's recommended to use it in conjunction
+ # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
+ networking.useDHCP = lib.mkDefault true;
+ # networking.interfaces.end0.useDHCP = lib.mkDefault true;
+ # networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
+
+ nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
+ powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
+}
diff --git a/hostnix/weebnix/home-assistant.nix b/hostnix/weebnix/home-assistant.nix
new file mode 100644
index 0000000..77c7fa8
--- /dev/null
+++ b/hostnix/weebnix/home-assistant.nix
@@ -0,0 +1,116 @@
+{ pkgs, ... }:
+
+{
+ services.postgresql = {
+ enable = true;
+ ensureDatabases = [ "hass" ];
+ ensureUsers = [{
+ name = "hass";
+ ensureDBOwnership = true;
+ }];
+ };
+
+ services.home-assistant = {
+ enable = true;
+ extraPackages = ps: with ps; [ psycopg2 ];
+ extraComponents = [
+ "androidtv_remote"
+ "apple_tv"
+ "cast"
+ "homekit_controller"
+ "hue"
+ "spotify"
+ "esphome"
+ "met"
+ "radio_browser"
+ ];
+ customComponents = [
+ (
+ pkgs.buildHomeAssistantComponent rec {
+ owner = "BeryJu";
+ domain = "auth_header";
+ version = "1.10";
+ src = pkgs.fetchFromGitHub {
+ inherit owner;
+ repo = "hass-auth-header";
+ rev = "refs/tags/v${version}";
+ hash = "sha256-dSmY3d8Kx0pXl+20dTGAYgjSH6OhNh53jPX7VLCZs7Y=";
+ };
+ dontBuild = true;
+ }
+ )
+ (
+ pkgs.buildHomeAssistantComponent rec {
+ owner = "make-all";
+ domain = "tuya_local";
+ version = "2023.12.1";
+ src = pkgs.fetchFromGitHub {
+ inherit owner;
+ repo = "tuya-local";
+ rev = "refs/tags/${version}";
+ hash = "sha256-vi5EmtXAyXaUbJl+yAT5EL0yYb3XFRaAj6fybQRCM4A=";
+ };
+ propagatedBuildInputs = with pkgs.home-assistant.python.pkgs; [
+ (
+ buildPythonPackage rec {
+ pname = "tinytuya";
+ version = "1.13.1";
+ format = "wheel";
+ src = pkgs.fetchPypi {
+ inherit pname version format;
+ hash = "sha256-j7t4P4U9iuVHyb6HASkf7LmBheHN32IjdKE60HUbjIE=";
+ };
+ }
+ )
+ colorama
+ ];
+ dontBuild = true;
+ }
+ )
+ ];
+ config = {
+ default_config = { };
+ http = {
+ server_host = "::1";
+ trusted_proxies = [ "::1" ];
+ use_x_forwarded_for = true;
+ };
+ recorder.db_url = "postgresql://@/hass";
+ auth_header = { };
+ };
+ };
+
+ services.nginx.virtualHosts."ha.weebnix.mou.fo" = {
+ enableACME = true;
+ forceSSL = true;
+ locations."/" = {
+ proxyPass = "http://[::1]:8123";
+ proxyWebsockets = true;
+ extraConfig = ''
+ # This is frequently used in examples but without clear explanation. It
+ # might help with WebSockets.
+ proxy_buffering off;
+ # oauth2_proxy NixOS module sets some non-standard headers, but we need
+ # the preferred_username claim.
+ auth_request_set $preferred_username $upstream_http_x_auth_request_preferred_username;
+ proxy_set_header X-Forwarded-Preferred-Username $preferred_username;
+ '';
+ };
+ # Duplicate relevant parts of root route to skip oauth2-proxy module magic.
+ locations."/api/" = {
+ proxyPass = "http://[::1]:8123";
+ proxyWebsockets = true;
+ extraConfig = ''
+ proxy_buffering off;
+ '';
+ };
+ # Disable service worker caching that works improperly with reverse proxy.
+ # https://github.com/home-assistant/frontend/issues/14836
+ # https://community.home-assistant.io/t/disabling-service-worker-reverse-proxy-auth-causes-issues/167082
+ locations."/service_worker.js" = {
+ return = ''410 "Service worker disabled: https://github.com/home-assistant/frontend/issues/14836"'';
+ };
+ };
+
+ services.oauth2_proxy.nginx.virtualHosts = [ "ha.weebnix.mou.fo" ];
+}
diff --git a/hostnix/weebnix/oidc.nix b/hostnix/weebnix/oidc.nix
new file mode 100644
index 0000000..bf70882
--- /dev/null
+++ b/hostnix/weebnix/oidc.nix
@@ -0,0 +1,51 @@
+{ ... }:
+
+{
+ services.keycloak = {
+ enable = true;
+ database.passwordFile = "/var/lib/secrets/keycloak.dbpass";
+ settings = {
+ hostname = "kc.weebnix.mou.fo";
+ http-host = "127.0.0.1";
+ http-port = 7567;
+ proxy = "edge";
+ };
+ };
+
+ services.nginx.virtualHosts."kc.weebnix.mou.fo" = {
+ enableACME = true;
+ forceSSL = true;
+ locations."/".proxyPass = "http://127.0.0.1:7567";
+ # We can handle oauth2-proxy callbacks on any subdomain, but the Keycloak
+ # subdomain is the least arbitrary.
+ locations."/oauth2/".proxyPass = "http://127.0.0.1:4180";
+ };
+
+ # Work around "upstream sent too big header" because of large tokens.
+ services.nginx.appendHttpConfig = ''
+ proxy_buffers 8 16k;
+ proxy_buffer_size 16k;
+ '';
+
+ # The oauth2_proxy module has a magic nginx.virtualHosts option that rewrites
+ # nginx configs. It's mostly unhelpful, but we use it for brevity. In
+ # particular, it configures Traefik-like ForwardAuth authentication with
+ # auth_request. Note if this resource is missing for whatever reason, the
+ # module magic will fail open (auth_request unset).
+ services.oauth2_proxy = {
+ enable = true;
+ cookie.domain = "weebnix.mou.fo";
+ setXauthrequest = true; # include claims
+ email.domains = [ "*" ]; # allow any authenticated user
+ # https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/oauth_provider/#keycloak-oidc-auth-provider
+ provider = "keycloak-oidc";
+ clientID = "weebnix.mou.fo";
+ # Sets OAUTH2_PROXY_COOKIE_SECRET and OAUTH2_PROXY_CLIENT_SECRET.
+ keyFile = "/var/lib/secrets/oauth2-proxy.env";
+ redirectURL = "https://kc.weebnix.mou.fo/oauth2/callback";
+ extraConfig = {
+ "oidc-issuer-url" = "https://kc.weebnix.mou.fo/realms/staging";
+ "whitelist-domain" = ".weebnix.mou.fo";
+ };
+ };
+}
diff --git a/hostnix/weebnix/privacy-frontends.nix b/hostnix/weebnix/privacy-frontends.nix
new file mode 100644
index 0000000..b312155
--- /dev/null
+++ b/hostnix/weebnix/privacy-frontends.nix
@@ -0,0 +1,15 @@
+{ ... }:
+
+{
+ services.libreddit = {
+ enable = true;
+ address = "[::1]";
+ port = 7682;
+ };
+
+ services.nginx.virtualHosts."lr.weebnix.mou.fo" = {
+ enableACME = true;
+ forceSSL = true;
+ locations."/".proxyPass = "http://[::1]:7682";
+ };
+}
diff --git a/hostnix/weebnix/syncthing.nix b/hostnix/weebnix/syncthing.nix
new file mode 100644
index 0000000..a0a09be
--- /dev/null
+++ b/hostnix/weebnix/syncthing.nix
@@ -0,0 +1,136 @@
+{ ... }:
+
+let
+ staggeredVersioning = {
+ type = "staggered";
+ params = {
+ cleanInterval = "3600";
+ maxAge = "31536000";
+ };
+ };
+in
+{
+ systemd.tmpfiles.rules = [
+ "d /var/lib/syncthing 0775 syncthing syncthing"
+ ];
+
+ systemd.services.syncthing = {
+ serviceConfig.UMask = "0002";
+ };
+
+ services.syncthing = {
+ enable = true;
+ openDefaultPorts = true;
+ # Syncthing supports named sockets but the NixOS module assumes network.
+ guiAddress = "[::1]:8384";
+ settings = {
+ devices = {
+ "Asus Nexus 7" = {
+ id = "BVZARYC-2D56A6I-V6L2VQF-MU7IVCT-ITJTCGQ-IGMZG2W-RZRCTOT-K4GDHAY";
+ };
+ "DESKTOP-SFVBFBU" = {
+ id = "FQEK2MG-2AVMHEM-H6KASQ3-RTA3Z3F-A4R4MUY-YELZVRQ-6QUDSHA-DZZN7AJ";
+ autoAcceptFolders = true;
+ };
+ "Joes-iPhone-6" = {
+ id = "F5APH5K-XXO454B-6YU4BTT-YPHF4KT-OD7YF5Y-JTWJRSU-UNJ2KZK-IVJZNQT";
+ autoAcceptFolders = true;
+ };
+ "iPad" = {
+ id = "U7D7667-RFEFHXX-TUJGGII-CE62S6P-YC6MWNV-4LBJ4YJ-5ZUZVPT-GBC5PQH";
+ autoAcceptFolders = true;
+ };
+ "maxsettings-C6554E6AF22F" = {
+ id = "HO3QQZO-RDWYDB6-U74ZQRC-FP7YPB2-IPB2EBC-KIQ5JII-FD4KBXR-J3GCOQ5";
+ autoAcceptFolders = true;
+ };
+ "penguin" = {
+ id = "5BEB6SZ-YAPV3CC-54RZF3V-HQXXP3Y-TTVDWDU-SHHNVCH-IXKZ3O2-6RXG6QL";
+ autoAcceptFolders = true;
+ };
+ "sparky" = {
+ id = "FE43LDI-33WS467-LIGFWCC-5PPSKN6-GYODEWJ-KLQZLN7-H3GYGLG-IJ2JGQW";
+ autoAcceptFolders = true;
+ };
+ "steamdeck" = {
+ id = "SCUAABL-XU6AS5H-IZZE4PN-LY5J4LH-OYZMXTU-2UMTVUL-I7B7QKE-ZBPSAQ5";
+ autoAcceptFolders = true;
+ };
+ "weeber.mou.fo" = {
+ id = "PRE6XCX-7JDMJGJ-6TPMHOS-TP2AT3S-T6CAR3Z-URL5EEU-HVXUDJ4-C5UJ2AV";
+ autoAcceptFolders = true;
+ };
+ };
+ folders = {
+ "Documents" = {
+ id = "bhemx-9nh3v";
+ path = "~/Documents";
+ versioning = staggeredVersioning;
+ devices = [ "sparky" "weeber.mou.fo" ];
+ };
+ "Downloads" = {
+ id = "kvq6q-axjhu";
+ path = "~/Downloads";
+ versioning = staggeredVersioning;
+ devices = [ "sparky" "weeber.mou.fo" ];
+ };
+ "Game/Documents/Bioshock" = {
+ id = "7zhqz-x6uvw";
+ path = "~/Game/Documents/Bioshock";
+ versioning = staggeredVersioning;
+ devices = [ "weeber.mou.fo" ];
+ };
+ "Game/Epic Games/TheTalosPrinciple/UserData" = {
+ id = "vek7u-iausx";
+ path = "~/Game/Epic Games/TheTalosPrinciple/UserData";
+ versioning = staggeredVersioning;
+ devices = [ "DESKTOP-SFVBFBU" "maxsettings-C6554E6AF22F" "weeber.mou.fo" ];
+ };
+ "Game/PCSX2" = {
+ id = "chxsg-hpqgm";
+ path = "~/Game/PCSX2";
+ versioning = staggeredVersioning;
+ devices = [ "maxsettings-C6554E6AF22F" "weeber.mou.fo" ];
+ };
+ "Pictures" = {
+ id = "vfjsd-4fczh";
+ path = "~/Pictures";
+ versioning = staggeredVersioning;
+ devices = [ "sparky" "weeber.mou.fo" ];
+ };
+ "Sync" = {
+ id = "7thks-5badk";
+ path = "~/Sync";
+ versioning = staggeredVersioning;
+ devices = [
+ "Asus Nexus 7"
+ "DESKTOP-SFVBFBU"
+ "Joes-iPhone-6"
+ "iPad"
+ "penguin"
+ "sparky"
+ "weeber.mou.fo"
+ ];
+ };
+ "iPad" = {
+ id = "qtzmu-fqdrs";
+ path = "~/iPad";
+ versioning = staggeredVersioning;
+ devices = [ "iPad" "weeber.mou.fo" ];
+ };
+ };
+ };
+ };
+
+ services.nginx.virtualHosts."st.weebnix.mou.fo" = {
+ enableACME = true;
+ forceSSL = true;
+ locations."/" = {
+ proxyPass = "http://[::1]:8384";
+ # https://docs.syncthing.net/users/faq.html#why-do-i-get-host-check-error-in-the-gui-api
+ recommendedProxySettings = false;
+ };
+ };
+
+ services.oauth2_proxy.nginx.virtualHosts = [ "st.weebnix.mou.fo" ];
+}
diff --git a/hostnix/weebnix/system.nix b/hostnix/weebnix/system.nix
new file mode 100644
index 0000000..8c80708
--- /dev/null
+++ b/hostnix/weebnix/system.nix
@@ -0,0 +1,49 @@
+{ pkgs, lib, ... }:
+
+{
+ boot.loader.systemd-boot.enable = true;
+ # Raspberry Pi has no NVRAM.
+ boot.loader.efi.canTouchEfiVariables = false;
+
+ boot.kernelPackages = pkgs.linuxPackages_rpi4;
+ # https://github.com/NixOS/nixpkgs/issues/122130#issuecomment-1568815007
+ # It's unclear if these are strictly necessary with the downstream kernel,
+ # but let's leave them in to keep working with mainline.
+ boot.initrd.availableKernelModules = [ "uas" "pcie-brcmstb" "reset-raspberrypi" ];
+
+ networking.hostName = "weebnix";
+ networking.domain = "mou.fo";
+ # TODO secrets management or switch to wired
+ networking.wireless = {
+ enable = true;
+ networks."oldschool".psk = builtins.readFile /var/lib/secrets/oldschool.wpa-psk;
+ };
+
+ systemd.network.enable = true;
+ networking.useNetworkd = true;
+ networking.dhcpcd.enable = false;
+ networking.tempAddresses = "disabled";
+
+ systemd.network.networks = let
+ default = {
+ networkConfig = {
+ DHCP = "yes";
+ MulticastDNS = "yes";
+ };
+ ipv6AcceptRAConfig.Token = "prefixstable"; # RFC 7217
+ };
+ in {
+ "10-wlan" = lib.recursiveUpdate default {
+ matchConfig.Name = "wlan0";
+ };
+ "10-eth" = lib.recursiveUpdate default {
+ matchConfig.Name = "end0";
+ linkConfig.RequiredForOnline = "no";
+ };
+ };
+
+ # Problematic when the clock is unreliable (Pi has no RTC).
+ services.resolved.dnssec = "false";
+
+ time.timeZone = "America/New_York";
+}