From fd870b66be8142ec255b78a24ecd7993870347be Mon Sep 17 00:00:00 2001 From: Skyler Grey Date: Wed, 15 Oct 2025 23:21:19 +0000 Subject: [PATCH] feat(pm): block missing nginx host connections Change-Id: lppnnvqpmowyzpslvqtklqswqmypwryw We previously returned One Of The Websites when nginx was accessed from a host that we didn't know about. That included direct IP address access as well as things which have been CNAMEd to us (either through a starred record or due to past services) but which aren't actually hosted by us. This leads to a number of undesireable effects: - User confusion ("why does the aux docs website have Stalwart?") - Incorrect SSL certificates ("your blog seems to have an invalid certificate") - SSL being offered via direct IPs, which isn't possible to sign on the public internet We can block this by making a default server to take control whenever nothing matches, and setting that default server to block all connections and reject all SSL handshakes We need to have a certificate for this, but it needn't actually be valid for anything so let's self sign stuff... --- packetmix/systems/common/nginx.nix | 42 ++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 packetmix/systems/common/nginx.nix diff --git a/packetmix/systems/common/nginx.nix b/packetmix/systems/common/nginx.nix new file mode 100644 index 00000000..f91803fb --- /dev/null +++ b/packetmix/systems/common/nginx.nix @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2025 FreshlyBakedCake +# +# SPDX-License-Identifier: MIT + +{ config, lib, ... }: +{ + # By default, nginx will serve a "best-effort" site even if there is no matching vhost + # We can disable this by making a matching vhost and returning 444... + # Notice how we don't enable nginx here: that makes this safe to deploy even on places that don't currently run nginx. We're effectively changing the default behavior + services.nginx.virtualHosts."missinghost.invalid" = { + default = true; + + addSSL = true; + enableACME = true; + acmeRoot = null; + + locations."/".return = "444"; + + extraConfig = '' + ssl_reject_handshake on; + ''; + }; + + systemd.services."acme-missinghost.invalid".enable = false; + systemd.timers."acme-missinghost.invalid".enable = false; + + systemd.targets."acme-finished-missinghost.invalid" = { + requires = lib.mkForce [ "acme-selfsigned-missinghost.invalid.service" ]; + after = lib.mkForce [ "acme-selfsigned-missinghost.invalid.service" ]; + }; + + security.acme.acceptTerms = true; + security.acme.certs = lib.mkIf config.services.nginx.enable { + "missinghost.invalid" = { + dnsProvider = null; + listenHTTP = null; + s3Bucket = null; + webroot = "/dev/null"; + email = "invalid@missinghost.invalid"; + }; # Nix requires some values, even if we're actually disabling the acme-missinghost.invalid service... that's problematic if there are no defaults for the system + }; +} -- 2.43.0 From 2fcee37b13673013dccb9ab02aa2a72caaca2583 Mon Sep 17 00:00:00 2001 From: Skyler Grey Date: Wed, 15 Oct 2025 23:21:19 +0000 Subject: [PATCH] feat(pm/umber): clean up silverbullet SSL Change-Id: ukuomtnrpmmqlmvmxktwtuwqmmpsxvyw There's no need for us to be listening for silverbullet on our clicks.domains host, nor should we be listening for plain HTTP anymore --- packetmix/systems/umber/silverbullet.nix | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packetmix/systems/umber/silverbullet.nix b/packetmix/systems/umber/silverbullet.nix index 6c4849f2..72edf7be 100644 --- a/packetmix/systems/umber/silverbullet.nix +++ b/packetmix/systems/umber/silverbullet.nix @@ -28,12 +28,10 @@ services.nginx.virtualHosts."silverbullet.starrysky.fyi" = { listenAddresses = [ "localhost.tailscale" ]; - addSSL = true; + onlySSL = true; enableACME = true; acmeRoot = null; - serverAliases = [ "umber.clicks.domains" ]; - locations."/" = { proxyPass = "http://$silverbullet_upstream_minion_only"; recommendedProxySettings = true; -- 2.43.0 From 4c9a44a83797f8fd2617e546bc0845a3bab22545 Mon Sep 17 00:00:00 2001 From: Skyler Grey Date: Wed, 15 Oct 2025 23:21:19 +0000 Subject: [PATCH] feat(pm/umber): init grocy Change-Id: zoqyltwplryxqptuulosrpxplxlpzssk Grocy is a stock tracking application for groceries. I'd like to use it to keep track of some of my stuff, so let's host it on umber! --- packetmix/systems/umber/grocy.nix | 34 ++++++++++++++++++++ packetmix/systems/umber/grocy/custom_js.html | 27 ++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 packetmix/systems/umber/grocy.nix create mode 100644 packetmix/systems/umber/grocy/custom_js.html diff --git a/packetmix/systems/umber/grocy.nix b/packetmix/systems/umber/grocy.nix new file mode 100644 index 00000000..34070ed8 --- /dev/null +++ b/packetmix/systems/umber/grocy.nix @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: 2025 FreshlyBakedCake +# +# SPDX-License-Identifier: MIT + +{ pkgs, lib, ... }: +{ + services.grocy = { + enable = true; + package = pkgs.stdenv.mkDerivation { + name = "grocy-custom-js"; + src = pkgs.grocy; + + dontBuild = true; + installPhase = '' + mkdir -p $out/ + cp -r * $out/ + + mkdir -p $out/data/ + cp ${./grocy/custom_js.html} $out/data/custom_js.html # we need to specify the filename explicitly, as otherwise this'll have a hash + ''; + }; + hostName = "grocy.starrysky.fyi"; + + settings.currency = "GBP"; + }; + + services.nginx.virtualHosts."grocy.starrysky.fyi" = { + acmeRoot = null; + forceSSL = lib.mkForce false; + onlySSL = true; + }; + + clicks.storage.impermanence.persist.directories = [ "/var/lib/grocy" ]; +} diff --git a/packetmix/systems/umber/grocy/custom_js.html b/packetmix/systems/umber/grocy/custom_js.html new file mode 100644 index 00000000..c1160ddb --- /dev/null +++ b/packetmix/systems/umber/grocy/custom_js.html @@ -0,0 +1,27 @@ + + + -- 2.43.0 From 9eca3e58b392c5272c251bcce2b26279552b8481 Mon Sep 17 00:00:00 2001 From: Skyler Grey Date: Sat, 3 Jan 2026 22:35:18 +0000 Subject: [PATCH] feat(pm/umber): add copyparty Change-Id: qqpzsrlryuvskrxpqrrzlvvssqnnomsy I want a private file host for things I can't put on our main copyparty instance. I'll host that on umber --- packetmix/systems/umber/copyparty.nix | 138 ++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 packetmix/systems/umber/copyparty.nix diff --git a/packetmix/systems/umber/copyparty.nix b/packetmix/systems/umber/copyparty.nix new file mode 100644 index 00000000..f8174dcc --- /dev/null +++ b/packetmix/systems/umber/copyparty.nix @@ -0,0 +1,138 @@ +# SPDX-FileCopyrightText: 2025 FreshlyBakedCake +# +# SPDX-License-Identifier: MIT + +{ + project, + pkgs, + config, + lib, + ... +}: +{ + imports = [ + project.inputs.copyparty.result.nixosModules.default + ]; + + config = { + nixpkgs.overlays = [ project.inputs.copyparty.result.overlays.default ]; + + services.copyparty = + let + admins = [ + "minion" + ]; + in + { + enable = true; + + settings = { + i = "127.0.0.1"; # ip + p = 1030; # port + + # we'll be using nginx for this... + http-only = true; + no-crt = true; + + idp-store = 3; + idp-h-usr = "X-Webauth-Login"; + idp-adm = admins; + have-idp-hdrs = 1; # https://github.com/9001/copyparty/issues/849 + + shr = "/share"; + shr-db = "/var/lib/copyparty/shares.db"; + shr-adm = admins; + + # as we might have private directories, better to be a bit conservative about permissions... + chmod-f = 700; + chmod-d = 700; + + magic = true; # "enable filetype detection on nameless uploads" + + e2dsa = true; # index files to allow searching, upload undo, etc. + e2ts = true; # and scan metadata... + + rss = true; # allow (experimental) rss support -> useful for antennapod/miniflux/co. + dav-auth = true; # "force auth for all folders" notably "(required by davfs2 when only some folders are world-readable)" + + xvol = true; # don't allow symlinks to break out of confinement... + no-robots = true; # not really meant to be indexed. Maybe we want to add anubis at some point too... + + ah-alg = "argon2"; + + spinner = "⭐"; # [hopefully this isn't too boring for you, tripflag](https://github.com/9001/copyparty/tree/hovudstraum/docs/rice#boring-loader-spinner) + + xm = "aw,f,j,t3600,${project.inputs.copyparty.src}/bin/hooks/wget.py"; # download URLs that are pasted into the message box + + xff-src = "127.0.0.1"; + rproxy = 1; + + exp = true; + }; + + volumes = { + "/" = { + path = "/var/lib/copyparty/data"; + + access = { + r = "*"; + A = admins; + }; + }; + "/private" = { + path = "/var/lib/copyparty/private"; + + access = { + A = [ + "minion" + ]; + }; + }; + }; + }; + + systemd.services.copyparty = { + path = [ pkgs.wget ]; # Needed for downloading files by URL + serviceConfig = { + BindReadOnlyPaths = [ + "/etc/ssl" + "/etc/static/ssl" + ]; # Required for wget to validate SSL for downloads + StateDirectory = + "copyparty " + + (lib.pipe config.services.copyparty.volumes [ + builtins.attrValues + (map (mount: mount.path)) + (map (lib.removePrefix "/var/lib/")) + (lib.concatStringsSep " ") + ]); + }; + }; + + services.nginx.enable = true; + + services.nginx.virtualHosts."copyparty.starrysky.fyi" = { + serverName = "copyparty.starrysky.fyi"; + + addSSL = true; + enableACME = true; + acmeRoot = null; + + locations."/" = { + proxyPass = "http://127.0.0.1:1030"; + recommendedProxySettings = true; + proxyWebsockets = true; + }; + + extraConfig = '' + client_max_body_size 1024M; + ''; + }; + services.nginx.tailscaleAuth = { + enable = true; + virtualHosts = [ "copyparty.starrysky.fyi" ]; + }; + + clicks.storage.impermanence.persist.directories = [ "/var/lib/copyparty" ]; + }; +} -- 2.43.0 From 05c58242af0c7836d605f57a4c5142578d4a1c32 Mon Sep 17 00:00:00 2001 From: Skyler Grey Date: Sat, 3 Jan 2026 22:35:18 +0000 Subject: [PATCH] feat(pm/umber): enable RAID Change-Id: pzsplyyumvuwxntknxklmuyoyynoryvt We have some drives in umber that should be set up as a software RAID. To do that, we need to enable this in the hardware config --- packetmix/systems/umber/hardware-configuration.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packetmix/systems/umber/hardware-configuration.nix b/packetmix/systems/umber/hardware-configuration.nix index 04e10654..2c9d0af9 100644 --- a/packetmix/systems/umber/hardware-configuration.nix +++ b/packetmix/systems/umber/hardware-configuration.nix @@ -29,6 +29,11 @@ ]; }; + boot.swraid.enable = true; + boot.swraid.mdadmConf = '' + PROGRAM=true + ''; # Disable reporting for this system + clicks.storage.impermanence = { enable = true; devices = { -- 2.43.0