Reorganize services/ into category subfolders

Group service modules by category (media, network, vpn, identity,
dev, desktop) to make the growing services/ dir easier to navigate.
containers.nix stays at the top level since it's a shared backend,
not a single-category service.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 06:08:43 +02:00
co-authored by Claude Sonnet 5
parent 4679afa505
commit d7a66f3e3b
27 changed files with 41 additions and 38 deletions
+8 -5
View File
@@ -11,7 +11,10 @@ Pi 3B+ DNS/DHCP, aarch64). See `README.md` for the full install/deploy walkthrou
``` ```
flake.nix # nixosConfigurations: real hosts + test/util targets flake.nix # nixosConfigurations: real hosts + test/util targets
common.nix # shared base: user darman (key-only ssh), nix settings, firewall :22, tz common.nix # shared base: user darman (key-only ssh), nix settings, firewall :22, tz
services/*.nix # one reusable NixOS module per service; each opens ITS OWN firewall ports services/<cat>/*.nix # one reusable NixOS module per service, grouped by category
# (media, network, vpn, identity, dev, desktop); each opens
# ITS OWN firewall ports. services/containers.nix (podman
# backend) stays at the top level, shared across categories.
hosts/<h>/ # configuration.nix + disk-config.nix (disko) + hardware-configuration.nix + secrets.nix hosts/<h>/ # configuration.nix + disk-config.nix (disko) + hardware-configuration.nix + secrets.nix
secrets/<h>.yaml # sops-nix, age-encrypted per host secrets/<h>.yaml # sops-nix, age-encrypted per host
scripts/deploy # config-agnostic deploy wrapper (all args mandatory) scripts/deploy # config-agnostic deploy wrapper (all args mandatory)
@@ -19,9 +22,9 @@ scripts/edit_secrets
.sops.yaml # per-host encryption rules (admin key + each host's key) .sops.yaml # per-host encryption rules (admin key + each host's key)
``` ```
A host = `common.nix` + the `services/*` modules it imports + its `hosts/<h>/configuration.nix`. A host = `common.nix` + the `services/**` modules it imports + its `hosts/<h>/configuration.nix`.
`services/` modules are engine-agnostic and shared across hosts (e.g. `tailscale.nix`, `services/` modules are engine-agnostic and shared across hosts (e.g. `services/vpn/tailscale.nix`,
`caddy.nix` used by jupiter and neptun). `services/network/caddy.nix` used by jupiter and neptun).
## Commands ## Commands
@@ -73,7 +76,7 @@ nix build .#nixosConfigurations.jupiter-vbox.config.system.build.virtualBoxOVA
`/etc/nix/nix.custom.conf` (NOT `/etc/nix/nix.conf` — Determinate Nix regenerates that) `/etc/nix/nix.custom.conf` (NOT `/etc/nix/nix.conf` — Determinate Nix regenerates that)
+ `qemu-user-static-binfmt`, else emulated builds fail with "platform mismatch". Or + `qemu-user-static-binfmt`, else emulated builds fail with "platform mismatch". Or
build on the Pi with `--build-host darman@<ip>`. build on the Pi with `--build-host darman@<ip>`.
- **pihole on mercury is a CONTAINER** (`services/pihole.nix`, official image, host - **pihole on mercury is a CONTAINER** (`services/network/pihole.nix`, official image, host
networking, caps NET_ADMIN/NET_RAW/SYS_NICE/CHOWN, `FTLCONF_*` env config). The native networking, caps NET_ADMIN/NET_RAW/SYS_NICE/CHOWN, `FTLCONF_*` env config). The native
`services.pihole-ftl` module **segfaults on the Pi 3B+ aarch64** — do not switch back. `services.pihole-ftl` module **segfaults on the Pi 3B+ aarch64** — do not switch back.
- **`services.unbound.resolveLocalQueries = false`** is required: unbound listens on - **`services.unbound.resolveLocalQueries = false`** is required: unbound listens on
+2 -2
View File
@@ -73,8 +73,8 @@
modules = [ modules = [
(nixpkgs + "/nixos/modules/virtualisation/qemu-vm.nix") (nixpkgs + "/nixos/modules/virtualisation/qemu-vm.nix")
./common.nix ./common.nix
./services/unbound.nix ./services/network/unbound.nix
./services/pihole.nix ./services/network/pihole.nix
({ lib, ... }: { ({ lib, ... }: {
networking.hostName = "mercury-vm"; networking.hostName = "mercury-vm";
networking.nameservers = [ "1.1.1.1" "9.9.9.9" ]; # host resolver (not pihole) networking.nameservers = [ "1.1.1.1" "9.9.9.9" ]; # host resolver (not pihole)
+13 -13
View File
@@ -7,20 +7,20 @@
./disk-config.nix # disko: OS-disk partitions + filesystems ./disk-config.nix # disko: OS-disk partitions + filesystems
./secrets.nix # sops-nix: samba password, tailscale key, ... ./secrets.nix # sops-nix: samba password, tailscale key, ...
../../common.nix # shared base: user / ssh / nix / firewall ../../common.nix # shared base: user / ssh / nix / firewall
../../services/samba.nix ../../services/network/samba.nix
../../services/avahi.nix ../../services/network/avahi.nix
../../services/audiobookshelf.nix ../../services/media/audiobookshelf.nix
../../services/containers.nix ../../services/containers.nix
../../services/caddy.nix ../../services/network/caddy.nix
../../services/tailscale.nix ../../services/vpn/tailscale.nix
../../services/jellyfin.nix ../../services/media/jellyfin.nix
../../services/sabnzbd.nix ../../services/media/sabnzbd.nix
../../services/prowlarr.nix ../../services/media/prowlarr.nix
../../services/sonarr.nix ../../services/media/sonarr.nix
../../services/radarr.nix ../../services/media/radarr.nix
../../services/clonarr.nix ../../services/media/clonarr.nix
../../services/seerr.nix ../../services/media/seerr.nix
../../services/gitea.nix ../../services/dev/gitea.nix
]; ];
# sabnzbd's unrar dependency is unfree; scope the allowance to just that # sabnzbd's unrar dependency is unfree; scope the allowance to just that
+4 -4
View File
@@ -7,11 +7,11 @@
imports = [ imports = [
(modulesPath + "/virtualisation/virtualbox-image.nix") (modulesPath + "/virtualisation/virtualbox-image.nix")
../../common.nix # shared base: user / ssh / nix / firewall ../../common.nix # shared base: user / ssh / nix / firewall
../../services/samba.nix ../../services/network/samba.nix
../../services/avahi.nix ../../services/network/avahi.nix
../../services/audiobookshelf.nix ../../services/media/audiobookshelf.nix
../../services/containers.nix ../../services/containers.nix
../../services/caddy.nix ../../services/network/caddy.nix
]; ];
networking.hostName = "jupiter"; networking.hostName = "jupiter";
+2 -2
View File
@@ -7,8 +7,8 @@
imports = [ imports = [
../../common.nix # shared base: user / ssh / nix / firewall ../../common.nix # shared base: user / ssh / nix / firewall
./secrets.nix # sops-nix: darman password (age key on boot part.) ./secrets.nix # sops-nix: darman password (age key on boot part.)
../../services/unbound.nix # local recursive resolver (127.0.0.1:5335) ../../services/network/unbound.nix # local recursive resolver (127.0.0.1:5335)
../../services/pihole.nix # DNS adblock + DHCP (declarative static leases) ../../services/network/pihole.nix # DNS adblock + DHCP (declarative static leases)
]; ];
networking.hostName = "mercury"; networking.hostName = "mercury";
+7 -7
View File
@@ -7,11 +7,11 @@
./disk-config.nix # disko: vda partitions + filesystems ./disk-config.nix # disko: vda partitions + filesystems
./secrets.nix # sops-nix: tailscale authkey ./secrets.nix # sops-nix: tailscale authkey
../../common.nix # shared base: user / ssh / nix / firewall ../../common.nix # shared base: user / ssh / nix / firewall
../../services/caddy.nix ../../services/network/caddy.nix
../../services/tailscale.nix ../../services/vpn/tailscale.nix
../../services/zitadel.nix ../../services/identity/zitadel.nix
../../services/headscale.nix ../../services/vpn/headscale.nix
../../services/headplane.nix ../../services/vpn/headplane.nix
]; ];
# ---- Boot (UEFI) ---- # ---- Boot (UEFI) ----
@@ -52,7 +52,7 @@
# TODO: port your other VPS services' vhosts here before deploying. # TODO: port your other VPS services' vhosts here before deploying.
# ---- Zitadel (identity/OIDC provider) ---- # ---- Zitadel (identity/OIDC provider) ----
# Runs locally on neptun (see services/zitadel.nix); Caddy just terminates # Runs locally on neptun (see services/identity/zitadel.nix); Caddy just terminates
# TLS and proxies to it. # TLS and proxies to it.
services.zitadel.settings.ExternalDomain = "auth.mgaction.town"; services.zitadel.settings.ExternalDomain = "auth.mgaction.town";
services.caddy.virtualHosts."auth.mgaction.town".extraConfig = '' services.caddy.virtualHosts."auth.mgaction.town".extraConfig = ''
@@ -78,7 +78,7 @@
# ---- Gitea SSH forward ---- # ---- Gitea SSH forward ----
# Caddy only proxies HTTP; forward :2222 over the tailnet to gitea's own # Caddy only proxies HTTP; forward :2222 over the tailnet to gitea's own
# SSH server on jupiter (services/gitea.nix), so # SSH server on jupiter (services/dev/gitea.nix), so
# `ssh://git@git.mgaction.town:2222/...` works. Also needs a matching # `ssh://git@git.mgaction.town:2222/...` works. Also needs a matching
# inbound-2222 rule in netcup's edge firewall panel (not managed by Nix). # inbound-2222 rule in netcup's edge firewall panel (not managed by Nix).
systemd.services.gitea-ssh-forward = { systemd.services.gitea-ssh-forward = {
+2 -2
View File
@@ -18,7 +18,7 @@
# bootstrap password is different — services.zitadel.steps would render it # bootstrap password is different — services.zitadel.steps would render it
# into a world-readable store path, so render a FirstInstance steps file # into a world-readable store path, so render a FirstInstance steps file
# from the secret instead and point extraStepsPaths at it (see # from the secret instead and point extraStepsPaths at it (see
# services/zitadel.nix and the pihole.env template on mercury for the same # services/identity/zitadel.nix and the pihole.env template on mercury for the same
# pattern). # pattern).
sops.secrets.zitadel_master_key = { }; sops.secrets.zitadel_master_key = { };
sops.secrets.zitadel_admin_password = { }; sops.secrets.zitadel_admin_password = { };
@@ -39,7 +39,7 @@
# Headplane: cookie_secret_path takes a path natively (no store leak). # Headplane: cookie_secret_path takes a path natively (no store leak).
# oidc.client_secret + the headscale API key are still REPLACE_ME # oidc.client_secret + the headscale API key are still REPLACE_ME
# placeholders (see services/headplane.nix) until Zitadel/headscale are # placeholders (see services/vpn/headplane.nix) until Zitadel/headscale are
# actually deployed and those get created for real. # actually deployed and those get created for real.
sops.secrets.headplane_cookie_secret = { }; sops.secrets.headplane_cookie_secret = { };
sops.secrets.headplane_oidc_client_secret = { }; sops.secrets.headplane_oidc_client_secret = { };
@@ -1,6 +1,6 @@
{ config, ... }: { config, ... }:
# Headplane — web UI for headscale (services/headscale.nix; must be enabled # Headplane — web UI for headscale (services/vpn/headscale.nix; must be enabled
# first). Runs as headscale's own OS user so it can restart headscale when # first). Runs as headscale's own OS user so it can restart headscale when
# settings change from the UI. # settings change from the UI.
# #
@@ -9,7 +9,7 @@
# /admin prefix — Headplane appends that itself, including for the OIDC # /admin prefix — Headplane appends that itself, including for the OIDC
# callback. # callback.
# #
# Auth is Zitadel (services/zitadel.nix) via OIDC. client_id, client_secret, # Auth is Zitadel (services/identity/zitadel.nix) via OIDC. client_id, client_secret,
# and the headscale API key can't be known until Zitadel/headscale are # and the headscale API key can't be known until Zitadel/headscale are
# actually deployed, so they're placeholders below; direct API-key login # actually deployed, so they're placeholders below; direct API-key login
# still works as a fallback until then. Once live: # still works as a fallback until then. Once live:
@@ -1,7 +1,7 @@
{ ... }: { ... }:
# Headscale — self-hosted control server for the tailnet. Every host's # Headscale — self-hosted control server for the tailnet. Every host's
# services/tailscale.nix points --login-server at https://vpn.mgaction.town # services/vpn/tailscale.nix points --login-server at https://vpn.mgaction.town
# (this host). MagicDNS base_domain "hosts.mgaction.town" matches the # (this host). MagicDNS base_domain "hosts.mgaction.town" matches the
# "jupiter.hosts.mgaction.town" names used in this repo's Caddy vhosts # "jupiter.hosts.mgaction.town" names used in this repo's Caddy vhosts
# (e.g. hosts/neptun/configuration.nix) — don't change one without the other. # (e.g. hosts/neptun/configuration.nix) — don't change one without the other.