Compare commits
1 Commits
docs
..
17c1a00dee
| Author | SHA1 | Date | |
|---|---|---|---|
| 17c1a00dee |
@@ -7,10 +7,10 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
name: Check, build and cache nixfiles
|
name: Check, build and cache nixfiles
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v4
|
||||||
- uses: cachix/install-nix-action@v31
|
- uses: cachix/install-nix-action@v27
|
||||||
with:
|
with:
|
||||||
# Gitea will supply a token in GITHUB_TOKEN, which this action will
|
# Gitea will supply a token in GITHUB_TOKEN, which this action will
|
||||||
# try to pass to Nix when downloading from GitHub
|
# try to pass to Nix when downloading from GitHub
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
# AGENTS.md
|
|
||||||
|
|
||||||
This file provides guidance to coding agents when working with code in this repository.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Personal Nix flake managing NixOS systems and home-manager configurations for a set of
|
|
||||||
machines ("boxes": servers, home machines, routers). It is built around a **custom module system** layered
|
|
||||||
on top of NixOS/home-manager, not the stock flake `nixosConfigurations` pattern.
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
This repo provides a `numtide/devshell` (entered via `direnv` / `use flake`). The shell defines
|
|
||||||
named commands — prefer them over raw `nix` invocations. Run a bare command name with no args to
|
|
||||||
see its help, or browse `devshell/commands.nix` / `devshell/install.nix` / `devshell/vm-tasks.nix`.
|
|
||||||
|
|
||||||
Common ones:
|
|
||||||
- `fmt` — format Nix with `nixpkgs-fmt` (the canonical formatter here).
|
|
||||||
- `build-system <host> [nix args]` — build a NixOS system's `toplevel`.
|
|
||||||
- `build-n-switch <args>` — wraps `doas nixos-rebuild --flake .`.
|
|
||||||
- `build-home <name>` / `home-switch` — build / switch a home-manager config.
|
|
||||||
- `run-vm <host>` — build & boot a system as a dev VM (installs `.keys/dev.key` into the VM).
|
|
||||||
- `build-iso` / `build-kexec` / `build-netboot <host>` — alternate build outputs via `config.my.buildAs.*`.
|
|
||||||
- `check-system <host> [nix args]` — evaluate a system (catches eval errors without a full build).
|
|
||||||
**Prefer this over `build-system` to validate a config change** — evaluation surfaces module/option
|
|
||||||
errors quickly and cheaply; only do a full build when you specifically need the built artifact.
|
|
||||||
- `deploy <host>` and `deploy-multi <hosts...>` — deploy-rs deployment (uses `.keys/deploy.key`, `--skip-checks`).
|
|
||||||
Pass the flake-qualified node, e.g. `deploy .#git`. The deploy node name is **always** the system
|
|
||||||
name (`deploy-rs.nix` keys nodes directly off `nixos.systems` / `home-manager.homes`); a system is
|
|
||||||
only a deploy target when `config.my.deploy.enable` is true (defaults true; auto-disabled for dev
|
|
||||||
VMs and containers).
|
|
||||||
- `ssh-machine <name> [cmd]` — SSH to a NixOS system or home-manager config by name. Resolves the
|
|
||||||
target and ssh options (identity, port) from its deploy-rs node, so it needs `my.deploy.enable`
|
|
||||||
(same gate as `deploy`).
|
|
||||||
- `ragenix` — edit age secrets using `.keys/dev.key` as identity (see Secrets).
|
|
||||||
- `repl` — `nix repl .#`.
|
|
||||||
- `update-nixpkgs` / `update-home-manager` — bump pinned inputs.
|
|
||||||
|
|
||||||
Check everything (what CI runs): `nix flake check --no-build`.
|
|
||||||
CI builds each attr of `.#ci.x86_64-linux` (systems, homes, packages, shell) and pushes to the
|
|
||||||
Harmonia binary cache; see `.gitea/workflows/ci.yaml` and `ci/push-to-cache.sh`.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### The custom module system
|
|
||||||
`flake.nix` does **not** call `nixosSystem` per host directly. Instead it `evalModules` over
|
|
||||||
`./nixos`, `./home-manager`, `./deploy-rs.nix`, and the per-host files listed in the `configs`
|
|
||||||
list in `flake.nix`. That evaluation produces a top-level config (`self.nixfiles`) from which the
|
|
||||||
real flake outputs are derived:
|
|
||||||
- `nixos.systems.<name>` → `nixosConfigurations.<name>`
|
|
||||||
- `home-manager.homes.<name>` → `homeConfigurations.<name>`
|
|
||||||
- `nixos.modules` / `home-manager.modules` → `nixosModules` / `homeModules`
|
|
||||||
- `deploy-rs.rendered` → `deploy`
|
|
||||||
|
|
||||||
`nixos/default.nix` and `home-manager/default.nix` define the `systemOpts` / `homeOpts` submodules
|
|
||||||
and the `mkSystem` / `mkHome` functions that actually invoke `eval-config.nix` /
|
|
||||||
`homeManagerConfiguration`. **To add a new host:** create a box file that sets
|
|
||||||
`nixos.systems.<name> = { ... }`, then add its path to the `configs` list in `flake.nix`.
|
|
||||||
|
|
||||||
### Multiple nixpkgs channels
|
|
||||||
Four pkgs sets are threaded everywhere as `pkgsFlakes` / `pkgs'` (and `hmFlakes` for home-manager):
|
|
||||||
`unstable`, `stable`, `mine` (a personal nixpkgs fork), `mine-stable`. Each system/home picks its
|
|
||||||
channel via `nixpkgs` / `home-manager` / `hmNixpkgs` options (e.g. `nixpkgs = "mine-stable"`).
|
|
||||||
Modules receive `pkgs'` = an attrset of all channels for the current system.
|
|
||||||
|
|
||||||
### `lib.my` and the `my` option namespace
|
|
||||||
`lib/default.nix` extends `lib` with a `my` attrset (helpers like `mkOpt'`, `mkBoolOpt'`,
|
|
||||||
`mkDefault'`, `inlineModule'`, `mkDefaultSystemsPkgs`, `homeStateVersion`). It also pulls in:
|
|
||||||
- `lib.my.net` — network/CIDR helpers from the `libnetRepo` input. Used heavily for IP math.
|
|
||||||
- `lib.my.c` — shared constants from `lib/constants.nix` (UIDs/GIDs, kernel package selection,
|
|
||||||
nginx snippets, per-network domains/prefixes, etc.). Reuse these rather than hardcoding.
|
|
||||||
- `lib.my.dns` — DNS helpers (`lib/dns.nix`).
|
|
||||||
|
|
||||||
Custom modules add options under the `my.*` namespace (e.g. `my.secrets`, `my.build`,
|
|
||||||
`my.tmproot`, `my.server`). Use `mkOpt'`/`mkBoolOpt'` for option declarations to match style.
|
|
||||||
|
|
||||||
### Modules and module lists
|
|
||||||
Module sets are registered in `nixos/modules/_list.nix` and `home-manager/modules/_list.nix`
|
|
||||||
(name → path), which become `nixos.modules` / `home-manager.modules` and are applied to every
|
|
||||||
system/home. To add a shared module, drop the file in `nixos/modules/` (or `home-manager/modules/`)
|
|
||||||
and add an entry to the relevant `_list.nix`.
|
|
||||||
|
|
||||||
### Network assignments
|
|
||||||
Each system declares `assignments.<name>` (in its `nixos.systems.<host>` block) with IPv4/IPv6
|
|
||||||
addresses, gateways, domains, MTU, etc. These are aggregated into `allAssignments` (passed to every
|
|
||||||
module) and there is an assertion that fails on duplicate IPs. Host networking
|
|
||||||
(`networking.hostName`, `domain`) defaults from the `internal` assignment.
|
|
||||||
|
|
||||||
### Hosts / "boxes"
|
|
||||||
Per-host configs live under `nixos/boxes/<host>` (some are single `.nix` files, some directories
|
|
||||||
with nested VMs/containers under e.g. `colony/vms`). Many "systems" are VMs or containers managed
|
|
||||||
via the `vms` / `containers` modules and the `l2mesh` VXLAN module.
|
|
||||||
|
|
||||||
For a human-readable map of what is actually deployed (per-machine roles, services and networking),
|
|
||||||
see `README.md` and the per-machine docs under `docs/boxes/` (grouped `docs/boxes/colony/`,
|
|
||||||
`docs/boxes/home/`, `docs/boxes/misc/`). Keep these in sync when adding, removing or repurposing
|
|
||||||
a machine or service.
|
|
||||||
|
|
||||||
## Secrets
|
|
||||||
|
|
||||||
age-encrypted secrets in `secrets/`, managed with **ragenix**. Each module declares
|
|
||||||
`my.secrets.files.<name>` and `my.secrets.key` (the host pubkey to encrypt for). `secrets.nix`
|
|
||||||
(the ragenix rules file) is generated by reading every system's declared secrets and computing the
|
|
||||||
recipient key list (always including `.keys/dev.pub`). Edit secrets with the `ragenix` devshell
|
|
||||||
command, which supplies `.keys/dev.key` as the identity. The `.keys/` directory (dev + deploy
|
|
||||||
private keys) is required for editing secrets, deploying, and running dev VMs.
|
|
||||||
|
|
||||||
## Conventions
|
|
||||||
|
|
||||||
- Format with `nixpkgs-fmt` (`fmt`). 2-space indent, `inherit (...)` blocks at the top of `let`.
|
|
||||||
- Prefer `lib.my` helpers (`mkOpt'`, `mkBoolOpt'`, `mkDefault'`) and `lib.my.c` constants over
|
|
||||||
reimplementing.
|
|
||||||
- New shared functionality → a module in `*/modules/` + entry in `_list.nix`, options under `my.*`.
|
|
||||||
- New host → box file under `nixos/boxes/` + entry in the `configs` list in `flake.nix`.
|
|
||||||
- Custom packages live in `pkgs/` and are registered in `pkgs/default.nix`; the overlay is exposed
|
|
||||||
as `overlays.default`.
|
|
||||||
- In prose and commit messages, quote code-like identifiers (commands, options, paths, package and
|
|
||||||
attribute names) in backticks.
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
# nixfiles
|
|
||||||
|
|
||||||
Personal Nix flake managing every machine I run: hosted servers, home
|
|
||||||
infrastructure, routers, a remote site, VPSes and personal workstations. It is
|
|
||||||
built around a **custom module system** layered on top of NixOS and
|
|
||||||
home-manager rather than the stock per-host `nixosConfigurations` pattern.
|
|
||||||
|
|
||||||
For day-to-day commands and a deeper explanation of the module system,
|
|
||||||
conventions and secrets, see [`AGENTS.md`](AGENTS.md). This README is the map of
|
|
||||||
**what is actually deployed**; the per-machine details live under [`docs/boxes/`](docs/boxes).
|
|
||||||
|
|
||||||
> **Note:** This documentation (the README and everything under `docs/`) is a
|
|
||||||
> work in progress and was **agent-generated** from the repository. It may be
|
|
||||||
> incomplete or out of date — treat the Nix configuration as the source of truth.
|
|
||||||
|
|
||||||
## The boxes at a glance
|
|
||||||
|
|
||||||
Machines are grouped by deployment/location. Each group has its own directory
|
|
||||||
under `docs/boxes/` with a `README.md` overview and one file per machine.
|
|
||||||
|
|
||||||
| Group | What it is | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| **colony** | Hosted dedicated server in Amsterdam (`ams1`). A VM host running the public-facing infrastructure: routing, web, git, media, object storage, chat, game servers. | [`docs/boxes/colony/`](docs/boxes/colony) |
|
|
||||||
| **home** | Home network: a VM host (`palace`), the home routers, storage, Home Assistant, and personal desktops. | [`docs/boxes/home/`](docs/boxes/home) |
|
|
||||||
| **misc** | Everything else: edge VPSes (`britway`, `britnet`), the remote `kelder` site, the `tower` workstation, and the installer image. | [`docs/boxes/misc/`](docs/boxes/misc) |
|
|
||||||
|
|
||||||
## The "big machine" pattern
|
|
||||||
|
|
||||||
The larger sites (`colony`, `home`) all follow the same shape:
|
|
||||||
|
|
||||||
```
|
|
||||||
physical host (VM host)
|
|
||||||
├── VM ── thing impractical to containerise (router, storage, podman host, …)
|
|
||||||
├── VM ── container host ──┬── NixOS container ── application
|
|
||||||
│ ├── NixOS container ──┬── application
|
|
||||||
│ │ ├── application
|
|
||||||
│ │ └── application
|
|
||||||
│ └── …
|
|
||||||
└── VM ── …
|
|
||||||
```
|
|
||||||
|
|
||||||
- A **physical host** (`colony`, `palace`) does little itself beyond running
|
|
||||||
**VMs** via the custom `my.vms` module (QEMU + systemd units, LVM-backed
|
|
||||||
disks).
|
|
||||||
- **VMs** exist for things that are impractical to put in a container — kernel
|
|
||||||
features, separate networking, podman/OCI workloads, foreign OSes.
|
|
||||||
- One VM is usually a **container host** (`shill` on colony, `sfh` on home; and
|
|
||||||
`kelder` directly). It runs **NixOS containers** via the custom `my.containers`
|
|
||||||
module (systemd-nspawn based, each with its own address on a bridge).
|
|
||||||
- **Most applications live in those NixOS containers.** A container isn't limited
|
|
||||||
to a single application — it commonly hosts a **group of related applications**
|
|
||||||
that belong together (e.g. `jackflix` runs Jellyfin, the *arr stack,
|
|
||||||
Transmission, PhotoPrism and copyparty; `object` runs MinIO, Harmonia, HedgeDoc
|
|
||||||
and wastebin). Each container is a first-class entry in `docs/boxes/`.
|
|
||||||
|
|
||||||
Networking between everything is largely defined by per-system `assignments`
|
|
||||||
(IPs/prefixes) plus an L2 VXLAN mesh (`my.vpns.l2`, AS211024) that ties the edge
|
|
||||||
routers together. See [`AGENTS.md`](AGENTS.md) for the mechanics.
|
|
||||||
|
|
||||||
## Repo layout
|
|
||||||
|
|
||||||
```
|
|
||||||
README.md <- you are here
|
|
||||||
nixos/
|
|
||||||
boxes/ per-machine configuration ("boxes")
|
|
||||||
colony/ colony host + its VMs (vms/) + shill's containers
|
|
||||||
home/ palace host + its VMs, plus stream, castle
|
|
||||||
britway/ britnet.nix, kelder/, tower/, installer.nix …
|
|
||||||
modules/ shared NixOS modules (my.* options); registered in _list.nix
|
|
||||||
home-manager/ home-manager modules + configs
|
|
||||||
lib/ lib.my helpers, constants (lib.my.c), net/dns helpers
|
|
||||||
pkgs/ custom packages (overlays.default)
|
|
||||||
secrets/ age-encrypted secrets (ragenix)
|
|
||||||
devshell/ devshell commands (build/deploy/check/ssh helpers)
|
|
||||||
docs/boxes/ per-machine documentation (colony/, home/, misc/)
|
|
||||||
```
|
|
||||||
|
|
||||||
A machine is wired into the flake by adding its box file to the `configs` list
|
|
||||||
in `flake.nix`. See [`AGENTS.md`](AGENTS.md#architecture) for how `evalModules`
|
|
||||||
turns these into `nixosConfigurations`, `homeConfigurations` and `deploy` nodes.
|
|
||||||
+1
-30
@@ -48,30 +48,11 @@ in
|
|||||||
help = "Print the ed25519 pubkey for a host";
|
help = "Print the ed25519 pubkey for a host";
|
||||||
command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'";
|
command = "${pkgs.openssh}/bin/ssh-keyscan -t ed25519 \"$1\" 2> /dev/null | awk '{ print $2 \" \" $3 }'";
|
||||||
}
|
}
|
||||||
{
|
|
||||||
name = "ssh-machine";
|
|
||||||
category = "utilities";
|
|
||||||
help = "SSH to a machine by NixOS system or home-manager config name";
|
|
||||||
command = ''
|
|
||||||
name="$1"
|
|
||||||
shift
|
|
||||||
# Run from the project root so deploy's relative identity path (.keys/deploy.key) resolves
|
|
||||||
cd "$PRJ_ROOT"
|
|
||||||
# deploy-rs node names are the system/home name, with `@` mangled to `-at-`
|
|
||||||
node="''${name//@/-at-}"
|
|
||||||
# Single eval: resolve `user@host` plus merged (global + node) deploy-rs ssh options
|
|
||||||
info="$(nix eval --raw .#deploy --apply 'd: let n = d.nodes."'"$node"'"; in "''${n.sshUser}@''${n.hostname} ''${builtins.concatStringsSep " " (d.sshOpts ++ n.sshOpts)}"')"
|
|
||||||
target="''${info%% *}"
|
|
||||||
opts="''${info#* }"
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
exec ${pkgs.openssh}/bin/ssh $opts "$target" "$@"
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
name = "json2nix";
|
name = "json2nix";
|
||||||
category = "utilities";
|
category = "utilities";
|
||||||
help = "Convert JSON to formatted Nix";
|
help = "Convert JSON to formatted Nix";
|
||||||
command = "nix eval --impure --expr 'builtins.fromJSON (builtins.readFile /dev/stdin)' | ${pkgs.nixfmt}/bin/nixfmt -";
|
command = "nix eval --impure --expr 'builtins.fromJSON (builtins.readFile /dev/stdin)' | ${pkgs.nixfmt-rfc-style}/bin/nixfmt";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -92,12 +73,6 @@ in
|
|||||||
help = "Build NixOS configuration";
|
help = "Build NixOS configuration";
|
||||||
command = ''nix build "''${@:2}" ".#nixosConfigurations.\"$1\".config.system.build.toplevel"'';
|
command = ''nix build "''${@:2}" ".#nixosConfigurations.\"$1\".config.system.build.toplevel"'';
|
||||||
}
|
}
|
||||||
{
|
|
||||||
name = "check-system";
|
|
||||||
category = "utilities";
|
|
||||||
help = "Evaluate NixOS configuration (check validity without building)";
|
|
||||||
command = ''nix eval "''${@:2}" ".#nixosConfigurations.\"$1\".config.system.build.toplevel.drvPath"'';
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
name = "build-n-switch";
|
name = "build-n-switch";
|
||||||
category = "tasks";
|
category = "tasks";
|
||||||
@@ -169,11 +144,7 @@ in
|
|||||||
help = "Deploy multiple flakes at once";
|
help = "Deploy multiple flakes at once";
|
||||||
command = ''
|
command = ''
|
||||||
for f in $@; do
|
for f in $@; do
|
||||||
if [ -n "''${O:-}" ]; then
|
|
||||||
deploy "$O" $f
|
deploy "$O" $f
|
||||||
else
|
|
||||||
deploy $f
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
# colony
|
|
||||||
|
|
||||||
The hosted dedicated server in Amsterdam (`ams1`). This is the public-facing
|
|
||||||
half of the boxes: almost everything reachable from the internet lives here.
|
|
||||||
|
|
||||||
- **Internal domain:** `ams1.int.nul.ie`
|
|
||||||
- **Public domain:** `nul.ie` (public services are published as `*.nul.ie`)
|
|
||||||
- **Source:** [`nixos/boxes/colony/`](../../../nixos/boxes/colony)
|
|
||||||
|
|
||||||
## Shape
|
|
||||||
|
|
||||||
`colony` is the physical VM host. It runs the VMs below; one of them (`shill`)
|
|
||||||
is itself a NixOS container host where most applications run.
|
|
||||||
|
|
||||||
```
|
|
||||||
colony (physical VM host)
|
|
||||||
├── estuary ── edge router / firewall / DNS / BGP
|
|
||||||
├── shill ──── NixOS container host ──┬── middleman (reverse proxy, ACME, SSO)
|
|
||||||
│ ├── colony-psql (shared PostgreSQL)
|
|
||||||
│ ├── vaultwarden (password manager)
|
|
||||||
│ ├── chatterbox (Matrix + bridges)
|
|
||||||
│ ├── toot (Mastodon)
|
|
||||||
│ ├── jackflix (media stack)
|
|
||||||
│ ├── object (MinIO, Nix cache, …)
|
|
||||||
│ ├── waffletail (Tailscale subnet router)
|
|
||||||
│ ├── qclk (clock service)
|
|
||||||
│ └── gam (game servers)
|
|
||||||
├── whale2 ─── podman/OCI host (game servers)
|
|
||||||
├── git ────── Gitea + Actions runner
|
|
||||||
├── mail ───── Debian VM running Mailcow (not NixOS — configured out of repo)
|
|
||||||
└── darts ──── third-party/customer VM (opaque to this repo)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Machines
|
|
||||||
|
|
||||||
| Machine | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `colony` | Physical VM host (AMD, LVM-thin, borgthin backups → rsync.net) | [colony.md](colony.md) |
|
|
||||||
| `estuary` | Edge router: WAN, firewall/NAT, DNS, BGP, IXP peering, WireGuard | [estuary.md](estuary.md) |
|
|
||||||
| `shill` | NixOS container host (see containers below) | [shill.md](shill.md) |
|
|
||||||
| `whale2` | podman/OCI host for game servers | [whale2.md](whale2.md) |
|
|
||||||
| `git` | Gitea + Gitea Actions runner | [git.md](git.md) |
|
|
||||||
|
|
||||||
### shill containers
|
|
||||||
|
|
||||||
| Container | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `middleman` | Front-end nginx reverse proxy, ACME certs, nginx-sso, librespeed | [middleman.md](middleman.md) |
|
|
||||||
| `colony-psql` | Shared PostgreSQL (14) for colony services | [colony-psql.md](colony-psql.md) |
|
|
||||||
| `vaultwarden` | Vaultwarden (Bitwarden-compatible password manager) | [vaultwarden.md](vaultwarden.md) |
|
|
||||||
| `chatterbox` | Matrix homeserver + bridges (heisenbridge, mautrix-*) | [chatterbox.md](chatterbox.md) |
|
|
||||||
| `toot` | Bluesky PDS (Mastodon disabled) | [toot.md](toot.md) |
|
|
||||||
| `jackflix` | Media: Jellyfin, *arr stack, Transmission, PhotoPrism, copyparty | [jackflix.md](jackflix.md) |
|
|
||||||
| `object` | MinIO (S3), Harmonia (Nix cache), HedgeDoc, wastebin | [object.md](object.md) |
|
|
||||||
| `waffletail` | Tailscale subnet router (advertises colony prefixes into the tailnet) | [waffletail.md](waffletail.md) |
|
|
||||||
| `qclk` | `qclk` clock service (reachable over WireGuard) | [qclk.md](qclk.md) |
|
|
||||||
| `gam` | Game servers (Terraria, …) | [gam.md](gam.md) |
|
|
||||||
|
|
||||||
## Non-NixOS VMs
|
|
||||||
|
|
||||||
These run on `colony` but are **not** managed by this repo (no NixOS config). The
|
|
||||||
QEMU instances are still declared in `colony`'s `my.vms.instances`, and colony's
|
|
||||||
networking routes/firewalls traffic to them:
|
|
||||||
|
|
||||||
- **`mail`** — a Debian VM running [Mailcow](https://mailcow.email/) (`mail.nul.ie`).
|
|
||||||
ACME certs are pushed to it from `middleman` (see [middleman.md](middleman.md)).
|
|
||||||
- **`darts`** — a third-party/customer VM; opaque to this repo, given a routed
|
|
||||||
prefix and otherwise left alone.
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# chatterbox
|
|
||||||
|
|
||||||
The Matrix homeserver (`nul.ie`) and its chat-network bridges.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/chatterbox.nix`](../../../nixos/boxes/colony/vms/shill/containers/chatterbox.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Matrix homeserver** for `server_name = "nul.ie"`.
|
|
||||||
- **Bridges** to other chat networks:
|
|
||||||
- `heisenbridge` (IRC),
|
|
||||||
- `mautrix-whatsapp` (WhatsApp),
|
|
||||||
- `mautrix-meta` / `mautrix-messenger` (Facebook Messenger / Instagram).
|
|
||||||
- Fronted by `middleman` (federation on `:8448`).
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `chatterbox-ctr`).
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# colony-psql
|
|
||||||
|
|
||||||
The shared PostgreSQL instance for colony. Several other containers
|
|
||||||
(`middleman`, `chatterbox`, `toot`, `git`, …) connect here rather than each
|
|
||||||
running their own database.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/colony-psql.nix`](../../../nixos/boxes/colony/vms/shill/containers/colony-psql.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **PostgreSQL 14** serving the other colony services over the `ctrs` network.
|
|
||||||
Consumers wait for it to be ready via the `systemdAwaitPostgres` helper.
|
|
||||||
- netdata for monitoring.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `colony-psql-ctr`).
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# colony (host)
|
|
||||||
|
|
||||||
The physical dedicated server in Amsterdam and the VM host for everything in
|
|
||||||
this group.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/colony/default.nix`](../../../nixos/boxes/colony/default.nix)
|
|
||||||
(VM instances in [`nixos/boxes/colony/vms/default.nix`](../../../nixos/boxes/colony/vms/default.nix))
|
|
||||||
- **nixpkgs:** `mine-stable`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
Bare-metal AMD host. It does little application work itself — its job is to run
|
|
||||||
the VMs and provide them with storage, networking and backups.
|
|
||||||
|
|
||||||
- **Virtualisation:** QEMU/KVM (`kvm-amd`, IOMMU on) via the `my.vms` module. VM
|
|
||||||
disks are LVM logical volumes (`vm-<name>-<disk>`) in the `main` volume group;
|
|
||||||
`estuary` additionally gets a WAN NIC by PCI passthrough.
|
|
||||||
- **Storage:** LVM-thin (`services.lvm.boot.thin`), `/persist` for state,
|
|
||||||
`/mnt/backup` for the local borg repo. `smartd` + `rasdaemon` for health.
|
|
||||||
- **Backups:** `my.borgthin` snapshots the persist/data LVs of the host and its
|
|
||||||
VMs into `/mnt/backup/main`, which is then `rsync`'d (along with LVM metadata)
|
|
||||||
to rsync.net (`zh2855.rsync.net`).
|
|
||||||
- **Monitoring:** netdata (with freeipmi), smartd.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- Two bridges: `base` (the colony "base" network, shared with `estuary`) and
|
|
||||||
`vms` (the VM network). Dummy interfaces keep the bridges up so dependent VMs
|
|
||||||
can start.
|
|
||||||
- Default gateway / edge is `estuary`; `colony` itself holds the `routing` and
|
|
||||||
`internal` (a.k.a. `vm`) assignments and routes container/OCI/Tailscale
|
|
||||||
prefixes to `shill` and `whale2`.
|
|
||||||
- `my.firewall` trusts the `vms` interface and forwards customer prefixes
|
|
||||||
(`vm-mail`, `vm-darts`) through.
|
|
||||||
|
|
||||||
## VMs hosted here
|
|
||||||
|
|
||||||
`estuary`, `shill`, `whale2`, `git` (all NixOS, documented in this directory),
|
|
||||||
plus the non-NixOS `mail` and `darts` (see [README](README.md#non-nixos-vms)).
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
# estuary
|
|
||||||
|
|
||||||
The colony edge router and firewall — the machine that holds colony's public
|
|
||||||
IPs and connects everything else to the internet.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/colony/vms/estuary/`](../../../nixos/boxes/colony/vms/estuary)
|
|
||||||
(`default.nix`, `bgp.nix`, `dns.nix`, `bandwidth.nix`)
|
|
||||||
- **nixpkgs:** `mine`
|
|
||||||
- **Host:** VM on `colony` (gets the WAN NIC by PCI passthrough)
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Edge routing / firewall / NAT:** owns the colony public IPv4/IPv6
|
|
||||||
(`94.142.241.x` / `2a02:898:0:20::`), does NAT and port-forwarding for the
|
|
||||||
internal services (`my.firewall.nat.forwardPorts` driven by
|
|
||||||
`firewallForwards`). Forwards HTTP/S to `middleman`, git to `git`, game ports
|
|
||||||
to the OCI game servers on `whale2`, etc.
|
|
||||||
- **BGP:** runs BIRD2 ([`bgp.nix`](../../../nixos/boxes/colony/vms/estuary/bgp.nix))
|
|
||||||
announcing AS211024, over VLANs on the WAN link:
|
|
||||||
- peers at the IXPs **Frys-IX**, **NL-ix** and **FogIXP**;
|
|
||||||
- plus **iFog transit** (`ifog-transit`) — an upstream transit provider from
|
|
||||||
iFog, **not** an IXP.
|
|
||||||
- **DNS:** authoritative/recursive DNS ([`dns.nix`](../../../nixos/boxes/colony/vms/estuary/dns.nix)),
|
|
||||||
redirected to port 5353 locally.
|
|
||||||
- **VPNs:**
|
|
||||||
- Part of the AS211024 **L2 VXLAN mesh** (`my.vpns.l2`) with `river`, `stream`
|
|
||||||
and `britway`.
|
|
||||||
- WireGuard endpoints for the remote `kelder` site, `hillcrest`, and
|
|
||||||
`john-valorant`.
|
|
||||||
- **Misc:** iperf3 server. (A bandwidth-accounting script,
|
|
||||||
[`bandwidth.py`](../../../nixos/boxes/colony/vms/estuary/bandwidth.py), exists but
|
|
||||||
is **legacy and not currently used**.)
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `wan` — the passed-through igb NIC (9000 MTU), carrying the upstream uplink and
|
|
||||||
tagged IXP VLANs (`ifog` 409 → `frys-ix`/`nl-ix`/`fogixp`/`ifog-transit`).
|
|
||||||
- `base` — colony base network; sends RAs and provides DNS to the base prefix,
|
|
||||||
routes the VM/container/OCI/Tailscale prefixes back to `colony`.
|
|
||||||
- `as211024` — the L2 mesh interface.
|
|
||||||
- Assignments: `internal` (public, alt name `fw`), `base`, `as211024`.
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# gam
|
|
||||||
|
|
||||||
A game-server container (the lightweight counterpart to the OCI game servers on
|
|
||||||
`whale2`).
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/gam.nix`](../../../nixos/boxes/colony/vms/shill/containers/gam.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Hosts game servers run directly as NixOS services — currently **Terraria**
|
|
||||||
(config/world from secrets). Exposed to the internet via `estuary`'s port
|
|
||||||
forwards (`:7777`).
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `gam-ctr`).
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# git
|
|
||||||
|
|
||||||
The Gitea VM — source hosting and CI for the boxes (`git.nul.ie`).
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/colony/vms/git/`](../../../nixos/boxes/colony/vms/git)
|
|
||||||
(`default.nix`, `gitea.nix`, `gitea-actions.nix`)
|
|
||||||
- **nixpkgs:** `mine`
|
|
||||||
- **Host:** VM on `colony`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Gitea** ([`gitea.nix`](../../../nixos/boxes/colony/vms/git/gitea.nix)) — the Git
|
|
||||||
forge (`git.nul.ie`). PostgreSQL-backed (the shared `colony-psql`), LFS
|
|
||||||
enabled, with object storage backed by MinIO on `object` (a MinIO secret is
|
|
||||||
spliced into `app.ini` at startup).
|
|
||||||
- **Gitea Actions runner**
|
|
||||||
([`gitea-actions.nix`](../../../nixos/boxes/colony/vms/git/gitea-actions.nix)) — a
|
|
||||||
Docker-mode runner (`main-docker`) using podman. Labels provide Debian/node-24
|
|
||||||
(Trixie) and Ubuntu 26.04 images; runner config comes from the upstream
|
|
||||||
module's `settings` option. The Actions cache lives on a dedicated disk
|
|
||||||
(`/var/cache/gitea-runner`). Runs as a fixed `gitea-runner` user (not
|
|
||||||
`DynamicUser`) so it can read its token.
|
|
||||||
- **nginx** — terminates TLS for `git.nul.ie` and proxies to Gitea on `:3000`.
|
|
||||||
ACME certs for `nul.ie` / `*.nul.ie` via the Cloudflare DNS challenge.
|
|
||||||
- **podman** — also hosts the OCI registry/build images; `/var/lib/containers`
|
|
||||||
is an XFS data disk.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `vms` interface with `routing` / `internal` assignments.
|
|
||||||
- HTTP/HTTPS forwarded in from `estuary`; podman default subnet `10.88.0.0/16` is
|
|
||||||
allowed to forward.
|
|
||||||
|
|
||||||
## CI
|
|
||||||
|
|
||||||
This runner is what executes the repo's own `.gitea/workflows/ci.yaml`, building
|
|
||||||
each `.#ci.x86_64-linux` attribute and pushing to the Harmonia binary cache. See
|
|
||||||
[`AGENTS.md`](../../../AGENTS.md#commands).
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# jackflix
|
|
||||||
|
|
||||||
The media stack — acquisition, library and streaming.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/jackflix/`](../../../nixos/boxes/colony/vms/shill/containers/jackflix)
|
|
||||||
(`default.nix`, `networking.nix`)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Streaming:** Jellyfin.
|
|
||||||
- **Acquisition (*arr stack):** Transmission, Jackett, FlareSolverr, Radarr,
|
|
||||||
Sonarr, and Jellyseerr (`seerr`) for requests.
|
|
||||||
- **Photos:** PhotoPrism (`photos.nul.ie`).
|
|
||||||
- **File sharing:** copyparty (`:3923`) serving public + private media volumes.
|
|
||||||
- Media lives on the shared `/mnt/media` volume (bind-mounted read-write from
|
|
||||||
`shill`). Downloaders bind to a VPN interface
|
|
||||||
([`networking.nix`](../../../nixos/boxes/colony/vms/shill/containers/jackflix/networking.nix)),
|
|
||||||
so torrent traffic only flows while `systemd-networkd-wait-online@vpn` is up.
|
|
||||||
- A shared `media` group (gid 2000) gives the apps coordinated access.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `jackflix-ctr`), plus its
|
|
||||||
own VPN interface for the download clients.
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
# middleman
|
|
||||||
|
|
||||||
The front-end reverse proxy for all public colony web services — the single
|
|
||||||
ingress that `estuary` forwards HTTP/HTTPS to.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/middleman/`](../../../nixos/boxes/colony/vms/shill/containers/middleman)
|
|
||||||
(`default.nix`, `vhosts.nix`)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **nginx** reverse proxy ([`vhosts.nix`](../../../nixos/boxes/colony/vms/shill/containers/middleman/vhosts.nix)
|
|
||||||
holds the per-service vhosts) with VTS stats, fancyindex, brotli, caching, and
|
|
||||||
a dynamic resolver pointed at `estuary` so upstreams can be re-resolved at
|
|
||||||
runtime. It is the single public ingress for almost every web service — colony,
|
|
||||||
home, and beyond.
|
|
||||||
- **ACME** — issues the wildcard certificates that **its own** vhosts are served
|
|
||||||
with (it is not a shared CA for the other boxes; `git`, `britway`, `kelder-spoder`, etc. each
|
|
||||||
run their own ACME):
|
|
||||||
- `nul.ie` / `*.nul.ie` (+ `*.s3.nul.ie`) via the Cloudflare DNS challenge,
|
|
||||||
- the internal `ams1.int.nul.ie` / `*` via an `exec` challenge that calls
|
|
||||||
`estuary`'s pdns over SSH.
|
|
||||||
- As a one-off consumer, it then pushes the public cert to the `mail` (Mailcow)
|
|
||||||
VM via `scp` + a remote `mailcow-ssl-reload`.
|
|
||||||
- **nginx-sso** — single-sign-on (`sso.nul.ie`) with Google OAuth and a simple
|
|
||||||
username/password provider; protects the SSO-gated vhosts below.
|
|
||||||
- **librespeed** — speed-test frontend + backend (`librespeed.${domain}` /
|
|
||||||
`speed.nul.ie`).
|
|
||||||
|
|
||||||
## Published vhosts
|
|
||||||
|
|
||||||
All under `*.nul.ie` with the wildcard cert unless noted. Upstreams are addressed
|
|
||||||
by their internal container/VM hostnames. "SSO" = gated behind nginx-sso.
|
|
||||||
|
|
||||||
| Host(s) | Upstream | Notes |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `nul.ie` (default `_`) | static | landing page (CV, SSH pubkey) + Matrix/atproto `.well-known` |
|
|
||||||
| `sso.nul.ie` | nginx-sso | SSO endpoint |
|
|
||||||
| `pass.nul.ie` | `vaultwarden` | password manager |
|
|
||||||
| `matrix.nul.ie` (+`:8448`) | `chatterbox` | Matrix client + federation |
|
|
||||||
| `element.nul.ie` | element-web | Matrix web client |
|
|
||||||
| `toot.nul.ie` | `toot` :80 | Mastodon (currently disabled — see [toot.md](toot.md)) |
|
|
||||||
| `pds.nul.ie` | `toot` :3000 | Bluesky PDS |
|
|
||||||
| `jackflix.nul.ie` | `jackflix` Jellyfin | streaming |
|
|
||||||
| `torrents` / `jackett` / `radarr` / `sonarr` `.nul.ie` | `jackflix` | *arr stack (**SSO**) |
|
|
||||||
| `gib.nul.ie` | `jackflix` Jellyseerr | requests |
|
|
||||||
| `photos.nul.ie` | `jackflix` PhotoPrism | |
|
|
||||||
| `stuff` / `public` / `p.nul.ie` | `jackflix` copyparty + `/mnt/media` | file sharing / index |
|
|
||||||
| `share.nul.ie` | `object` :9090 | |
|
|
||||||
| `minio` / `s3` / `*.s3.nul.ie` | `object` MinIO | S3 + console (Docker manifest MIME hack) |
|
|
||||||
| `nix-cache.nul.ie` | `object` Harmonia | Nix binary cache (immutable cache headers) |
|
|
||||||
| `md.nul.ie` / `pb.nul.ie` | `object` | HedgeDoc / wastebin |
|
|
||||||
| `mc-map` / `mc-rail` / `mc-map-kink` `.nul.ie` | `whale2` OCI | Minecraft maps |
|
|
||||||
| `netdata-colony.nul.ie` | many hosts :19999 | netdata fan-out (**SSO**) |
|
|
||||||
| `pront.nul.ie` | `stream-hi` (home) | print/webcam (**SSO**) |
|
|
||||||
| `hass.nul.ie` | `hass` (home) | Home Assistant |
|
|
||||||
| `hass-john.nul.ie` | `john-valorant-tun` | remote HASS over WireGuard tunnel |
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network; bind-mounts `/mnt/media` for
|
|
||||||
serving static/media content.
|
|
||||||
- nginx waits for `colony-psql` before starting (DNS bootstrap hack).
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# object
|
|
||||||
|
|
||||||
Object storage and Nix binary cache, plus a couple of small self-hosted web
|
|
||||||
apps.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/object.nix`](../../../nixos/boxes/colony/vms/shill/containers/object.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **MinIO** — S3-compatible object storage (`s3.nul.ie` / `*.s3.nul.ie`). Backs
|
|
||||||
several other services (Gitea LFS/artifacts, social-media uploads, …). Stored on the
|
|
||||||
`/mnt/minio` volume (XFS, bind-mounted from `shill`).
|
|
||||||
- **Harmonia** — serves the Nix binary cache for all the boxes (`nix-cache.nul.ie`), backed
|
|
||||||
by the `/mnt/nix-cache` volume.
|
|
||||||
- **atticd** — an alternative Nix cache (stores into MinIO/S3). **Currently
|
|
||||||
disabled** — present in the config but not running.
|
|
||||||
- **HedgeDoc** — collaborative markdown notes.
|
|
||||||
- **wastebin** — pastebin.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `object-ctr`).
|
|
||||||
- `/mnt/minio` and `/mnt/nix-cache` bind-mounted read-write from `shill`.
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# qclk
|
|
||||||
|
|
||||||
The `qclk` service container.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/qclk/`](../../../nixos/boxes/colony/vms/shill/containers/qclk)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs the custom `qclk` service, exposing an API that is reached over a
|
|
||||||
dedicated WireGuard **`management`** network. Managed devices are configured as
|
|
||||||
WireGuard peers (each gets an address in the `qclk` prefix), and AS211024
|
|
||||||
trusted hosts are allowed to reach the API.
|
|
||||||
- `shill` routes the `qclk` prefix to this container.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `qclk-ctr`), plus the
|
|
||||||
`management` WireGuard interface carrying the `qclk` prefix.
|
|
||||||
|
|
||||||
> Check `qclk/default.nix` for the current peer list and exactly what the service
|
|
||||||
> does — this entry intentionally stays high-level.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# shill
|
|
||||||
|
|
||||||
The colony **NixOS container host**. Most colony applications run as
|
|
||||||
systemd-nspawn containers on `shill`.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/colony/vms/shill/`](../../../nixos/boxes/colony/vms/shill)
|
|
||||||
(`default.nix`, `containers-ext.nix`, `hercules.nix`, `containers/`)
|
|
||||||
- **nixpkgs:** `mine`
|
|
||||||
- **Host:** VM on `colony` (large: 12 cores, 40 GiB RAM)
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs the colony NixOS containers via `my.containers.instances`, each attached
|
|
||||||
to the `ctrs` bridge with its own address.
|
|
||||||
- Provides shared data volumes to those containers via bind mounts from
|
|
||||||
LVM-backed disks: `/mnt/media` (→ `middleman`, `jackflix`), `/mnt/minio` and
|
|
||||||
`/mnt/nix-cache` (→ `object`).
|
|
||||||
- Acts as the router between the `vms` network and the `ctrs` container network
|
|
||||||
(sends RAs on `ctrs`, routes Tailscale prefixes via `waffletail` and the
|
|
||||||
`qclk` prefix via `qclk`). Includes an nftables `ct mark` hack to make
|
|
||||||
internal DNAT return paths work.
|
|
||||||
- Tuned sysctls for high connection counts / torrent traffic; netdata.
|
|
||||||
|
|
||||||
## Containers
|
|
||||||
|
|
||||||
Defined in [`shill/containers/`](../../../nixos/boxes/colony/vms/shill/containers)
|
|
||||||
and wired up in `shill`'s `my.containers.instances`:
|
|
||||||
|
|
||||||
| Container | Role |
|
|
||||||
| --- | --- |
|
|
||||||
| [`middleman`](middleman.md) | Front-end nginx reverse proxy, ACME, nginx-sso, librespeed |
|
|
||||||
| [`colony-psql`](colony-psql.md) | Shared PostgreSQL |
|
|
||||||
| [`vaultwarden`](vaultwarden.md) | Password manager |
|
|
||||||
| [`chatterbox`](chatterbox.md) | Matrix homeserver + bridges |
|
|
||||||
| [`toot`](toot.md) | Bluesky PDS (Mastodon disabled) |
|
|
||||||
| [`jackflix`](jackflix.md) | Media stack |
|
|
||||||
| [`object`](object.md) | MinIO / Harmonia / HedgeDoc / wastebin |
|
|
||||||
| [`waffletail`](waffletail.md) | Tailscale subnet router |
|
|
||||||
| [`qclk`](qclk.md) | Clock service |
|
|
||||||
| [`gam`](gam.md) | Game servers |
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Container systems set `my.deploy.enable = false` (they are deployed as part of
|
|
||||||
`shill`'s container profiles, not as standalone deploy nodes) and render via
|
|
||||||
`my.asContainer`.
|
|
||||||
- `hercules.nix` configures Hercules CI agent bits;
|
|
||||||
`containers-ext.nix` holds extra per-container host wiring.
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# toot
|
|
||||||
|
|
||||||
A federated-social container. Despite the name (Mastodon = "toots"), it currently
|
|
||||||
hosts a **Bluesky PDS**; the Mastodon instance is disabled.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/toot.nix`](../../../nixos/boxes/colony/vms/shill/containers/toot.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Bluesky PDS** (Personal Data Server) — the active service, published as
|
|
||||||
`pds.nul.ie` (proxied by `middleman` to `:3000`).
|
|
||||||
- **Mastodon** — **currently disabled**. The config is still present and
|
|
||||||
`toot.nul.ie` still maps to `:80`, but the instance is not running. (It was
|
|
||||||
backed by the shared `colony-psql` and MinIO/S3 on `object`.)
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `toot-ctr`).
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# vaultwarden
|
|
||||||
|
|
||||||
[Vaultwarden](https://github.com/dani-garcia/vaultwarden), a Bitwarden-compatible
|
|
||||||
password manager.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/vaultwarden.nix`](../../../nixos/boxes/colony/vms/shill/containers/vaultwarden.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs Vaultwarden, fronted by `middleman` and published under `nul.ie`.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `vaultwarden-ctr`).
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# waffletail
|
|
||||||
|
|
||||||
The colony Tailscale node / subnet router.
|
|
||||||
|
|
||||||
- **Source:** [`shill/containers/waffletail.nix`](../../../nixos/boxes/colony/vms/shill/containers/waffletail.nix)
|
|
||||||
- **Host:** NixOS container on `shill`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Joins the Tailscale tailnet (auth key from secrets) and **advertises the colony
|
|
||||||
prefixes** into it, acting as the subnet router so tailnet clients can reach
|
|
||||||
colony services and vice-versa.
|
|
||||||
- nftables rules SNAT/forward between `host0` and `tailscale0` for the colony
|
|
||||||
v4/v6 ranges. `shill` routes the Tailscale prefixes here.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment on the `ctrs` network (alt name `waffletail-ctr`); owns
|
|
||||||
the `tailscale0` interface.
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# whale2
|
|
||||||
|
|
||||||
A podman/OCI host on colony dedicated to game servers (kept off `shill` so the
|
|
||||||
container churn and resource use stay isolated).
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/colony/vms/whale2/`](../../../nixos/boxes/colony/vms/whale2)
|
|
||||||
(`default.nix`, `valheim.nix`, `minecraft/`, `enshrouded.nix`)
|
|
||||||
- **nixpkgs:** `mine`
|
|
||||||
- **Host:** VM on `colony`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs OCI containers via **podman** (`virtualisation.oci-containers`, netavark
|
|
||||||
backend) on a dedicated `colony` bridge network (`oci`) with both IPv4 and
|
|
||||||
IPv6, so each game server gets its own routable address.
|
|
||||||
- Game servers configured in-repo: **Valheim**, **Minecraft** (several worlds —
|
|
||||||
see `extraAssignments`: `simpcraft`, `simpcraft-staging`, `kevcraft`,
|
|
||||||
`kinkcraft`, `graeme`), and **Enshrouded** (currently commented out).
|
|
||||||
- `/var/lib/containers` is an XFS data disk (project quotas).
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `vms` interface with `routing` / `internal` (alt name `oci`) assignments.
|
|
||||||
- An `oci` bridge carrying the `prefixes.oci` v4/v6 ranges; per-game addresses
|
|
||||||
are handed out via `extraAssignments` (`valheim-oci`, `simpcraft-oci`, …) and
|
|
||||||
exposed to the internet through `estuary`'s port forwards.
|
|
||||||
- Firewall trusts the `oci` interface and forwards `vms → oci`.
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# home
|
|
||||||
|
|
||||||
The home network. A VM host (`palace`), a redundant pair of routers, a storage
|
|
||||||
server, Home Assistant, and personal desktops.
|
|
||||||
|
|
||||||
- **Domain:** `h.nul.ie`
|
|
||||||
- **Source:** [`nixos/boxes/home/`](../../../nixos/boxes/home)
|
|
||||||
|
|
||||||
## Shape
|
|
||||||
|
|
||||||
```
|
|
||||||
palace (physical VM host)
|
|
||||||
├── river ──── home router (HA pair with stream)
|
|
||||||
├── cellar ── NVMe-oF storage server (SPDK)
|
|
||||||
└── sfh ───── NixOS container host ──┬── hass (Home Assistant)
|
|
||||||
└── unifi (UniFi controller — defined, currently disabled)
|
|
||||||
|
|
||||||
stream ── standalone home router (HA pair with river)
|
|
||||||
castle ── desktop workstation (boots its disks over NVMe-oF from cellar)
|
|
||||||
```
|
|
||||||
|
|
||||||
The two routers `river` (a VM on `palace`) and `stream` (standalone hardware)
|
|
||||||
share the [`routing-common`](../../../nixos/boxes/home/routing-common) config and
|
|
||||||
form a **keepalived/VRRP high-availability pair**: DHCP (kea), router
|
|
||||||
advertisements (radvd), DNS with blocklists, NAT, and the AS211024 L2 mesh link
|
|
||||||
back to colony.
|
|
||||||
|
|
||||||
## Machines
|
|
||||||
|
|
||||||
| Machine | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `palace` | Physical VM host | [palace.md](palace.md) |
|
|
||||||
| `river` | Home router (VM; VRRP pair with `stream`) | [river.md](river.md) |
|
|
||||||
| `cellar` | NVMe-oF storage server (SPDK) | [cellar.md](cellar.md) |
|
|
||||||
| `sfh` | NixOS container host | [sfh.md](sfh.md) |
|
|
||||||
| `stream` | Home router (standalone hardware; VRRP pair with `river`) | [stream.md](stream.md) |
|
|
||||||
| `castle` | Desktop workstation | [castle.md](castle.md) |
|
|
||||||
|
|
||||||
### sfh containers
|
|
||||||
|
|
||||||
| Container | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `hass` | Home Assistant | [hass.md](hass.md) |
|
|
||||||
| `unifi` | UniFi network controller (defined, **currently not imported**) | [unifi.md](unifi.md) |
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# castle
|
|
||||||
|
|
||||||
A desktop workstation.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/home/castle/default.nix`](../../../nixos/boxes/home/castle/default.nix)
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- AMD desktop running the GUI environment (`my.gui.enable`, Sway / Wayland via
|
|
||||||
home-manager).
|
|
||||||
- **Diskless-style boot:** its `/nix`, `/persist` and `/home` are NVMe-oF volumes
|
|
||||||
served by [`cellar`](cellar.md) (`/dev/nvmeof/{nix,persist,home}`). The
|
|
||||||
networking is careful not to drop the IP used for the NVMe-oF connection.
|
|
||||||
- Uses the `my.nvme` module for the NVMe-oF client setup.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- Sits on the home network; depends on the high-speed link to `cellar` for its
|
|
||||||
root storage.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
# cellar
|
|
||||||
|
|
||||||
The home storage server. Exports fast NVMe storage over the network so other
|
|
||||||
machines (notably `castle`) can boot and run from it.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/home/palace/vms/cellar/`](../../../nixos/boxes/home/palace/vms/cellar)
|
|
||||||
(`default.nix`, `spdk.nix`)
|
|
||||||
- **Host:** VM on `palace` (NVMe drives passed through)
|
|
||||||
- **Deploy address:** `192.168.68.80`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs **SPDK** ([`spdk.nix`](../../../nixos/boxes/home/palace/vms/cellar/spdk.nix)) as
|
|
||||||
a userspace storage target. The kernel `nvme` driver is blacklisted so SPDK can
|
|
||||||
drive the NVMe devices directly (attached by PCI BDF).
|
|
||||||
- Builds a **RAID0** (`NVMeRaid`) across three NVMe drives, partitioned into three
|
|
||||||
namespaces, and exports each as an **NVMe-oF target over RDMA** (port 4420) on
|
|
||||||
the high-speed home network — one namespace per consumer:
|
|
||||||
|
|
||||||
| Namespace | NQN | Consumer |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `NVMeRaidp1` | `nqn.2016-06.io.spdk:river` | [`river`](river.md) |
|
|
||||||
| `NVMeRaidp2` | `nqn.2016-06.io.spdk:castle` | [`castle`](castle.md) |
|
|
||||||
| `NVMeRaidp3` | `nqn.2016-06.io.spdk:sfh` | [`sfh`](sfh.md) |
|
|
||||||
|
|
||||||
Each client is pinned by `hostnqn`, so `river`, `castle` and `sfh` all run their
|
|
||||||
storage off `cellar` over the network.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- Exports on the high-speed home network (`lan-hi` / the `hi` assignment) over
|
|
||||||
RDMA; the SPDK target waits for that link to be online before starting.
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- The `ublk_*` calls in `my.spdk.debugCommands` are **only a debugging script** —
|
|
||||||
they let you create a local ublk block device to mount and inspect the RAID on
|
|
||||||
`cellar` itself. They are **not** how storage is exported to clients; that is the
|
|
||||||
`nvmf` config above.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# hass
|
|
||||||
|
|
||||||
[Home Assistant](https://www.home-assistant.io/) — home automation.
|
|
||||||
|
|
||||||
- **Source:** [`sfh/containers/hass.nix`](../../../nixos/boxes/home/palace/vms/sfh/containers/hass.nix)
|
|
||||||
- **Host:** NixOS container on `sfh`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs Home Assistant plus supporting services in the container. The `hass-cli`
|
|
||||||
is wired up against the local server for convenience.
|
|
||||||
- Integrations/automations are configured here (see commit history for things
|
|
||||||
like the "West Wood" integration).
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment (alt name `hass-ctr`), plus a loopback assignment
|
|
||||||
(`hass-ctr-lo`) used internally.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# palace (host)
|
|
||||||
|
|
||||||
The physical VM host for the home network — the home equivalent of `colony`.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/home/palace/default.nix`](../../../nixos/boxes/home/palace/default.nix)
|
|
||||||
(VM instances in [`palace/vms/default.nix`](../../../nixos/boxes/home/palace/vms/default.nix))
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Bare-metal host whose job is to run the home VMs via the `my.vms` module:
|
|
||||||
`river` (router), `cellar` (storage), `sfh` (container host).
|
|
||||||
- Provides the bridged networking those VMs sit on and passes through hardware
|
|
||||||
where needed (e.g. NVMe drives to `cellar`, NICs to `river`).
|
|
||||||
|
|
||||||
## VMs hosted here
|
|
||||||
|
|
||||||
| VM | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `river` | Home router (VRRP pair with `stream`) | [river.md](river.md) |
|
|
||||||
| `cellar` | NVMe-oF storage server | [cellar.md](cellar.md) |
|
|
||||||
| `sfh` | NixOS container host (Home Assistant, …) | [sfh.md](sfh.md) |
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
# river
|
|
||||||
|
|
||||||
One of the two home routers. `river` is a VM on `palace`; it forms a
|
|
||||||
high-availability pair with the standalone `stream`.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/home/palace/vms/river.nix`](../../../nixos/boxes/home/palace/vms/river.nix),
|
|
||||||
built from [`routing-common`](../../../nixos/boxes/home/routing-common) (instance `0`)
|
|
||||||
- **Host:** VM on `palace`
|
|
||||||
- **Deploy address:** `192.168.68.1`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
Everything in [`routing-common`](../../../nixos/boxes/home/routing-common):
|
|
||||||
|
|
||||||
- **VRRP/keepalived** failover with `stream` (`keepalived.nix`) — one router is
|
|
||||||
master at a time, sharing virtual IPs.
|
|
||||||
- **DHCP** via kea (`kea.nix`), **router advertisements** via radvd
|
|
||||||
(`radvd.nix`).
|
|
||||||
- **DNS** (`dns.nix`) — local resolver with a blocklist
|
|
||||||
(`dns-blocklist.txt`) and a periodic update script.
|
|
||||||
- **NAT / firewall** for the home LAN, with policy routing.
|
|
||||||
- **AS211024 L2 mesh** link back to colony/`estuary` (and the other edge
|
|
||||||
routers), so home and colony networks interconnect.
|
|
||||||
|
|
||||||
See [stream.md](stream.md) for the other half of the pair.
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# sfh
|
|
||||||
|
|
||||||
The home **NixOS container host** ("smart from home" / home services).
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/home/palace/vms/sfh/`](../../../nixos/boxes/home/palace/vms/sfh)
|
|
||||||
(`default.nix`, `containers/`)
|
|
||||||
- **Host:** VM on `palace`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs the home NixOS containers via `my.containers.instances`, in the same way
|
|
||||||
`shill` does on colony.
|
|
||||||
- Sits on the home network and connects to NVMe-oF storage (`cellar`) where
|
|
||||||
needed.
|
|
||||||
|
|
||||||
## Containers
|
|
||||||
|
|
||||||
Defined in [`sfh/containers/`](../../../nixos/boxes/home/palace/vms/sfh/containers)
|
|
||||||
and imported from its `containers/default.nix`:
|
|
||||||
|
|
||||||
| Container | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `hass` | Home Assistant | [hass.md](hass.md) |
|
|
||||||
| `unifi` | UniFi controller — **defined but currently commented out** of `containers/default.nix` | [unifi.md](unifi.md) |
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# stream
|
|
||||||
|
|
||||||
One of the two home routers. `stream` is standalone hardware; it forms a
|
|
||||||
high-availability pair with `river` (a VM on `palace`).
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/home/stream.nix`](../../../nixos/boxes/home/stream.nix),
|
|
||||||
built from [`routing-common`](../../../nixos/boxes/home/routing-common) (instance `1`)
|
|
||||||
- **Deploy address:** `192.168.68.2`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Same [`routing-common`](../../../nixos/boxes/home/routing-common) role as
|
|
||||||
[`river`](river.md): keepalived/VRRP, kea DHCP, radvd, DNS + blocklist, NAT and
|
|
||||||
the AS211024 L2 mesh link to colony.
|
|
||||||
- Additionally pulls in `mstpd` (`routing-common/mstpd.nix`) for spanning-tree on
|
|
||||||
its bridged ports — `stream` is the one wired into the physical switching, so
|
|
||||||
it manages the L2 topology.
|
|
||||||
|
|
||||||
See [river.md](river.md) for the other half of the pair.
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# unifi
|
|
||||||
|
|
||||||
The UniFi network controller.
|
|
||||||
|
|
||||||
- **Source:** [`sfh/containers/unifi.nix`](../../../nixos/boxes/home/palace/vms/sfh/containers/unifi.nix)
|
|
||||||
- **Host:** NixOS container on `sfh`
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
> **Currently disabled.** The system is still defined (`nixos.systems.unifi`),
|
|
||||||
> but its import is commented out in
|
|
||||||
> [`sfh/containers/default.nix`](../../../nixos/boxes/home/palace/vms/sfh/containers/default.nix),
|
|
||||||
> so it is not deployed as a container right now. Re-enable by uncommenting
|
|
||||||
> `./unifi.nix` there.
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Runs the UniFi controller (`services.unifi`) to manage the home UniFi network
|
|
||||||
gear.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment (alt name `unifi-ctr`).
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# misc
|
|
||||||
|
|
||||||
Everything that isn't part of the `colony` or `home` sites: the edge VPSes, the
|
|
||||||
remote `kelder` site, a workstation, and the installer image.
|
|
||||||
|
|
||||||
| Machine | What it is | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `britway` | Vultr VPS (London, `lon1`): Headscale, Tailscale exit node, BGP edge, nginx | [britway.md](britway.md) |
|
|
||||||
| `britnet` | VPS (Birmingham, `bhx1`): Tailscale/WireGuard gateway | [britnet.md](britnet.md) |
|
|
||||||
| `kelder` | Remote site host (`hentai.engineer`): NixOS container host | [kelder.md](kelder.md) |
|
|
||||||
| `tower` | Framework Laptop 13 (12th-gen Intel) workstation | [tower.md](tower.md) |
|
|
||||||
| `installer` | Custom NixOS installer image | [installer.md](installer.md) |
|
|
||||||
|
|
||||||
## kelder containers
|
|
||||||
|
|
||||||
`kelder` is itself a container host (like `shill`/`sfh`):
|
|
||||||
|
|
||||||
| Container | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `kelder-acquisition` | Media stack (Jellyfin + *arr + Transmission) | [kelder-acquisition.md](kelder-acquisition.md) |
|
|
||||||
| `kelder-spoder` | nginx web host | [kelder-spoder.md](kelder-spoder.md) |
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# britnet
|
|
||||||
|
|
||||||
A VPS in Birmingham (`bhx1`) acting as a Tailscale/WireGuard gateway node.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/britnet.nix`](../../../nixos/boxes/britnet.nix)
|
|
||||||
- **Internal domain:** `bhx1.int.nul.ie`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Tailscale node** + **WireGuard** (`wg0`) gateway: provides a second egress /
|
|
||||||
entry point into the boxes' overlay networks.
|
|
||||||
- nftables SNATs traffic arriving on `tailscale0` / `wg0` out of the provider
|
|
||||||
interface (`veth0`), using the `allhost` assignment addresses.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- Provider uplink with gateways `77.74.199.1` (v4) / `2a12:ab46:5344::1` (v6).
|
|
||||||
- `tailscale0` and `wg0` overlay interfaces; `allhost` assignment for SNAT.
|
|
||||||
|
|
||||||
> `britnet` is a separate machine from [`britway`](britway.md) — different
|
|
||||||
> provider/site, narrower role (gateway rather than control plane + BGP edge).
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
# britway
|
|
||||||
|
|
||||||
A Vultr VPS in London (`lon1`) acting as a network edge node: the Tailscale
|
|
||||||
control plane, an exit node, and a BGP speaker in the AS211024 mesh.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/britway/`](../../../nixos/boxes/britway)
|
|
||||||
(`default.nix`, `bgp.nix`, `nginx.nix`, `tailscale.nix`)
|
|
||||||
- **Internal domain:** `lon1.int.nul.ie`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Headscale** ([`tailscale.nix`](../../../nixos/boxes/britway/tailscale.nix)) — the
|
|
||||||
self-hosted Tailscale control server (`hs.nul.ie`) the rest of the boxes log
|
|
||||||
into.
|
|
||||||
- **Tailscale node** — advertises itself as an **exit node** and advertises the
|
|
||||||
tailnet routes, so tailnet clients can egress / reach internal prefixes via
|
|
||||||
britway.
|
|
||||||
- **BGP** ([`bgp.nix`](../../../nixos/boxes/britway/bgp.nix)) — part of the AS211024
|
|
||||||
L2 VXLAN mesh (`my.vpns.l2`) alongside `estuary`, `river` and `stream`.
|
|
||||||
- **nginx** ([`nginx.nix`](../../../nixos/boxes/britway/nginx.nix)) — reverse proxy /
|
|
||||||
web front-end with ACME certs.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `vultr` assignment on the provider interface; `as211024` on the mesh.
|
|
||||||
- A `veth0`/`tailscale0` setup with SNAT so tailnet traffic egresses via the VPS
|
|
||||||
public IP.
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# installer
|
|
||||||
|
|
||||||
The custom NixOS installer image used to bootstrap new boxes.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/installer.nix`](../../../nixos/installer.nix)
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Defines `nixos.systems.installer`, a minimal system whose `my.buildAs.*`
|
|
||||||
outputs produce installable artifacts — primarily a bootable **ISO**
|
|
||||||
(`isoImage`), and the same base is reused for kexec/netboot trees.
|
|
||||||
- Build it with the devshell commands (see [`AGENTS.md`](../../../AGENTS.md#commands)):
|
|
||||||
- `build-iso installer`
|
|
||||||
- `build-kexec installer` / `build-netboot installer`
|
|
||||||
- A released ISO is what `colony`'s VM definitions reference as install media; the
|
|
||||||
`update-installer` devshell command tags a release to trigger a rebuild.
|
|
||||||
|
|
||||||
This is a build target rather than a deployed machine — there is no running
|
|
||||||
`installer` host.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# kelder-acquisition
|
|
||||||
|
|
||||||
The media stack for the `kelder` site — a slimmer cousin of colony's
|
|
||||||
[`jackflix`](../colony/jackflix.md).
|
|
||||||
|
|
||||||
- **Source:** [`kelder/containers/acquisition/`](../../../nixos/boxes/kelder/containers/acquisition)
|
|
||||||
(`default.nix`, `networking.nix`)
|
|
||||||
- **Host:** NixOS container on `kelder`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Jellyfin** for streaming (with hardware transcoding — the `jellyfin` user is
|
|
||||||
in the `render` group, `jellyfin-ffmpeg`).
|
|
||||||
- **Acquisition:** Transmission, Jackett, Radarr, Sonarr.
|
|
||||||
- Runs under the site's shared `kontent` user.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment (alt name `acquisition-ctr`) on the kelder container
|
|
||||||
network; download client networking in `networking.nix`.
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# kelder-spoder
|
|
||||||
|
|
||||||
An nginx web host on the `kelder` site.
|
|
||||||
|
|
||||||
- **Source:** [`kelder/containers/spoder/`](../../../nixos/boxes/kelder/containers/spoder)
|
|
||||||
(`default.nix`, `nginx.nix`)
|
|
||||||
- **Host:** NixOS container on `kelder`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Serves web content via **nginx** ([`nginx.nix`](../../../nixos/boxes/kelder/containers/spoder/nginx.nix)),
|
|
||||||
with ACME-managed certificates (nginx in the `acme` group, reloads on renewal).
|
|
||||||
- Runs under the site's shared `kontent` user.
|
|
||||||
|
|
||||||
## Networking
|
|
||||||
|
|
||||||
- `internal` assignment (alt name `spoder-ctr`) on the kelder container network.
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
# kelder
|
|
||||||
|
|
||||||
A host at a remote site ("kelder" = cellar/basement), linked back to the rest of
|
|
||||||
the other boxes over WireGuard. It is itself a **NixOS container host**.
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/kelder/`](../../../nixos/boxes/kelder)
|
|
||||||
(`default.nix`, `boot.nix`, `containers/`, `plymouth/`)
|
|
||||||
- **Domain:** `hentai.engineer`
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- **Site uplink:** connects to colony's `estuary` over **WireGuard**
|
|
||||||
(`kelder` peer; see [estuary.md](../colony/estuary.md)), so the remote site is
|
|
||||||
reachable through the colony edge. A periodic `dns_update.py` keeps DNS current.
|
|
||||||
- **Container host:** runs NixOS containers via `my.containers.instances`
|
|
||||||
(`acquisition`, `spoder`).
|
|
||||||
- Custom boot/splash (`boot.nix`, Plymouth theme in `plymouth/`).
|
|
||||||
|
|
||||||
## Containers
|
|
||||||
|
|
||||||
| Container | Role | Docs |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `kelder-acquisition` | Media stack (Jellyfin + *arr + Transmission) | [kelder-acquisition.md](kelder-acquisition.md) |
|
|
||||||
| `kelder-spoder` | nginx web host | [kelder-spoder.md](kelder-spoder.md) |
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
# tower
|
|
||||||
|
|
||||||
A laptop workstation — a Framework Laptop 13 (12th-gen Intel).
|
|
||||||
|
|
||||||
- **Source:** [`nixos/boxes/tower/default.nix`](../../../nixos/boxes/tower/default.nix)
|
|
||||||
|
|
||||||
## Role
|
|
||||||
|
|
||||||
- Framework Laptop 13 (12th-gen Intel) running the GUI environment
|
|
||||||
(`my.gui.enable`) with home-manager on the `mine` channel.
|
|
||||||
- Joins the tailnet via the self-hosted Headscale on [`britway`](britway.md)
|
|
||||||
(`tailscale up --login-server=https://hs.nul.ie --accept-routes`).
|
|
||||||
- Local virtualisation enabled (`kvm-intel`, IOMMU on).
|
|
||||||
|
|
||||||
> Unlike [`castle`](../home/castle.md), `tower` lives outside the `home/` box
|
|
||||||
> tree and boots from local disks rather than NVMe-oF.
|
|
||||||
Generated
+88
-142
@@ -8,7 +8,7 @@
|
|||||||
"ragenix",
|
"ragenix",
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
"systems": "systems_7"
|
"systems": "systems_6"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761656077,
|
"lastModified": 1761656077,
|
||||||
@@ -75,11 +75,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781351267,
|
"lastModified": 1764708670,
|
||||||
"narHash": "sha256-86HFs1K+LRlx8t4AjaMdU5qlg4O7kLz1VlnNapKZIuY=",
|
"narHash": "sha256-Gdo9lD6JwXGMVFJ8ZHCENcxXg30SG72kwsHnxPDCscI=",
|
||||||
"owner": "9001",
|
"owner": "9001",
|
||||||
"repo": "copyparty",
|
"repo": "copyparty",
|
||||||
"rev": "90639de9840d7dcc2d9000026fe547f666c1d550",
|
"rev": "29925dc22b1f6810768d0af25d9c35ee35d88aa7",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -90,11 +90,11 @@
|
|||||||
},
|
},
|
||||||
"crane": {
|
"crane": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1780532242,
|
"lastModified": 1763938834,
|
||||||
"narHash": "sha256-D+BsdpxmtUwtqGoY0IXPhHgTlmqgcZKCEo1oMyn7ep0=",
|
"narHash": "sha256-j8iB0Yr4zAvQLueCZ5abxfk6fnG/SJ5JnGUziETjwfg=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "59a82a1222dd3b2080b5cc52a1a2e8d5f1b77f37",
|
"rev": "d9e753122e51cee64eb8d2dddfe11148f339f5a2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -105,8 +105,8 @@
|
|||||||
},
|
},
|
||||||
"crane_2": {
|
"crane_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760924934,
|
"lastModified": 1725409566,
|
||||||
"narHash": "sha256-tuuqY5aU7cUkR71sO2TraVKK2boYrdW3gCSXUkF4i44=",
|
"narHash": "sha256-PrtLmqhM6UtJP7v7IGyzjBFhbG4eOAHT6LPYOFmYfbk=",
|
||||||
"owner": "ipetkov",
|
"owner": "ipetkov",
|
||||||
"repo": "crane",
|
"repo": "crane",
|
||||||
"rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
|
"rev": "c6b4d5308293d0d04fcfeee92705017537cad02f",
|
||||||
@@ -150,11 +150,11 @@
|
|||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781023725,
|
"lastModified": 1762286984,
|
||||||
"narHash": "sha256-Gt+qFANcrDRjl3xzidLYrAUQCd3808iuAsLwZbYYAEU=",
|
"narHash": "sha256-9I2H9x5We6Pl+DBYHjR1s3UT8wgwcpAH03kn9CqtdQc=",
|
||||||
"owner": "serokell",
|
"owner": "serokell",
|
||||||
"repo": "deploy-rs",
|
"repo": "deploy-rs",
|
||||||
"rev": "2ce9051767ee4d1a3c43b52ba327431783bfd463",
|
"rev": "9c870f63e28ec1e83305f7f6cb73c941e699f74f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -184,8 +184,8 @@
|
|||||||
},
|
},
|
||||||
"devshell-tools": {
|
"devshell-tools": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_10",
|
"flake-utils": "flake-utils_9",
|
||||||
"nixpkgs": "nixpkgs_5"
|
"nixpkgs": "nixpkgs_4"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1710099997,
|
"lastModified": 1710099997,
|
||||||
@@ -227,11 +227,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768818222,
|
"lastModified": 1764011051,
|
||||||
"narHash": "sha256-460jc0+CZfyaO8+w8JNtlClB2n4ui1RbHfPTLkpwhU8=",
|
"narHash": "sha256-M7SZyPZiqZUR/EiiBJnmyUbOi5oE/03tCeFrTiUZchI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "devshell",
|
"repo": "devshell",
|
||||||
"rev": "255a2b1725a20d060f566e4755dbf571bbbb5f76",
|
"rev": "17ed8d9744ebe70424659b0ef74ad6d41fc87071",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -256,6 +256,27 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": [
|
||||||
|
"harmonia",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1763759067,
|
||||||
|
"narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
@@ -278,24 +299,6 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_9"
|
"systems": "systems_9"
|
||||||
},
|
},
|
||||||
"locked": {
|
|
||||||
"lastModified": 1709126324,
|
|
||||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils_11": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems_10"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705309234,
|
"lastModified": 1705309234,
|
||||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||||
@@ -310,7 +313,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils_12": {
|
"flake-utils_11": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667395993,
|
"lastModified": 1667395993,
|
||||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||||
@@ -426,7 +429,7 @@
|
|||||||
},
|
},
|
||||||
"flake-utils_8": {
|
"flake-utils_8": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_6"
|
"systems": "systems_7"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1731533236,
|
||||||
@@ -447,11 +450,11 @@
|
|||||||
"systems": "systems_8"
|
"systems": "systems_8"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1709126324,
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -463,6 +466,7 @@
|
|||||||
"harmonia": {
|
"harmonia": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"crane": "crane",
|
"crane": "crane",
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
"nix": "nix",
|
"nix": "nix",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs-unstable"
|
"nixpkgs-unstable"
|
||||||
@@ -470,37 +474,17 @@
|
|||||||
"treefmt-nix": "treefmt-nix"
|
"treefmt-nix": "treefmt-nix"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781128165,
|
"lastModified": 1765032623,
|
||||||
"narHash": "sha256-97WpKZkaNAL5g7MtASLwqnrJrvrLpQRr6cXWiRNLiXQ=",
|
"narHash": "sha256-BbtN5NFN2RU3KP2TLA6zOoiv5MZXWqN1mXxIkKY8Kx4=",
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "harmonia",
|
|
||||||
"rev": "f0dd1094cdc8d72e038cf9347cacfa9272a8f72d",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "harmonia",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hass-west-wood": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils_7",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs-unstable"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1781402797,
|
|
||||||
"narHash": "sha256-pBdDca7xv1nuP0kj+gC5g5AcR/DV+9Zy3CS6uDOMdJ4=",
|
|
||||||
"owner": "devplayer0",
|
"owner": "devplayer0",
|
||||||
"repo": "hass-west-wood",
|
"repo": "harmonia",
|
||||||
"rev": "3e6ef7a9084e4053c82dea20127a775e7bcf77a5",
|
"rev": "310e2b2c6583710c52531785f1245d9621284310",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "devplayer0",
|
"owner": "devplayer0",
|
||||||
"repo": "hass-west-wood",
|
"ref": "cache-config-daemon-store",
|
||||||
|
"repo": "harmonia",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -533,16 +517,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781319724,
|
"lastModified": 1764866045,
|
||||||
"narHash": "sha256-ZGuxexEMo4Xv28KJ0dX/m/PHN4oZIOnxHZpNTyrvx4M=",
|
"narHash": "sha256-0GsEtXV9OquDQ1VclQfP16cU5VZh7NEVIOjSH4UaJuM=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "8355f0a16b2dbb06a97959a918af5b239bbe05ae",
|
"rev": "f63d0fe9d81d36e5fc95497217a72e02b8b7bcab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "home-manager",
|
"id": "home-manager",
|
||||||
"ref": "release-26.05",
|
"ref": "release-25.11",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -553,11 +537,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781305496,
|
"lastModified": 1764872372,
|
||||||
"narHash": "sha256-g8Vv4Qfc7n+lgov97REu3X6BeJtvYY0hlSUZR1GrGQQ=",
|
"narHash": "sha256-uZuXRz9CzeCHsRbc2MQvKomwoX6GcFC5BUMEk3ouSFU=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "c87a39aa979acc4848016d2220c6238390d84779",
|
"rev": "05a56dbf24f195c62286e3273a2671d3b4904b00",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -566,18 +550,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"impermanence": {
|
"impermanence": {
|
||||||
"inputs": {
|
|
||||||
"home-manager": [
|
|
||||||
"home-manager-unstable"
|
|
||||||
],
|
|
||||||
"nixpkgs": "nixpkgs_4"
|
|
||||||
},
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1769548169,
|
"lastModified": 1737831083,
|
||||||
"narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=",
|
"narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "impermanence",
|
"repo": "impermanence",
|
||||||
"rev": "7b1d382faf603b6d264f58627330f9faa5cba149",
|
"rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -589,11 +567,11 @@
|
|||||||
"libnetRepo": {
|
"libnetRepo": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1776595118,
|
"lastModified": 1745053097,
|
||||||
"narHash": "sha256-6bIEi8q5hXCHU9nApTbQXvpljMWldg3QipCD+jkOGK8=",
|
"narHash": "sha256-BEW57utyWCqP4U+MzCXFqbvEC8LE3iZv5dsPMrmTJ9Q=",
|
||||||
"owner": "oddlama",
|
"owner": "oddlama",
|
||||||
"repo": "nixos-extra-modules",
|
"repo": "nixos-extra-modules",
|
||||||
"rev": "84207afebb794be7b53cfc9768730f37c64f4a13",
|
"rev": "7565d8554b0fc9d621851150e7939d34a3a8cd6c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -605,11 +583,11 @@
|
|||||||
"nix": {
|
"nix": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1780652321,
|
"lastModified": 1764532838,
|
||||||
"narHash": "sha256-o/6YXRB6AbeL4SYtSHlJ9oEROl6Wmf7yheJNa3fAv2I=",
|
"narHash": "sha256-hw4J7wfqXWBCvsMVXPS4nvkcSeTXAtR5h9Ylv7a7dBA=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nix",
|
"repo": "nix",
|
||||||
"rev": "d1f04a798cf4276da59567c07a3bf4a628669288",
|
"rev": "8be9507a88f466dd44e6e56cd00167fa10e995b8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -620,7 +598,7 @@
|
|||||||
},
|
},
|
||||||
"nixGL": {
|
"nixGL": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_8",
|
"flake-utils": "flake-utils_7",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs-unstable"
|
"nixpkgs-unstable"
|
||||||
]
|
]
|
||||||
@@ -657,11 +635,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-mine": {
|
"nixpkgs-mine": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781356656,
|
"lastModified": 1765034197,
|
||||||
"narHash": "sha256-Ygkl3ZBJ434/WhwdK1FyvPMeHvNPAopg3KE/1HtcJuk=",
|
"narHash": "sha256-SioIdjObnBC/N78okBChJpcfNns3qLsyXrMaBLx6uio=",
|
||||||
"owner": "devplayer0",
|
"owner": "devplayer0",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a15e20705db295f621cb5bb63613f03a9373323f",
|
"rev": "96f12e0722c76b4113f8bd4c4fd18532b35d5a7f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -673,11 +651,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-mine-stable": {
|
"nixpkgs-mine-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781356876,
|
"lastModified": 1765034227,
|
||||||
"narHash": "sha256-s8ed+zuk5wrbyhtDQpkxycAcLmhQH9umGRuVRBNKUbU=",
|
"narHash": "sha256-5yQGE8/IvyHV1xQsESjhQumSzPcAmeLXFCY6ZdGDpek=",
|
||||||
"owner": "devplayer0",
|
"owner": "devplayer0",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "2eb8bacf9f641d4510fc43ba7fc0eea7dfdf5b24",
|
"rev": "c07d5abb1e18828369dabbda975b7374d39347c0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -689,26 +667,26 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs-stable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1780902259,
|
"lastModified": 1764677808,
|
||||||
"narHash": "sha256-q8yYEC5f1mFlQO9RGna4LTc9QrcvWunX6FYp83munkQ=",
|
"narHash": "sha256-H3lC7knbXOBrHI9hITQ7modLuX20mYJVhZORL5ioms0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "bd0ff2d3eac24699c3664d5966b9ef36f388e2ca",
|
"rev": "1aab89277eb2d87823d5b69bae631a2496cff57a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
"ref": "nixos-26.05",
|
"ref": "nixos-25.11",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781074563,
|
"lastModified": 1764667669,
|
||||||
"narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
|
"narHash": "sha256-7WUCZfmqLAssbDqwg9cUDAXrSoXN79eEEq17qhTNM/Y=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
|
"rev": "418468ac9527e799809c900eda37cbff999199b6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -748,22 +726,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_4": {
|
"nixpkgs_4": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1768564909,
|
|
||||||
"narHash": "sha256-Kell/SpJYVkHWMvnhqJz/8DqQg2b6PguxVWOuadbHCc=",
|
|
||||||
"owner": "nixos",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "e4bae1bd10c9c57b2cf517953ab70060a828ee6f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixos",
|
|
||||||
"ref": "nixos-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_5": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1709309926,
|
"lastModified": 1709309926,
|
||||||
"narHash": "sha256-VZFBtXGVD9LWTecGi6eXrE0hJ/mVB3zGUlHImUs2Qak=",
|
"narHash": "sha256-VZFBtXGVD9LWTecGi6eXrE0hJ/mVB3zGUlHImUs2Qak=",
|
||||||
@@ -779,7 +741,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_6": {
|
"nixpkgs_5": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1674990008,
|
"lastModified": 1674990008,
|
||||||
"narHash": "sha256-4zOyp+hFW2Y7imxIpZqZGT8CEqKmDjwgfD6BzRUE0mQ=",
|
"narHash": "sha256-4zOyp+hFW2Y7imxIpZqZGT8CEqKmDjwgfD6BzRUE0mQ=",
|
||||||
@@ -820,7 +782,7 @@
|
|||||||
"inputs": {
|
"inputs": {
|
||||||
"agenix": "agenix",
|
"agenix": "agenix",
|
||||||
"crane": "crane_2",
|
"crane": "crane_2",
|
||||||
"flake-utils": "flake-utils_9",
|
"flake-utils": "flake-utils_8",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs-unstable"
|
"nixpkgs-unstable"
|
||||||
],
|
],
|
||||||
@@ -850,7 +812,6 @@
|
|||||||
"devshell": "devshell_3",
|
"devshell": "devshell_3",
|
||||||
"flake-utils": "flake-utils_6",
|
"flake-utils": "flake-utils_6",
|
||||||
"harmonia": "harmonia",
|
"harmonia": "harmonia",
|
||||||
"hass-west-wood": "hass-west-wood",
|
|
||||||
"home-manager-stable": "home-manager-stable",
|
"home-manager-stable": "home-manager-stable",
|
||||||
"home-manager-unstable": "home-manager-unstable",
|
"home-manager-unstable": "home-manager-unstable",
|
||||||
"impermanence": "impermanence",
|
"impermanence": "impermanence",
|
||||||
@@ -887,8 +848,8 @@
|
|||||||
},
|
},
|
||||||
"sbt": {
|
"sbt": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_12",
|
"flake-utils": "flake-utils_11",
|
||||||
"nixpkgs": "nixpkgs_6"
|
"nixpkgs": "nixpkgs_5"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1698464090,
|
"lastModified": 1698464090,
|
||||||
@@ -907,7 +868,7 @@
|
|||||||
"sharry": {
|
"sharry": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"devshell-tools": "devshell-tools",
|
"devshell-tools": "devshell-tools",
|
||||||
"flake-utils": "flake-utils_11",
|
"flake-utils": "flake-utils_10",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs-unstable"
|
"nixpkgs-unstable"
|
||||||
],
|
],
|
||||||
@@ -942,21 +903,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems_10": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems_2": {
|
"systems_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
@@ -1085,11 +1031,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1780220602,
|
"lastModified": 1761311587,
|
||||||
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
|
"narHash": "sha256-Msq86cR5SjozQGCnC6H8C+0cD4rnx91BPltZ9KK613Y=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
|
"rev": "2eddae033e4e74bf581c2d1dfa101f9033dbd2dc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
devshell.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
devshell.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
|
||||||
nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
|
nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
|
||||||
nixpkgs-stable.url = "nixpkgs/nixos-26.05";
|
nixpkgs-stable.url = "nixpkgs/nixos-25.11";
|
||||||
nixpkgs-mine.url = "github:devplayer0/nixpkgs/devplayer0";
|
nixpkgs-mine.url = "github:devplayer0/nixpkgs/devplayer0";
|
||||||
nixpkgs-mine-stable.url = "github:devplayer0/nixpkgs/devplayer0-stable";
|
nixpkgs-mine-stable.url = "github:devplayer0/nixpkgs/devplayer0-stable";
|
||||||
|
|
||||||
home-manager-unstable.url = "home-manager";
|
home-manager-unstable.url = "home-manager";
|
||||||
home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
home-manager-stable.url = "home-manager/release-26.05";
|
home-manager-stable.url = "home-manager/release-25.11";
|
||||||
home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable";
|
home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable";
|
||||||
|
|
||||||
# Stuff used by the flake for build / deployment
|
# Stuff used by the flake for build / deployment
|
||||||
@@ -30,13 +30,12 @@
|
|||||||
|
|
||||||
# Stuff used by systems
|
# Stuff used by systems
|
||||||
impermanence.url = "github:nix-community/impermanence";
|
impermanence.url = "github:nix-community/impermanence";
|
||||||
impermanence.inputs.home-manager.follows = "home-manager-unstable";
|
|
||||||
boardie.url = "github:devplayer0/boardie";
|
boardie.url = "github:devplayer0/boardie";
|
||||||
boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
nixGL.url = "github:nix-community/nixGL";
|
nixGL.url = "github:nix-community/nixGL";
|
||||||
nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
harmonia.url = "github:nix-community/harmonia";
|
# harmonia.url = "github:nix-community/harmonia";
|
||||||
# harmonia.url = "github:devplayer0/harmonia/cache-config-daemon-store";
|
harmonia.url = "github:devplayer0/harmonia/cache-config-daemon-store";
|
||||||
harmonia.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
harmonia.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
|
|
||||||
# Packages not in nixpkgs
|
# Packages not in nixpkgs
|
||||||
@@ -47,8 +46,6 @@
|
|||||||
# borgthin.inputs.nixpkgs.follows = "nixpkgs-mine";
|
# borgthin.inputs.nixpkgs.follows = "nixpkgs-mine";
|
||||||
copyparty.url = "github:9001/copyparty";
|
copyparty.url = "github:9001/copyparty";
|
||||||
copyparty.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
copyparty.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
hass-west-wood.url = "github:devplayer0/hass-west-wood";
|
|
||||||
hass-west-wood.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
|
|||||||
@@ -133,32 +133,34 @@ in
|
|||||||
ssh = {
|
ssh = {
|
||||||
enable = mkDefault true;
|
enable = mkDefault true;
|
||||||
enableDefaultConfig = false;
|
enableDefaultConfig = false;
|
||||||
settings = {
|
matchBlocks = {
|
||||||
nix-dev-vm = {
|
nix-dev-vm = {
|
||||||
User = "dev";
|
user = "dev";
|
||||||
HostName = "localhost";
|
hostname = "localhost";
|
||||||
Port = 2222;
|
port = 2222;
|
||||||
|
extraOptions = {
|
||||||
StrictHostKeyChecking = "no";
|
StrictHostKeyChecking = "no";
|
||||||
UserKnownHostsFile = "/dev/null";
|
UserKnownHostsFile = "/dev/null";
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
"rsync.net" = {
|
"rsync.net" = {
|
||||||
Host = "rsyncnet";
|
host = "rsyncnet";
|
||||||
User = "16413";
|
user = "16413";
|
||||||
HostName = "ch-s010.rsync";
|
hostname = "ch-s010.rsync";
|
||||||
};
|
};
|
||||||
|
|
||||||
shoe = {
|
shoe = {
|
||||||
Host = "shoe.netsoc.tcd.ie shoe";
|
host = "shoe.netsoc.tcd.ie shoe";
|
||||||
User = "netsoc";
|
user = "netsoc";
|
||||||
};
|
};
|
||||||
netsocBoxes = {
|
netsocBoxes = {
|
||||||
Host = "cube spoon napalm gandalf saruman";
|
host = "cube spoon napalm gandalf saruman";
|
||||||
User = "root";
|
user = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
"*" = {
|
"*" = {
|
||||||
IdentityFile = [
|
identityFile = [
|
||||||
"~/.ssh/id_rsa"
|
"~/.ssh/id_rsa"
|
||||||
"~/.ssh/borg"
|
"~/.ssh/borg"
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,520 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Source: https://github.com/daniel3303/ClaudeCodeStatusLine
|
|
||||||
# Single line: Model | tokens | %used | %remain | think | 5h bar @reset | 7d bar @reset | extra
|
|
||||||
|
|
||||||
set -f # disable globbing
|
|
||||||
VERSION="1.4.4"
|
|
||||||
|
|
||||||
input=$(cat)
|
|
||||||
|
|
||||||
if [ -z "$input" ]; then
|
|
||||||
printf "Claude"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ANSI colors matching oh-my-posh theme
|
|
||||||
blue='\033[38;2;0;153;255m'
|
|
||||||
orange='\033[38;2;255;176;85m'
|
|
||||||
green='\033[38;2;0;160;0m'
|
|
||||||
cyan='\033[38;2;46;149;153m'
|
|
||||||
red='\033[38;2;255;85;85m'
|
|
||||||
yellow='\033[38;2;230;200;0m'
|
|
||||||
purple='\033[38;2;167;139;250m'
|
|
||||||
white='\033[38;2;220;220;220m'
|
|
||||||
dim='\033[2m'
|
|
||||||
reset='\033[0m'
|
|
||||||
|
|
||||||
# Format token counts (e.g., 50k / 200k)
|
|
||||||
format_tokens() {
|
|
||||||
local num=$1
|
|
||||||
if [ "$num" -ge 1000000 ]; then
|
|
||||||
awk "BEGIN {v=sprintf(\"%.1f\",$num/1000000)+0; if(v==int(v)) printf \"%dm\",v; else printf \"%.1fm\",v}"
|
|
||||||
elif [ "$num" -ge 1000 ]; then
|
|
||||||
awk "BEGIN {printf \"%.0fk\", $num / 1000}"
|
|
||||||
else
|
|
||||||
printf "%d" "$num"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Format number with commas (e.g., 134,938)
|
|
||||||
format_commas() {
|
|
||||||
printf "%'d" "$1"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return color escape based on usage percentage
|
|
||||||
# Usage: usage_color <pct>
|
|
||||||
usage_color() {
|
|
||||||
local pct=$1
|
|
||||||
if [ "$pct" -ge 90 ]; then echo "$red"
|
|
||||||
elif [ "$pct" -ge 70 ]; then echo "$orange"
|
|
||||||
elif [ "$pct" -ge 50 ]; then echo "$yellow"
|
|
||||||
else echo "$green"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Resolve config directory: CLAUDE_CONFIG_DIR (set by alias) or default ~/.claude
|
|
||||||
claude_config_dir="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
||||||
|
|
||||||
# Return 0 (true) if $1 > $2 using semantic versioning
|
|
||||||
version_gt() {
|
|
||||||
local a="${1#v}" b="${2#v}"
|
|
||||||
local IFS='.'
|
|
||||||
read -r a1 a2 a3 <<< "$a"
|
|
||||||
read -r b1 b2 b3 <<< "$b"
|
|
||||||
a1=${a1:-0}; a2=${a2:-0}; a3=${a3:-0}
|
|
||||||
b1=${b1:-0}; b2=${b2:-0}; b3=${b3:-0}
|
|
||||||
[ "$a1" -gt "$b1" ] 2>/dev/null && return 0
|
|
||||||
[ "$a1" -lt "$b1" ] 2>/dev/null && return 1
|
|
||||||
[ "$a2" -gt "$b2" ] 2>/dev/null && return 0
|
|
||||||
[ "$a2" -lt "$b2" ] 2>/dev/null && return 1
|
|
||||||
[ "$a3" -gt "$b3" ] 2>/dev/null && return 0
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
# ===== Extract data from JSON =====
|
|
||||||
model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"')
|
|
||||||
model_name=$(echo "$model_name" | sed 's/ *(\([0-9.]*[kKmM]*\) context)/ \1/') # "(1M context)" → "1M"
|
|
||||||
|
|
||||||
# Context window
|
|
||||||
size=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
|
|
||||||
[ "$size" -eq 0 ] 2>/dev/null && size=200000
|
|
||||||
|
|
||||||
# Token usage
|
|
||||||
input_tokens=$(echo "$input" | jq -r '.context_window.current_usage.input_tokens // 0')
|
|
||||||
cache_create=$(echo "$input" | jq -r '.context_window.current_usage.cache_creation_input_tokens // 0')
|
|
||||||
cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')
|
|
||||||
current=$(( input_tokens + cache_create + cache_read ))
|
|
||||||
|
|
||||||
used_tokens=$(format_tokens $current)
|
|
||||||
total_tokens=$(format_tokens $size)
|
|
||||||
|
|
||||||
if [ "$size" -gt 0 ]; then
|
|
||||||
pct_used=$(( current * 100 / size ))
|
|
||||||
else
|
|
||||||
pct_used=0
|
|
||||||
fi
|
|
||||||
pct_remain=$(( 100 - pct_used ))
|
|
||||||
|
|
||||||
used_comma=$(format_commas $current)
|
|
||||||
remain_comma=$(format_commas $(( size - current )))
|
|
||||||
|
|
||||||
settings_path="$claude_config_dir/settings.json"
|
|
||||||
effort_level=""
|
|
||||||
stdin_effort=$(echo "$input" | jq -r '.effort.level // empty' 2>/dev/null)
|
|
||||||
if [ -n "$stdin_effort" ]; then
|
|
||||||
effort_level="$stdin_effort"
|
|
||||||
elif [ -n "$CLAUDE_CODE_EFFORT_LEVEL" ]; then
|
|
||||||
effort_level="$CLAUDE_CODE_EFFORT_LEVEL"
|
|
||||||
elif [ -f "$settings_path" ]; then
|
|
||||||
effort_val=$(jq -r '.effortLevel // empty' "$settings_path" 2>/dev/null)
|
|
||||||
[ -n "$effort_val" ] && effort_level="$effort_val"
|
|
||||||
fi
|
|
||||||
[ -z "$effort_level" ] && effort_level="medium"
|
|
||||||
|
|
||||||
# ===== Claude CLI version (cached, 1h TTL) =====
|
|
||||||
cli_version_cache="/tmp/claude/statusline-cli-version"
|
|
||||||
cli_version=""
|
|
||||||
cli_version_max_age=3600
|
|
||||||
|
|
||||||
if [ -f "$cli_version_cache" ]; then
|
|
||||||
cv_mtime=$(stat -c %Y "$cli_version_cache" 2>/dev/null || stat -f %m "$cli_version_cache" 2>/dev/null)
|
|
||||||
cv_now=$(date +%s)
|
|
||||||
cv_age=$(( cv_now - cv_mtime ))
|
|
||||||
if [ "$cv_age" -lt "$cli_version_max_age" ]; then
|
|
||||||
cli_version=$(cat "$cli_version_cache" 2>/dev/null)
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$cli_version" ]; then
|
|
||||||
cli_version=$(claude --version 2>/dev/null | awk '{print $1}')
|
|
||||||
if [ -n "$cli_version" ]; then
|
|
||||||
mkdir -p /tmp/claude 2>/dev/null
|
|
||||||
echo "$cli_version" > "$cli_version_cache"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ===== Build single-line output =====
|
|
||||||
out=""
|
|
||||||
out+="${blue}${model_name}${reset}"
|
|
||||||
|
|
||||||
# Current working directory
|
|
||||||
cwd=$(echo "$input" | jq -r '.cwd // empty')
|
|
||||||
if [ -n "$cwd" ]; then
|
|
||||||
display_dir="${cwd##*/}"
|
|
||||||
git_branch=$(git -C "${cwd}" rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
||||||
out+=" ${dim}|${reset} "
|
|
||||||
out+="${cyan}${display_dir}${reset}"
|
|
||||||
if [ -n "$git_branch" ]; then
|
|
||||||
out+="${dim}@${reset}${green}${git_branch}${reset}"
|
|
||||||
git_stat=$(git -C "${cwd}" diff --numstat 2>/dev/null | awk '{a+=$1; d+=$2} END {if (a+d>0) printf "+%d -%d", a, d}')
|
|
||||||
[ -n "$git_stat" ] && out+=" ${dim}(${reset}${green}${git_stat%% *}${reset} ${red}${git_stat##* }${reset}${dim})${reset}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
out+=" ${dim}|${reset} "
|
|
||||||
out+="${orange}${used_tokens}/${total_tokens}${reset} ${dim}(${reset}${green}${pct_used}%${reset}${dim})${reset}"
|
|
||||||
out+=" ${dim}|${reset} "
|
|
||||||
out+="effort: "
|
|
||||||
case "$effort_level" in
|
|
||||||
low) out+="${dim}${effort_level}${reset}" ;;
|
|
||||||
medium) out+="${orange}med${reset}" ;;
|
|
||||||
high) out+="${green}${effort_level}${reset}" ;;
|
|
||||||
xhigh) out+="${purple}${effort_level}${reset}" ;;
|
|
||||||
max) out+="${red}${effort_level}${reset}" ;;
|
|
||||||
*) out+="${green}${effort_level}${reset}" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# ===== Cross-platform OAuth token resolution (from statusline.sh) =====
|
|
||||||
# Tries credential sources in order: env var → macOS Keychain → Linux creds file → GNOME Keyring
|
|
||||||
get_oauth_token() {
|
|
||||||
local token=""
|
|
||||||
|
|
||||||
# 1. Explicit env var override
|
|
||||||
if [ -n "$CLAUDE_CODE_OAUTH_TOKEN" ]; then
|
|
||||||
echo "$CLAUDE_CODE_OAUTH_TOKEN"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 2. macOS Keychain (Claude Code appends a SHA256 hash of CLAUDE_CONFIG_DIR to the service name)
|
|
||||||
if command -v security >/dev/null 2>&1; then
|
|
||||||
local keychain_svc="Claude Code-credentials"
|
|
||||||
if [ -n "$CLAUDE_CONFIG_DIR" ]; then
|
|
||||||
local dir_hash
|
|
||||||
dir_hash=$(echo -n "$CLAUDE_CONFIG_DIR" | shasum -a 256 | cut -c1-8)
|
|
||||||
keychain_svc="Claude Code-credentials-${dir_hash}"
|
|
||||||
fi
|
|
||||||
local blob
|
|
||||||
blob=$(security find-generic-password -s "$keychain_svc" -w 2>/dev/null)
|
|
||||||
if [ -n "$blob" ]; then
|
|
||||||
token=$(echo "$blob" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
|
|
||||||
if [ -n "$token" ] && [ "$token" != "null" ]; then
|
|
||||||
echo "$token"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 3. Linux credentials file
|
|
||||||
local creds_file="${claude_config_dir}/.credentials.json"
|
|
||||||
if [ -f "$creds_file" ]; then
|
|
||||||
token=$(jq -r '.claudeAiOauth.accessToken // empty' "$creds_file" 2>/dev/null)
|
|
||||||
if [ -n "$token" ] && [ "$token" != "null" ]; then
|
|
||||||
echo "$token"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 4. GNOME Keyring via secret-tool
|
|
||||||
if command -v secret-tool >/dev/null 2>&1; then
|
|
||||||
local blob
|
|
||||||
blob=$(timeout 2 secret-tool lookup service "Claude Code-credentials" 2>/dev/null)
|
|
||||||
if [ -n "$blob" ]; then
|
|
||||||
token=$(echo "$blob" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
|
|
||||||
if [ -n "$token" ] && [ "$token" != "null" ]; then
|
|
||||||
echo "$token"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# ===== LINE 2 & 3: Usage limits with progress bars =====
|
|
||||||
# First, try to use rate_limits data provided directly by Claude Code in the JSON input.
|
|
||||||
# This is the most reliable source — no OAuth token or API call required.
|
|
||||||
builtin_five_hour_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
|
|
||||||
builtin_five_hour_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
|
|
||||||
builtin_seven_day_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
|
|
||||||
builtin_seven_day_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
|
|
||||||
|
|
||||||
use_builtin=false
|
|
||||||
if [ -n "$builtin_five_hour_pct" ] || [ -n "$builtin_seven_day_pct" ]; then
|
|
||||||
use_builtin=true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cache setup — shared across all Claude Code instances to avoid rate limits
|
|
||||||
claude_config_dir_hash=$(echo -n "$claude_config_dir" | shasum -a 256 2>/dev/null || echo -n "$claude_config_dir" | sha256sum 2>/dev/null)
|
|
||||||
claude_config_dir_hash=$(echo "$claude_config_dir_hash" | cut -c1-8)
|
|
||||||
cache_file="/tmp/claude/statusline-usage-cache-${claude_config_dir_hash}.json"
|
|
||||||
cache_max_age=60 # seconds between API calls
|
|
||||||
mkdir -p /tmp/claude
|
|
||||||
|
|
||||||
needs_refresh=true
|
|
||||||
usage_data=""
|
|
||||||
|
|
||||||
# Always load cache — used as primary source for API path, and as fallback when builtin reports zero
|
|
||||||
if [ -f "$cache_file" ] && [ -s "$cache_file" ]; then
|
|
||||||
cache_mtime=$(stat -c %Y "$cache_file" 2>/dev/null || stat -f %m "$cache_file" 2>/dev/null)
|
|
||||||
now=$(date +%s)
|
|
||||||
cache_age=$(( now - cache_mtime ))
|
|
||||||
if [ "$cache_age" -lt "$cache_max_age" ]; then
|
|
||||||
needs_refresh=false
|
|
||||||
fi
|
|
||||||
usage_data=$(cat "$cache_file" 2>/dev/null)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# When builtin values are all zero AND reset timestamps are missing, it likely indicates
|
|
||||||
# an API failure on Claude's side — fall through to cached data instead of displaying
|
|
||||||
# misleading 0%. Genuine zero responses (after a billing reset) still include valid
|
|
||||||
# resets_at timestamps, so we trust those.
|
|
||||||
effective_builtin=false
|
|
||||||
if $use_builtin; then
|
|
||||||
# Trust builtin if any percentage is non-zero
|
|
||||||
if { [ -n "$builtin_five_hour_pct" ] && [ "$(printf '%.0f' "$builtin_five_hour_pct" 2>/dev/null)" != "0" ]; } || \
|
|
||||||
{ [ -n "$builtin_seven_day_pct" ] && [ "$(printf '%.0f' "$builtin_seven_day_pct" 2>/dev/null)" != "0" ]; }; then
|
|
||||||
effective_builtin=true
|
|
||||||
fi
|
|
||||||
# Also trust if reset timestamps are present — genuine zero responses include valid reset times
|
|
||||||
if ! $effective_builtin; then
|
|
||||||
if { [ -n "$builtin_five_hour_reset" ] && [ "$builtin_five_hour_reset" != "null" ] && [ "$builtin_five_hour_reset" != "0" ]; } || \
|
|
||||||
{ [ -n "$builtin_seven_day_reset" ] && [ "$builtin_seven_day_reset" != "null" ] && [ "$builtin_seven_day_reset" != "0" ]; }; then
|
|
||||||
effective_builtin=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Refresh API cache when stale — runs regardless of builtin rate_limits because
|
|
||||||
# extra_usage is only exposed through the OAuth usage endpoint (not stdin JSON).
|
|
||||||
# Throttled to cache_max_age and stampede-locked via touch for shared panes.
|
|
||||||
if $needs_refresh; then
|
|
||||||
touch "$cache_file" # stampede lock: prevent parallel panes from fetching simultaneously
|
|
||||||
token=$(get_oauth_token)
|
|
||||||
if [ -n "$token" ] && [ "$token" != "null" ]; then
|
|
||||||
response=$(curl -s --max-time 10 \
|
|
||||||
-H "Accept: application/json" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "Authorization: Bearer $token" \
|
|
||||||
-H "anthropic-beta: oauth-2025-04-20" \
|
|
||||||
-H "User-Agent: claude-code/2.1.34" \
|
|
||||||
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
|
|
||||||
# Only cache valid usage responses (not error/rate-limit JSON)
|
|
||||||
if [ -n "$response" ] && echo "$response" | jq -e '.five_hour' >/dev/null 2>&1; then
|
|
||||||
usage_data="$response"
|
|
||||||
echo "$response" > "$cache_file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
# Remove the stampede sentinel if the fetch failed to produce valid JSON —
|
|
||||||
# otherwise an empty cache file would suppress retries for a full cache_max_age window.
|
|
||||||
[ -f "$cache_file" ] && [ ! -s "$cache_file" ] && rm -f "$cache_file"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cross-platform ISO to epoch conversion
|
|
||||||
# Converts ISO 8601 timestamp (e.g. "2025-06-15T12:30:00Z" or "2025-06-15T12:30:00.123+00:00") to epoch seconds.
|
|
||||||
# Properly handles UTC timestamps and converts to local time.
|
|
||||||
iso_to_epoch() {
|
|
||||||
local iso_str="$1"
|
|
||||||
|
|
||||||
# Try GNU date first (Linux) — handles ISO 8601 format automatically
|
|
||||||
local epoch
|
|
||||||
epoch=$(date -d "${iso_str}" +%s 2>/dev/null)
|
|
||||||
if [ -n "$epoch" ]; then
|
|
||||||
echo "$epoch"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# BSD date (macOS) - handle various ISO 8601 formats
|
|
||||||
local stripped="${iso_str%%.*}" # Remove fractional seconds (.123456)
|
|
||||||
stripped="${stripped%%Z}" # Remove trailing Z
|
|
||||||
stripped="${stripped%%+*}" # Remove timezone offset (+00:00)
|
|
||||||
stripped="${stripped%%-[0-9][0-9]:[0-9][0-9]}" # Remove negative timezone offset
|
|
||||||
|
|
||||||
# Check if timestamp is UTC (has Z or +00:00 or -00:00)
|
|
||||||
if [[ "$iso_str" == *"Z"* ]] || [[ "$iso_str" == *"+00:00"* ]] || [[ "$iso_str" == *"-00:00"* ]]; then
|
|
||||||
# For UTC timestamps, parse with timezone set to UTC
|
|
||||||
epoch=$(env TZ=UTC date -j -f "%Y-%m-%dT%H:%M:%S" "$stripped" +%s 2>/dev/null)
|
|
||||||
else
|
|
||||||
epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "$stripped" +%s 2>/dev/null)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$epoch" ]; then
|
|
||||||
echo "$epoch"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Format ISO reset time to compact local time
|
|
||||||
# Usage: format_reset_time <iso_string> <style: time|datetime|date>
|
|
||||||
format_reset_time() {
|
|
||||||
local iso_str="$1"
|
|
||||||
local style="$2"
|
|
||||||
{ [ -z "$iso_str" ] || [ "$iso_str" = "null" ]; } && return
|
|
||||||
|
|
||||||
# Parse ISO datetime and convert to local time (cross-platform)
|
|
||||||
local epoch
|
|
||||||
epoch=$(iso_to_epoch "$iso_str")
|
|
||||||
[ -z "$epoch" ] && return
|
|
||||||
|
|
||||||
# Format based on style
|
|
||||||
# Try GNU date first (Linux), then BSD date (macOS)
|
|
||||||
# Previous implementation piped BSD date through sed/tr, which always returned
|
|
||||||
# exit code 0 from the last pipe stage, preventing the GNU date fallback from
|
|
||||||
# ever executing on Linux.
|
|
||||||
local formatted=""
|
|
||||||
case "$style" in
|
|
||||||
time)
|
|
||||||
formatted=$(date -d "@$epoch" +"%H:%M" 2>/dev/null) || \
|
|
||||||
formatted=$(date -j -r "$epoch" +"%H:%M" 2>/dev/null)
|
|
||||||
;;
|
|
||||||
datetime)
|
|
||||||
formatted=$(date -d "@$epoch" +"%a %b %-d, %H:%M" 2>/dev/null) || \
|
|
||||||
formatted=$(date -j -r "$epoch" +"%a %b %-d, %H:%M" 2>/dev/null)
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
formatted=$(date -d "@$epoch" +"%b %-d" 2>/dev/null) || \
|
|
||||||
formatted=$(date -j -r "$epoch" +"%b %-d" 2>/dev/null)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
[ -n "$formatted" ] && echo "$formatted"
|
|
||||||
}
|
|
||||||
|
|
||||||
sep=" ${dim}|${reset} "
|
|
||||||
|
|
||||||
# Render extra_usage segment from API usage data (not available via stdin rate_limits).
|
|
||||||
# Appends to the global $out. No-op when data is missing or is_enabled is false.
|
|
||||||
render_extra_usage() {
|
|
||||||
local data="$1"
|
|
||||||
[ -z "$data" ] && return
|
|
||||||
local enabled
|
|
||||||
enabled=$(echo "$data" | jq -r '.extra_usage.is_enabled // false' 2>/dev/null)
|
|
||||||
[ "$enabled" != "true" ] && return
|
|
||||||
|
|
||||||
local pct used limit
|
|
||||||
pct=$(echo "$data" | jq -r '.extra_usage.utilization // 0' | awk '{printf "%.0f", $1}')
|
|
||||||
used=$(echo "$data" | jq -r '.extra_usage.used_credits // 0' | LC_NUMERIC=C awk '{printf "%.2f", $1/100}')
|
|
||||||
limit=$(echo "$data" | jq -r '.extra_usage.monthly_limit // 0' | LC_NUMERIC=C awk '{printf "%.2f", $1/100}')
|
|
||||||
|
|
||||||
if [ -n "$used" ] && [ -n "$limit" ] && [[ "$used" != *'$'* ]] && [[ "$limit" != *'$'* ]]; then
|
|
||||||
local color
|
|
||||||
color=$(usage_color "$pct")
|
|
||||||
out+="${sep}${white}extra${reset} ${color}\$${used}/\$${limit}${reset}"
|
|
||||||
else
|
|
||||||
out+="${sep}${white}extra${reset} ${green}enabled${reset}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
if $effective_builtin; then
|
|
||||||
# ---- Use rate_limits data provided directly by Claude Code in JSON input ----
|
|
||||||
# resets_at values are Unix epoch integers in this source
|
|
||||||
if [ -n "$builtin_five_hour_pct" ]; then
|
|
||||||
five_hour_pct=$(printf "%.0f" "$builtin_five_hour_pct")
|
|
||||||
five_hour_color=$(usage_color "$five_hour_pct")
|
|
||||||
out+="${sep}${white}5h${reset} ${five_hour_color}${five_hour_pct}%${reset}"
|
|
||||||
if [ -n "$builtin_five_hour_reset" ] && [ "$builtin_five_hour_reset" != "null" ]; then
|
|
||||||
five_hour_reset=$(date -j -r "$builtin_five_hour_reset" +"%H:%M" 2>/dev/null || date -d "@$builtin_five_hour_reset" +"%H:%M" 2>/dev/null)
|
|
||||||
[ -n "$five_hour_reset" ] && out+=" ${dim}@${five_hour_reset}${reset}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$builtin_seven_day_pct" ]; then
|
|
||||||
seven_day_pct=$(printf "%.0f" "$builtin_seven_day_pct")
|
|
||||||
seven_day_color=$(usage_color "$seven_day_pct")
|
|
||||||
out+="${sep}${white}7d${reset} ${seven_day_color}${seven_day_pct}%${reset}"
|
|
||||||
if [ -n "$builtin_seven_day_reset" ] && [ "$builtin_seven_day_reset" != "null" ]; then
|
|
||||||
seven_day_reset=$(date -j -r "$builtin_seven_day_reset" +"%a %b %-d, %H:%M" 2>/dev/null || date -d "@$builtin_seven_day_reset" +"%a %b %-d, %H:%M" 2>/dev/null)
|
|
||||||
[ -n "$seven_day_reset" ] && out+=" ${dim}@${seven_day_reset}${reset}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Render extra_usage from API cache (stdin rate_limits doesn't expose it)
|
|
||||||
render_extra_usage "$usage_data"
|
|
||||||
|
|
||||||
# Cache builtin values so they're available as fallback when API is unavailable.
|
|
||||||
# Convert epoch resets_at to ISO 8601 for compatibility with the API-format cache parser.
|
|
||||||
# Preserve extra_usage from prior API response so we don't clobber it.
|
|
||||||
_fh_reset_json="null"
|
|
||||||
if [ -n "$builtin_five_hour_reset" ] && [ "$builtin_five_hour_reset" != "null" ] && [ "$builtin_five_hour_reset" != "0" ]; then
|
|
||||||
_fh_iso=$(date -u -r "$builtin_five_hour_reset" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || \
|
|
||||||
date -u -d "@$builtin_five_hour_reset" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null)
|
|
||||||
[ -n "$_fh_iso" ] && _fh_reset_json="\"$_fh_iso\""
|
|
||||||
fi
|
|
||||||
_sd_reset_json="null"
|
|
||||||
if [ -n "$builtin_seven_day_reset" ] && [ "$builtin_seven_day_reset" != "null" ] && [ "$builtin_seven_day_reset" != "0" ]; then
|
|
||||||
_sd_iso=$(date -u -r "$builtin_seven_day_reset" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || \
|
|
||||||
date -u -d "@$builtin_seven_day_reset" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null)
|
|
||||||
[ -n "$_sd_iso" ] && _sd_reset_json="\"$_sd_iso\""
|
|
||||||
fi
|
|
||||||
_extra_json=$(echo "$usage_data" | jq -c '.extra_usage // null' 2>/dev/null)
|
|
||||||
[ -z "$_extra_json" ] && _extra_json="null"
|
|
||||||
printf '{"five_hour":{"utilization":%s,"resets_at":%s},"seven_day":{"utilization":%s,"resets_at":%s},"extra_usage":%s}' \
|
|
||||||
"${builtin_five_hour_pct:-0}" "$_fh_reset_json" \
|
|
||||||
"${builtin_seven_day_pct:-0}" "$_sd_reset_json" \
|
|
||||||
"$_extra_json" > "$cache_file" 2>/dev/null
|
|
||||||
elif [ -n "$usage_data" ] && echo "$usage_data" | jq -e '.five_hour' >/dev/null 2>&1; then
|
|
||||||
# ---- Fall back: API-fetched usage data ----
|
|
||||||
# ---- 5-hour (current) ----
|
|
||||||
five_hour_pct=$(echo "$usage_data" | jq -r '.five_hour.utilization // 0' | awk '{printf "%.0f", $1}')
|
|
||||||
five_hour_reset_iso=$(echo "$usage_data" | jq -r '.five_hour.resets_at // empty')
|
|
||||||
five_hour_reset=$(format_reset_time "$five_hour_reset_iso" "time")
|
|
||||||
five_hour_color=$(usage_color "$five_hour_pct")
|
|
||||||
|
|
||||||
out+="${sep}${white}5h${reset} ${five_hour_color}${five_hour_pct}%${reset}"
|
|
||||||
[ -n "$five_hour_reset" ] && out+=" ${dim}@${five_hour_reset}${reset}"
|
|
||||||
|
|
||||||
# ---- 7-day (weekly) ----
|
|
||||||
seven_day_pct=$(echo "$usage_data" | jq -r '.seven_day.utilization // 0' | awk '{printf "%.0f", $1}')
|
|
||||||
seven_day_reset_iso=$(echo "$usage_data" | jq -r '.seven_day.resets_at // empty')
|
|
||||||
seven_day_reset=$(format_reset_time "$seven_day_reset_iso" "datetime")
|
|
||||||
seven_day_color=$(usage_color "$seven_day_pct")
|
|
||||||
|
|
||||||
out+="${sep}${white}7d${reset} ${seven_day_color}${seven_day_pct}%${reset}"
|
|
||||||
[ -n "$seven_day_reset" ] && out+=" ${dim}@${seven_day_reset}${reset}"
|
|
||||||
|
|
||||||
render_extra_usage "$usage_data"
|
|
||||||
else
|
|
||||||
# No valid usage data — show placeholders
|
|
||||||
out+="${sep}${white}5h${reset} ${dim}-${reset}"
|
|
||||||
out+="${sep}${white}7d${reset} ${dim}-${reset}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ===== Update check (cached, 24h TTL) =====
|
|
||||||
# Set STATUSLINE_CHECK_UPDATES=false to disable the update check (no network calls).
|
|
||||||
update_line=""
|
|
||||||
if [ "${STATUSLINE_CHECK_UPDATES:-true}" != "false" ]; then
|
|
||||||
version_cache_file="/tmp/claude/statusline-version-cache.json"
|
|
||||||
version_cache_max_age=86400 # 24 hours
|
|
||||||
|
|
||||||
version_needs_refresh=true
|
|
||||||
version_data=""
|
|
||||||
|
|
||||||
if [ -f "$version_cache_file" ]; then
|
|
||||||
vc_mtime=$(stat -c %Y "$version_cache_file" 2>/dev/null || stat -f %m "$version_cache_file" 2>/dev/null)
|
|
||||||
vc_now=$(date +%s)
|
|
||||||
vc_age=$(( vc_now - vc_mtime ))
|
|
||||||
if [ "$vc_age" -lt "$version_cache_max_age" ]; then
|
|
||||||
version_needs_refresh=false
|
|
||||||
fi
|
|
||||||
version_data=$(cat "$version_cache_file" 2>/dev/null)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $version_needs_refresh; then
|
|
||||||
touch "$version_cache_file" 2>/dev/null
|
|
||||||
vc_response=$(curl -s --max-time 5 \
|
|
||||||
-H "Accept: application/vnd.github+json" \
|
|
||||||
"https://api.github.com/repos/daniel3303/ClaudeCodeStatusLine/releases/latest" 2>/dev/null)
|
|
||||||
if [ -n "$vc_response" ] && echo "$vc_response" | jq -e '.tag_name' >/dev/null 2>&1; then
|
|
||||||
version_data="$vc_response"
|
|
||||||
echo "$vc_response" > "$version_cache_file"
|
|
||||||
elif [ ! -s "$version_cache_file" ]; then
|
|
||||||
rm -f "$version_cache_file" 2>/dev/null
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$version_data" ]; then
|
|
||||||
latest_tag=$(echo "$version_data" | jq -r '.tag_name // empty')
|
|
||||||
if [ -n "$latest_tag" ] && version_gt "$latest_tag" "$VERSION"; then
|
|
||||||
update_line="\n${dim}Update available: ${latest_tag} → Tell Claude: \"Find my installed status bar and update it\"${reset}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Append CLI version as last segment
|
|
||||||
if [ -n "$cli_version" ]; then
|
|
||||||
out+=" ${dim}|${reset} ${orange}v${cli_version}${reset}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Output
|
|
||||||
printf "%b" "$out$update_line"
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{ lib, pkgs', pkgs, config, ... }:
|
{ lib, pkgs', pkgs, config, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) genAttrs mkIf mkMerge mkForce mapAttrs mkOptionDefault mkDefault;
|
inherit (lib) genAttrs mkIf mkMerge mkForce mapAttrs mkOptionDefault;
|
||||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||||
inherit (lib.my.c) pubDomain;
|
inherit (lib.my.c) pubDomain;
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ in
|
|||||||
jp2a
|
jp2a
|
||||||
terminaltexteffects
|
terminaltexteffects
|
||||||
screenfetch
|
screenfetch
|
||||||
fastfetch
|
neofetch
|
||||||
cmatrix
|
cmatrix
|
||||||
doomsaver
|
doomsaver
|
||||||
|
|
||||||
@@ -122,6 +122,12 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
termite = {
|
||||||
|
enable = true;
|
||||||
|
font = "${font.name} ${toString font.size}";
|
||||||
|
backgroundColor = "rgba(0, 0, 0, 0.8)";
|
||||||
|
};
|
||||||
|
|
||||||
foot = {
|
foot = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
@@ -155,19 +161,6 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
claude-code = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
model = "opus";
|
|
||||||
theme = "auto";
|
|
||||||
statusLine = {
|
|
||||||
type = "command";
|
|
||||||
command = ./claude-statusline.sh;
|
|
||||||
padding = 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,10 +387,6 @@ in
|
|||||||
name = "Numix";
|
name = "Numix";
|
||||||
package = pkgs.numix-gtk-theme;
|
package = pkgs.numix-gtk-theme;
|
||||||
};
|
};
|
||||||
gtk4.theme = {
|
|
||||||
name = "Numix";
|
|
||||||
package = pkgs.numix-gtk-theme;
|
|
||||||
};
|
|
||||||
iconTheme = {
|
iconTheme = {
|
||||||
name = "Numix";
|
name = "Numix";
|
||||||
package = pkgs.numix-icon-theme;
|
package = pkgs.numix-icon-theme;
|
||||||
@@ -426,30 +415,6 @@ in
|
|||||||
device_type = "computer";
|
device_type = "computer";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
easyeffects = {
|
|
||||||
enable = mkDefault false;
|
|
||||||
preset = mkDefault "moar-bass";
|
|
||||||
extraPresets = {
|
|
||||||
moar-bass = {
|
|
||||||
output = {
|
|
||||||
"bass_enhancer#0" = {
|
|
||||||
amount = 3;
|
|
||||||
blend = 0;
|
|
||||||
bypass = false;
|
|
||||||
floor = 20;
|
|
||||||
floor-active = false;
|
|
||||||
harmonics = 8.5;
|
|
||||||
input-gain = 0;
|
|
||||||
output-gain = 0;
|
|
||||||
scope = 100;
|
|
||||||
};
|
|
||||||
blocklist = [ ];
|
|
||||||
plugins_order = [ "bass_enhancer#0" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
programs = {
|
programs = {
|
||||||
@@ -529,7 +494,6 @@ in
|
|||||||
userDirs = {
|
userDirs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
createDirectories = true;
|
createDirectories = true;
|
||||||
setSessionVariables = true;
|
|
||||||
desktop = "$HOME/desktop";
|
desktop = "$HOME/desktop";
|
||||||
documents = "$HOME/documents";
|
documents = "$HOME/documents";
|
||||||
download = "$HOME/downloads";
|
download = "$HOME/downloads";
|
||||||
|
|||||||
+2
-29
@@ -29,8 +29,8 @@ rec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
kernel = {
|
kernel = {
|
||||||
lts = pkgs: pkgs.linuxKernel.packages.linux_6_18;
|
lts = pkgs: pkgs.linuxKernel.packages.linux_6_12;
|
||||||
latest = pkgs: pkgs.linuxKernel.packages.linux_7_0;
|
latest = pkgs: pkgs.linuxKernel.packages.linux_6_17;
|
||||||
};
|
};
|
||||||
|
|
||||||
nginx = rec {
|
nginx = rec {
|
||||||
@@ -148,9 +148,6 @@ rec {
|
|||||||
hillcrest = {
|
hillcrest = {
|
||||||
v4 = subnet 6 0 p2pTunnels.v4;
|
v4 = subnet 6 0 p2pTunnels.v4;
|
||||||
};
|
};
|
||||||
john-valorant = {
|
|
||||||
v4 = subnet 6 1 p2pTunnels.v4;
|
|
||||||
};
|
|
||||||
|
|
||||||
cust = {
|
cust = {
|
||||||
v4 = subnet 8 100 all.v4; # single ip for routing only
|
v4 = subnet 8 100 all.v4; # single ip for routing only
|
||||||
@@ -220,10 +217,6 @@ rec {
|
|||||||
port = 25568;
|
port = 25568;
|
||||||
dst = aa.kinkcraft-oci.internal.ipv4.address;
|
dst = aa.kinkcraft-oci.internal.ipv4.address;
|
||||||
}
|
}
|
||||||
{
|
|
||||||
port = 25569;
|
|
||||||
dst = aa.graeme-oci.internal.ipv4.address;
|
|
||||||
}
|
|
||||||
|
|
||||||
# RCON... unsafe?
|
# RCON... unsafe?
|
||||||
# {
|
# {
|
||||||
@@ -231,11 +224,6 @@ rec {
|
|||||||
# dst = aa.simpcraft-oci.internal.ipv4.address;
|
# dst = aa.simpcraft-oci.internal.ipv4.address;
|
||||||
# }
|
# }
|
||||||
|
|
||||||
{
|
|
||||||
port = 7777;
|
|
||||||
dst = aa.gam.internal.ipv4.address;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
port = 2456;
|
port = 2456;
|
||||||
dst = aa.valheim-oci.internal.ipv4.address;
|
dst = aa.valheim-oci.internal.ipv4.address;
|
||||||
@@ -268,11 +256,6 @@ rec {
|
|||||||
dst = aa.kinkcraft-oci.internal.ipv4.address;
|
dst = aa.kinkcraft-oci.internal.ipv4.address;
|
||||||
proto = "udp";
|
proto = "udp";
|
||||||
}
|
}
|
||||||
{
|
|
||||||
port = 25569;
|
|
||||||
dst = aa.graeme-oci.internal.ipv4.address;
|
|
||||||
proto = "udp";
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
port = 15636;
|
port = 15636;
|
||||||
@@ -290,12 +273,6 @@ rec {
|
|||||||
dst = aa.qclk.internal.ipv4.address;
|
dst = aa.qclk.internal.ipv4.address;
|
||||||
proto = "udp";
|
proto = "udp";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
port = 7777;
|
|
||||||
dst = aa.gam.internal.ipv4.address;
|
|
||||||
proto = "udp";
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
fstrimConfig = {
|
fstrimConfig = {
|
||||||
@@ -449,10 +426,6 @@ rec {
|
|||||||
vpn.port = 51822;
|
vpn.port = 51822;
|
||||||
};
|
};
|
||||||
|
|
||||||
john-valorant = {
|
|
||||||
vpn.port = 51823;
|
|
||||||
};
|
|
||||||
|
|
||||||
sshKeyFiles = {
|
sshKeyFiles = {
|
||||||
me = ../.keys/me.pub;
|
me = ../.keys/me.pub;
|
||||||
deploy = ../.keys/deploy.pub;
|
deploy = ../.keys/deploy.pub;
|
||||||
|
|||||||
+2
-2
@@ -248,8 +248,8 @@ rec {
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
trivial = prev.trivial // {
|
trivial = prev.trivial // {
|
||||||
release = "26.06:u-${prev.trivial.release}";
|
release = "25.11:u-${prev.trivial.release}";
|
||||||
codeName = "Irritating";
|
codeName = "Hooray";
|
||||||
revisionWithDefault = default: self.rev or default;
|
revisionWithDefault = default: self.rev or default;
|
||||||
versionSuffix = ".${date}.${revCode self}:u-${revCode pkgsFlake}";
|
versionSuffix = ".${date}.${revCode self}:u-${revCode pkgsFlake}";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ in
|
|||||||
config = {
|
config = {
|
||||||
my = {
|
my = {
|
||||||
secrets.files = {
|
secrets.files = {
|
||||||
|
"dhparams.pem" = {
|
||||||
|
owner = "acme";
|
||||||
|
group = "acme";
|
||||||
|
mode = "440";
|
||||||
|
};
|
||||||
"britway/cloudflare-credentials.conf" = {
|
"britway/cloudflare-credentials.conf" = {
|
||||||
owner = "acme";
|
owner = "acme";
|
||||||
group = "acme";
|
group = "acme";
|
||||||
@@ -40,7 +45,7 @@ in
|
|||||||
"*.${pubDomain}"
|
"*.${pubDomain}"
|
||||||
];
|
];
|
||||||
dnsProvider = "cloudflare";
|
dnsProvider = "cloudflare";
|
||||||
environmentFile = config.age.secrets."britway/cloudflare-credentials.conf".path;
|
credentialsFile = config.age.secrets."britway/cloudflare-credentials.conf".path;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -53,6 +58,7 @@ in
|
|||||||
logError = "stderr info";
|
logError = "stderr info";
|
||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
serverTokens = true;
|
serverTokens = true;
|
||||||
|
sslDhparam = config.age.secrets."dhparams.pem".path;
|
||||||
|
|
||||||
# Based on recommended*Settings, but probably better to be explicit about these
|
# Based on recommended*Settings, but probably better to be explicit about these
|
||||||
appendHttpConfig = ''
|
appendHttpConfig = ''
|
||||||
|
|||||||
@@ -291,23 +291,6 @@ in
|
|||||||
neighbor 2001:7f8:10f::3:3e9b:134 as 212635;
|
neighbor 2001:7f8:10f::3:3e9b:134 as 212635;
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol bgp peer4_nlix_meta1 from peer_bgp4 {
|
|
||||||
description "Meta 1 (on NL-ix, IPv4)";
|
|
||||||
neighbor 193.239.116.147 as 32934;
|
|
||||||
}
|
|
||||||
protocol bgp peer4_nlix_meta2 from peer_bgp4 {
|
|
||||||
description "Meta 2 (on NL-ix, IPv4)";
|
|
||||||
neighbor 193.239.116.148 as 32934;
|
|
||||||
}
|
|
||||||
protocol bgp peer6_nlix_meta1 from peer_bgp6 {
|
|
||||||
description "Meta 1 (on NL-ix, IPv6)";
|
|
||||||
neighbor 2001:7f8:13::a503:2934:1 as 32934;
|
|
||||||
}
|
|
||||||
protocol bgp peer6_nlix_meta2 from peer_bgp6 {
|
|
||||||
description "Meta 2 (on NL-ix, IPv6)";
|
|
||||||
neighbor 2001:7f8:13::a503:2934:2 as 32934;
|
|
||||||
}
|
|
||||||
|
|
||||||
protocol bgp peer4_frysix_meta1 from peer_bgp4 {
|
protocol bgp peer4_frysix_meta1 from peer_bgp4 {
|
||||||
description "Meta 1 (on Frys-IX, IPv4)";
|
description "Meta 1 (on Frys-IX, IPv4)";
|
||||||
neighbor 185.1.160.225 as 32934;
|
neighbor 185.1.160.225 as 32934;
|
||||||
|
|||||||
@@ -104,9 +104,11 @@ in
|
|||||||
lvm = {
|
lvm = {
|
||||||
dmeventd.enable = true;
|
dmeventd.enable = true;
|
||||||
};
|
};
|
||||||
resolved.settings.Resolve = {
|
resolved = {
|
||||||
LLMNR = false;
|
llmnr = "false";
|
||||||
MulticastDNS = false;
|
extraConfig = ''
|
||||||
|
MulticastDNS=false
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
netdata.enable = true;
|
netdata.enable = true;
|
||||||
|
|
||||||
@@ -188,25 +190,6 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
|
||||||
"30-john-valorant" = {
|
|
||||||
netdevConfig = {
|
|
||||||
Name = "john-valorant";
|
|
||||||
Kind = "wireguard";
|
|
||||||
};
|
|
||||||
wireguardConfig = {
|
|
||||||
PrivateKeyFile = config.age.secrets."estuary/john-valorant-wg.key".path;
|
|
||||||
ListenPort = lib.my.c.john-valorant.vpn.port;
|
|
||||||
};
|
|
||||||
wireguardPeers = [
|
|
||||||
{
|
|
||||||
PublicKey = "xyqKF0yOAv1bObN1paL2vATFh77pdFfvN+JmuAxaTCk=";
|
|
||||||
AllowedIPs = [ (net.cidr.host 2 prefixes.john-valorant.v4) ];
|
|
||||||
PersistentKeepalive = 25;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
|
|
||||||
links = {
|
links = {
|
||||||
@@ -384,7 +367,7 @@ in
|
|||||||
};
|
};
|
||||||
"95-hillcrest" = {
|
"95-hillcrest" = {
|
||||||
matchConfig.Name = "hillcrest";
|
matchConfig.Name = "hillcrest";
|
||||||
address = [ "${net.cidr.host 1 prefixes.hillcrest.v4}/32" ];
|
address = [ (net.cidr.host 1 prefixes.hillcrest.v4) ];
|
||||||
routes = [
|
routes = [
|
||||||
{
|
{
|
||||||
Destination = net.cidr.host 2 prefixes.hillcrest.v4;
|
Destination = net.cidr.host 2 prefixes.hillcrest.v4;
|
||||||
@@ -392,16 +375,6 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
"95-john-valorant" = {
|
|
||||||
matchConfig.Name = "john-valorant";
|
|
||||||
address = [ "${net.cidr.host 1 prefixes.john-valorant.v4}/32" ];
|
|
||||||
routes = [
|
|
||||||
{
|
|
||||||
Destination = net.cidr.host 2 prefixes.john-valorant.v4;
|
|
||||||
Scope = "link";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
} ];
|
} ];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -415,9 +388,6 @@ in
|
|||||||
"estuary/hillcrest-wg.key" = {
|
"estuary/hillcrest-wg.key" = {
|
||||||
owner = "systemd-network";
|
owner = "systemd-network";
|
||||||
};
|
};
|
||||||
"estuary/john-valorant-wg.key" = {
|
|
||||||
owner = "systemd-network";
|
|
||||||
};
|
|
||||||
"l2mesh/as211024.key" = {};
|
"l2mesh/as211024.key" = {};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -429,13 +399,7 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
firewall = {
|
firewall = {
|
||||||
udp.allowed = [
|
udp.allowed = [ 5353 lib.my.c.kelder.vpn.port lib.my.c.hillcrest.vpn.port ];
|
||||||
5353
|
|
||||||
|
|
||||||
lib.my.c.kelder.vpn.port
|
|
||||||
lib.my.c.hillcrest.vpn.port
|
|
||||||
lib.my.c.john-valorant.vpn.port
|
|
||||||
];
|
|
||||||
tcp.allowed = [ 5353 "bgp" ];
|
tcp.allowed = [ 5353 "bgp" ];
|
||||||
nat = {
|
nat = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -471,8 +435,6 @@ in
|
|||||||
ip6 daddr ${aa.simpcraft-staging-oci.internal.ipv6.address} tcp dport 25565 accept
|
ip6 daddr ${aa.simpcraft-staging-oci.internal.ipv6.address} tcp dport 25565 accept
|
||||||
ip6 daddr ${aa.kevcraft-oci.internal.ipv6.address} tcp dport 25567 accept
|
ip6 daddr ${aa.kevcraft-oci.internal.ipv6.address} tcp dport 25567 accept
|
||||||
ip6 daddr ${aa.kinkcraft-oci.internal.ipv6.address} tcp dport 25568 accept
|
ip6 daddr ${aa.kinkcraft-oci.internal.ipv6.address} tcp dport 25568 accept
|
||||||
ip6 daddr ${aa.graeme-oci.internal.ipv6.address} tcp dport 25569 accept
|
|
||||||
ip6 daddr ${aa.gam.internal.ipv6.address} tcp dport 7777 accept
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chain routing-udp {
|
chain routing-udp {
|
||||||
@@ -482,8 +444,6 @@ in
|
|||||||
ip6 daddr ${aa.enshrouded-oci.internal.ipv6.address} udp dport { 15636-15637 } accept
|
ip6 daddr ${aa.enshrouded-oci.internal.ipv6.address} udp dport { 15636-15637 } accept
|
||||||
ip6 daddr ${aa.kevcraft-oci.internal.ipv6.address} udp dport 25567 accept
|
ip6 daddr ${aa.kevcraft-oci.internal.ipv6.address} udp dport 25567 accept
|
||||||
ip6 daddr ${aa.kinkcraft-oci.internal.ipv6.address} udp dport 25568 accept
|
ip6 daddr ${aa.kinkcraft-oci.internal.ipv6.address} udp dport 25568 accept
|
||||||
ip6 daddr ${aa.graeme-oci.internal.ipv6.address} udp dport 25569 accept
|
|
||||||
ip6 daddr ${aa.gam.internal.ipv6.address} udp dport 7777 accept
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
chain filter-routing {
|
chain filter-routing {
|
||||||
@@ -504,7 +464,7 @@ in
|
|||||||
iifname { wan, as211024, $ixps } oifname base jump filter-routing
|
iifname { wan, as211024, $ixps } oifname base jump filter-routing
|
||||||
oifname $ixps jump ixp
|
oifname $ixps jump ixp
|
||||||
iifname base oifname { base, wan, $ixps } accept
|
iifname base oifname { base, wan, $ixps } accept
|
||||||
oifname { as211024, kelder, hillcrest, john-valorant } accept
|
oifname { as211024, kelder, hillcrest } accept
|
||||||
}
|
}
|
||||||
chain output {
|
chain output {
|
||||||
oifname ifog ether type != vlan reject
|
oifname ifog ether type != vlan reject
|
||||||
@@ -517,7 +477,6 @@ in
|
|||||||
}
|
}
|
||||||
chain postrouting {
|
chain postrouting {
|
||||||
oifname hillcrest snat ip to ${net.cidr.host 1 prefixes.hillcrest.v4}
|
oifname hillcrest snat ip to ${net.cidr.host 1 prefixes.hillcrest.v4}
|
||||||
oifname john-valorant snat ip to ${net.cidr.host 1 prefixes.john-valorant.v4}
|
|
||||||
ip saddr ${prefixes.all.v4} oifname != as211024 snat to ${assignments.internal.ipv4.address}
|
ip saddr ${prefixes.all.v4} oifname != as211024 snat to ${assignments.internal.ipv4.address}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
pdns-recursor = {
|
pdns-recursor = {
|
||||||
settings = {
|
yaml-settings = {
|
||||||
incoming = {
|
incoming = {
|
||||||
listen = [
|
listen = [
|
||||||
"127.0.0.1" "::1"
|
"127.0.0.1" "::1"
|
||||||
@@ -168,10 +168,6 @@ in
|
|||||||
kevcraft IN AAAA ${allAssignments.kevcraft-oci.internal.ipv6.address}
|
kevcraft IN AAAA ${allAssignments.kevcraft-oci.internal.ipv6.address}
|
||||||
kinkcraft IN A ${assignments.internal.ipv4.address}
|
kinkcraft IN A ${assignments.internal.ipv4.address}
|
||||||
kinkcraft IN AAAA ${allAssignments.kinkcraft-oci.internal.ipv6.address}
|
kinkcraft IN AAAA ${allAssignments.kinkcraft-oci.internal.ipv6.address}
|
||||||
graeme IN A ${assignments.internal.ipv4.address}
|
|
||||||
graeme IN AAAA ${allAssignments.graeme-oci.internal.ipv6.address}
|
|
||||||
terraria IN A ${assignments.internal.ipv4.address}
|
|
||||||
terraria IN AAAA ${allAssignments.gam.internal.ipv6.address}
|
|
||||||
|
|
||||||
mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
|
mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
|
||||||
mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}
|
mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}
|
||||||
@@ -185,9 +181,6 @@ in
|
|||||||
jam-fwd IN A ${allAssignments.shill.internal.ipv4.address}
|
jam-fwd IN A ${allAssignments.shill.internal.ipv4.address}
|
||||||
jam-cust IN AAAA ${net.cidr.host 1 prefixes.jam.v6}
|
jam-cust IN AAAA ${net.cidr.host 1 prefixes.jam.v6}
|
||||||
|
|
||||||
hillcrest-tun IN A ${net.cidr.host 2 prefixes.hillcrest.v4}
|
|
||||||
john-valorant-tun IN A ${net.cidr.host 2 prefixes.john-valorant.v4}
|
|
||||||
|
|
||||||
$TTL 3
|
$TTL 3
|
||||||
_acme-challenge IN LUA TXT @@FILE@@
|
_acme-challenge IN LUA TXT @@FILE@@
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ in
|
|||||||
"*.${pubDomain}"
|
"*.${pubDomain}"
|
||||||
];
|
];
|
||||||
dnsProvider = "cloudflare";
|
dnsProvider = "cloudflare";
|
||||||
environmentFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
|
credentialsFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -111,6 +111,7 @@ in
|
|||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
clientMaxBodySize = "0";
|
clientMaxBodySize = "0";
|
||||||
serverTokens = true;
|
serverTokens = true;
|
||||||
|
sslDhparam = config.age.secrets."dhparams.pem".path;
|
||||||
|
|
||||||
# Based on recommended*Settings, but probably better to be explicit about these
|
# Based on recommended*Settings, but probably better to be explicit about these
|
||||||
appendHttpConfig = ''
|
appendHttpConfig = ''
|
||||||
@@ -181,6 +182,11 @@ in
|
|||||||
secrets = {
|
secrets = {
|
||||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
|
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
|
||||||
files = {
|
files = {
|
||||||
|
"dhparams.pem" = {
|
||||||
|
owner = "acme";
|
||||||
|
group = "acme";
|
||||||
|
mode = "440";
|
||||||
|
};
|
||||||
"middleman/cloudflare-credentials.conf" = {
|
"middleman/cloudflare-credentials.conf" = {
|
||||||
owner = "acme";
|
owner = "acme";
|
||||||
group = "acme";
|
group = "acme";
|
||||||
|
|||||||
@@ -1,7 +1,19 @@
|
|||||||
{ lib, pkgs, config, ... }:
|
{ lib, pkgs, config, ... }:
|
||||||
let
|
let
|
||||||
|
inherit (builtins) toJSON;
|
||||||
inherit (lib) mkForce;
|
inherit (lib) mkForce;
|
||||||
inherit (lib.my.c) pubDomain;
|
inherit (lib.my.c) pubDomain;
|
||||||
|
|
||||||
|
cfgFile = pkgs.writeText "gitea-actions-runner.yaml" (toJSON {
|
||||||
|
container = {
|
||||||
|
network = "podman";
|
||||||
|
privileged = true;
|
||||||
|
};
|
||||||
|
cache = {
|
||||||
|
enabled = true;
|
||||||
|
dir = "/var/cache/gitea-runner";
|
||||||
|
};
|
||||||
|
});
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = {
|
config = {
|
||||||
@@ -18,8 +30,8 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
name = "main-docker";
|
name = "main-docker";
|
||||||
labels = [
|
labels = [
|
||||||
"debian-node-trixie:docker://node:24-trixie"
|
"debian-node-bullseye:docker://node:18-bullseye"
|
||||||
"ubuntu-26.04:docker://git.nul.ie/dev/actions-ubuntu:26.04"
|
"ubuntu-22.04:docker://git.nul.ie/dev/actions-ubuntu:22.04"
|
||||||
];
|
];
|
||||||
url = "https://git.${pubDomain}";
|
url = "https://git.${pubDomain}";
|
||||||
tokenFile = config.age.secrets."gitea/actions-runner.env".path;
|
tokenFile = config.age.secrets."gitea/actions-runner.env".path;
|
||||||
@@ -27,14 +39,6 @@ in
|
|||||||
runner = {
|
runner = {
|
||||||
timeout = "8h";
|
timeout = "8h";
|
||||||
};
|
};
|
||||||
container = {
|
|
||||||
network = "podman";
|
|
||||||
privileged = true;
|
|
||||||
};
|
|
||||||
cache = {
|
|
||||||
enabled = true;
|
|
||||||
dir = "/var/cache/gitea-runner";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -62,6 +66,7 @@ in
|
|||||||
DynamicUser = mkForce false;
|
DynamicUser = mkForce false;
|
||||||
User = "gitea-runner";
|
User = "gitea-runner";
|
||||||
Group = "gitea-runner";
|
Group = "gitea-runner";
|
||||||
|
ExecStart = mkForce "${config.services.gitea-actions-runner.package}/bin/act_runner -c ${cfgFile} daemon";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ in
|
|||||||
"/var/lib/machines/jam" = {
|
"/var/lib/machines/jam" = {
|
||||||
device = "/mnt/jam";
|
device = "/mnt/jam";
|
||||||
options = [ "bind" ];
|
options = [ "bind" ];
|
||||||
fsType = "none";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -198,17 +198,16 @@ in
|
|||||||
|
|
||||||
mautrix-whatsapp = {
|
mautrix-whatsapp = {
|
||||||
enable = true;
|
enable = true;
|
||||||
# package = pkgs.mautrix-whatsapp.overrideAttrs (o: rec {
|
package = pkgs.mautrix-whatsapp.overrideAttrs (o: {
|
||||||
# version = "26.05";
|
# TODO: Remove when upgrading nixpkgs
|
||||||
# tag = "v0.2605.0";
|
src = pkgs.fetchFromGitHub {
|
||||||
# src = pkgs.fetchFromGitHub {
|
owner = "mautrix";
|
||||||
# owner = "mautrix";
|
repo = "whatsapp";
|
||||||
# repo = "whatsapp";
|
tag = "v0.2511.0";
|
||||||
# inherit tag;
|
hash = "sha256-0Jpod9/mZ9eGFvPxki6Yz0KL1XQ4HTtZ7Zv7WvamuC0=";
|
||||||
# hash = "sha256-WlVfGQoP9e/wl98hUJei8O2JMcOKijoEY8XuU/z69Qk=";
|
};
|
||||||
# };
|
vendorHash = "sha256-n25j2uM3e5/5PYs2jwH+iclaU/p/MhctCAhPninz2HI=";
|
||||||
# vendorHash = "sha256-Hi/dZHJHoTTCnxLXgbkcYzuzis4fl5kxb5wMd9fKTY8=";
|
});
|
||||||
# });
|
|
||||||
environmentFile = config.age.secrets."chatterbox/mautrix-whatsapp.env".path;
|
environmentFile = config.age.secrets."chatterbox/mautrix-whatsapp.env".path;
|
||||||
settings = {
|
settings = {
|
||||||
database = {
|
database = {
|
||||||
@@ -253,17 +252,16 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# mautrix-meta.package = pkgs.mautrix-meta.overrideAttrs (o: rec {
|
# TODO: Remove when upgrading nixpkgs
|
||||||
# version = "26.05.1";
|
mautrix-meta.package = pkgs.mautrix-meta.overrideAttrs (o: {
|
||||||
# tag = "v0.2605.1";
|
src = pkgs.fetchFromGitHub {
|
||||||
# src = pkgs.fetchFromGitHub {
|
owner = "mautrix";
|
||||||
# owner = "mautrix";
|
repo = "meta";
|
||||||
# repo = "meta";
|
rev = "v0.2511.0";
|
||||||
# inherit tag;
|
hash = "sha256-Ke5b1Q1QIB2u5fbDmhvwe/HaZX1oycNSIor/9gdmdWA=";
|
||||||
# hash = "sha256-zpolDtwGulDTiojJPnkj9O0D5b4rgPYQX6A28rvuvM0=";
|
};
|
||||||
# };
|
vendorHash = "sha256-vbXV9xa0Q+Sml21QQZ3YUmPzXgrIZRJx0tQx0O4JcHs=";
|
||||||
# vendorHash = "sha256-+i45bXBhlXPXX24VMS9IJLLX+i4VPnqy5RAH4j88sTA=";
|
});
|
||||||
# });
|
|
||||||
mautrix-meta.instances = {
|
mautrix-meta.instances = {
|
||||||
messenger = {
|
messenger = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -9,6 +9,5 @@
|
|||||||
./toot.nix
|
./toot.nix
|
||||||
./waffletail.nix
|
./waffletail.nix
|
||||||
./qclk
|
./qclk
|
||||||
./gam.nix
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
{ lib, ... }:
|
|
||||||
let
|
|
||||||
inherit (lib.my) net;
|
|
||||||
inherit (lib.my.c) pubDomain;
|
|
||||||
inherit (lib.my.c.colony) domain prefixes;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
nixos.systems.gam = { config, ... }: {
|
|
||||||
system = "x86_64-linux";
|
|
||||||
nixpkgs = "mine";
|
|
||||||
rendered = config.configuration.config.my.asContainer;
|
|
||||||
|
|
||||||
assignments = {
|
|
||||||
internal = {
|
|
||||||
name = "gam-ctr";
|
|
||||||
inherit domain;
|
|
||||||
ipv4.address = net.cidr.host 11 prefixes.ctrs.v4;
|
|
||||||
ipv6 = {
|
|
||||||
iid = "::11";
|
|
||||||
address = net.cidr.host 11 prefixes.ctrs.v6;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
|
|
||||||
let
|
|
||||||
inherit (lib) mkMerge mkIf mkForce;
|
|
||||||
inherit (lib.my) networkdAssignment;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
config = mkMerge [
|
|
||||||
{
|
|
||||||
my = {
|
|
||||||
deploy.enable = false;
|
|
||||||
server.enable = true;
|
|
||||||
|
|
||||||
secrets = {
|
|
||||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAvDlH3nT1kve741gBluYmn5KQs8yz7FAEt8qLt+f0K6";
|
|
||||||
files = {
|
|
||||||
"gam/terraria.conf" = {
|
|
||||||
owner = "terraria";
|
|
||||||
group = "terraria";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd = {
|
|
||||||
network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
terraria = {
|
|
||||||
enable = true;
|
|
||||||
noUPnP = true;
|
|
||||||
messageOfTheDay = "sup gamers";
|
|
||||||
autoCreatedWorldSize = "large";
|
|
||||||
worldPath = "/var/lib/terraria/NotWorld.wld";
|
|
||||||
configFile = config.age.secrets."gam/terraria.conf".path;
|
|
||||||
openFirewall = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(mkIf config.my.build.isDevVM {
|
|
||||||
virtualisation = {
|
|
||||||
forwardPorts = [ ];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -60,10 +60,10 @@ in
|
|||||||
transmission.extraGroups = [ "media" ];
|
transmission.extraGroups = [ "media" ];
|
||||||
radarr.extraGroups = [ "media" ];
|
radarr.extraGroups = [ "media" ];
|
||||||
sonarr.extraGroups = [ "media" ];
|
sonarr.extraGroups = [ "media" ];
|
||||||
seerr = {
|
jellyseerr = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
uid = uids.jellyseerr;
|
uid = uids.jellyseerr;
|
||||||
group = "seerr";
|
group = "jellyseerr";
|
||||||
};
|
};
|
||||||
photoprism = {
|
photoprism = {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
@@ -77,7 +77,7 @@ in
|
|||||||
};
|
};
|
||||||
groups = {
|
groups = {
|
||||||
media.gid = 2000;
|
media.gid = 2000;
|
||||||
seerr.gid = gids.jellyseerr;
|
jellyseerr.gid = gids.jellyseerr;
|
||||||
photoprism.gid = gids.photoprism;
|
photoprism.gid = gids.photoprism;
|
||||||
copyparty.gid = gids.copyparty;
|
copyparty.gid = gids.copyparty;
|
||||||
};
|
};
|
||||||
@@ -88,15 +88,13 @@ in
|
|||||||
jackett.bindsTo = [ "systemd-networkd-wait-online@vpn.service" ];
|
jackett.bindsTo = [ "systemd-networkd-wait-online@vpn.service" ];
|
||||||
transmission.bindsTo = [ "systemd-networkd-wait-online@vpn.service" ];
|
transmission.bindsTo = [ "systemd-networkd-wait-online@vpn.service" ];
|
||||||
|
|
||||||
radarr.serviceConfig.UMask = mkForce "0002";
|
radarr.serviceConfig.UMask = "0002";
|
||||||
radarr.path = with pkgs; [ ffmpeg ];
|
sonarr.serviceConfig.UMask = "0002";
|
||||||
sonarr.serviceConfig.UMask = mkForce "0002";
|
jellyseerr.serviceConfig = {
|
||||||
sonarr.path = with pkgs; [ ffmpeg ];
|
|
||||||
seerr.serviceConfig = {
|
|
||||||
# Needs to be able to read its secrets
|
# Needs to be able to read its secrets
|
||||||
DynamicUser = mkForce false;
|
DynamicUser = mkForce false;
|
||||||
User = "seerr";
|
User = "jellyseerr";
|
||||||
Group = "seerr";
|
Group = "jellyseerr";
|
||||||
};
|
};
|
||||||
|
|
||||||
# https://github.com/NixOS/nixpkgs/issues/258793#issuecomment-1748168206
|
# https://github.com/NixOS/nixpkgs/issues/258793#issuecomment-1748168206
|
||||||
@@ -145,7 +143,7 @@ in
|
|||||||
jackett.enable = true;
|
jackett.enable = true;
|
||||||
radarr.enable = true;
|
radarr.enable = true;
|
||||||
sonarr.enable = true;
|
sonarr.enable = true;
|
||||||
seerr = {
|
jellyseerr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Forwarded in AirVPN config
|
# Forwarded in AirVPN config
|
||||||
transmissionPeerPort = 28457;
|
transmissionPeerPort = 47016;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ in
|
|||||||
secrets = {
|
secrets = {
|
||||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAQM9U1e/XcUCyMJITrpAHjAGahpqkZCmtX6pJkYzuks";
|
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAQM9U1e/XcUCyMJITrpAHjAGahpqkZCmtX6pJkYzuks";
|
||||||
files = {
|
files = {
|
||||||
|
"dhparams.pem" = {
|
||||||
|
owner = "acme";
|
||||||
|
group = "acme";
|
||||||
|
mode = "440";
|
||||||
|
};
|
||||||
"pdns-file-records.key" = {
|
"pdns-file-records.key" = {
|
||||||
owner = "acme";
|
owner = "acme";
|
||||||
group = "acme";
|
group = "acme";
|
||||||
@@ -171,7 +176,7 @@ in
|
|||||||
"*.${config.networking.domain}"
|
"*.${config.networking.domain}"
|
||||||
];
|
];
|
||||||
dnsProvider = "exec";
|
dnsProvider = "exec";
|
||||||
environmentFile =
|
credentialsFile =
|
||||||
let
|
let
|
||||||
script = pkgs.writeShellScript "lego-update-int.sh" ''
|
script = pkgs.writeShellScript "lego-update-int.sh" ''
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@@ -202,7 +207,7 @@ in
|
|||||||
"*.s3.${pubDomain}"
|
"*.s3.${pubDomain}"
|
||||||
];
|
];
|
||||||
dnsProvider = "cloudflare";
|
dnsProvider = "cloudflare";
|
||||||
environmentFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
|
credentialsFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
|
||||||
postRun =
|
postRun =
|
||||||
let
|
let
|
||||||
sshKey = config.age.secrets."middleman/mailcow-ssh.key".path;
|
sshKey = config.age.secrets."middleman/mailcow-ssh.key".path;
|
||||||
@@ -251,6 +256,7 @@ in
|
|||||||
valid = "5s";
|
valid = "5s";
|
||||||
};
|
};
|
||||||
proxyResolveWhileRunning = true;
|
proxyResolveWhileRunning = true;
|
||||||
|
sslDhparam = config.age.secrets."dhparams.pem".path;
|
||||||
|
|
||||||
appendConfig = ''
|
appendConfig = ''
|
||||||
worker_processes auto;
|
worker_processes auto;
|
||||||
|
|||||||
@@ -437,14 +437,6 @@ in
|
|||||||
};
|
};
|
||||||
useACMEHost = pubDomain;
|
useACMEHost = pubDomain;
|
||||||
};
|
};
|
||||||
"hass-john.${pubDomain}" = {
|
|
||||||
locations."/" = {
|
|
||||||
proxyPass = "http://john-valorant-tun.${domain}:8123";
|
|
||||||
proxyWebsockets = true;
|
|
||||||
extraConfig = proxyHeaders;
|
|
||||||
};
|
|
||||||
useACMEHost = pubDomain;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
minio =
|
minio =
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ in
|
|||||||
"/var/lib/harmonia" = {
|
"/var/lib/harmonia" = {
|
||||||
device = "/mnt/nix-cache";
|
device = "/mnt/nix-cache";
|
||||||
options = [ "bind" ];
|
options = [ "bind" ];
|
||||||
fsType = "none";
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,9 +161,6 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO/FIXME: this is bad...
|
|
||||||
nixpkgs.config.permittedInsecurePackages = [ "minio-2025-10-15T17-29-55Z" ];
|
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
minio = {
|
minio = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -266,7 +262,7 @@ in
|
|||||||
signKeyPaths = [ config.age.secrets."nix-cache.key".path ];
|
signKeyPaths = [ config.age.secrets."nix-cache.key".path ];
|
||||||
settings = {
|
settings = {
|
||||||
priority = 30;
|
priority = 30;
|
||||||
virtual_nix_store = "/nix/store";
|
daemon_store = "/nix/store";
|
||||||
real_nix_store = "/var/lib/harmonia/nix/store";
|
real_nix_store = "/var/lib/harmonia/nix/store";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ in
|
|||||||
PDS_EMAIL_FROM_ADDRESS = "pds@nul.ie";
|
PDS_EMAIL_FROM_ADDRESS = "pds@nul.ie";
|
||||||
|
|
||||||
PDS_DID_PLC_URL = "https://plc.directory";
|
PDS_DID_PLC_URL = "https://plc.directory";
|
||||||
PDS_INVITE_REQUIRED = "true";
|
PDS_INVITE_REQUIRED = 1;
|
||||||
PDS_BSKY_APP_VIEW_URL = "https://api.bsky.app";
|
PDS_BSKY_APP_VIEW_URL = "https://api.bsky.app";
|
||||||
PDS_BSKY_APP_VIEW_DID = "did:web:api.bsky.app";
|
PDS_BSKY_APP_VIEW_DID = "did:web:api.bsky.app";
|
||||||
PDS_REPORT_SERVICE_URL = "https://mod.bsky.app";
|
PDS_REPORT_SERVICE_URL = "https://mod.bsky.app";
|
||||||
|
|||||||
@@ -217,7 +217,6 @@ in
|
|||||||
toot = {};
|
toot = {};
|
||||||
waffletail = {};
|
waffletail = {};
|
||||||
qclk = {};
|
qclk = {};
|
||||||
gam = {};
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
mkMerge [
|
mkMerge [
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ in
|
|||||||
enshrouded-oci = 5;
|
enshrouded-oci = 5;
|
||||||
kevcraft-oci = 6;
|
kevcraft-oci = 6;
|
||||||
kinkcraft-oci = 7;
|
kinkcraft-oci = 7;
|
||||||
graeme-oci = 8;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
|
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
|
||||||
|
|||||||
@@ -186,49 +186,6 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
graeme = {
|
|
||||||
# 2026.2.1-java21-alpine
|
|
||||||
image = "itzg/minecraft-server@sha256:82adaddfe0156f07c34228f1c1065cdbd298abc174de0a9961abb068b11beebb";
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
TYPE = "VANILLA";
|
|
||||||
SERVER_PORT = "25569";
|
|
||||||
QUERY_PORT = "25569";
|
|
||||||
|
|
||||||
EULA = "true";
|
|
||||||
ENABLE_QUERY = "true";
|
|
||||||
ENABLE_RCON = "false";
|
|
||||||
MOTD = "§4§k----- §9G§ar§ba§ce§dm§ee §4§k-----";
|
|
||||||
ICON = "/ext/icon.png";
|
|
||||||
|
|
||||||
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
|
|
||||||
WHITELIST = concatStringsSep "," [
|
|
||||||
op
|
|
||||||
"fffa146c-0bc8-421c-9e3a-3635c0aca2ea" # Scarlehh
|
|
||||||
"1ea05f48-76cc-4034-bcd3-2fa1fc5a7375" # Dario
|
|
||||||
"4bf837b1-01db-4491-a0e0-700d98542833" # JoeSpencer
|
|
||||||
"d07a9554-1b05-4b0b-b558-27e4a86e1f53" # AmyClover
|
|
||||||
];
|
|
||||||
EXISTING_OPS_FILE = "SYNCHRONIZE";
|
|
||||||
OPS = op;
|
|
||||||
DIFFICULTY = "hard";
|
|
||||||
SPAWN_PROTECTION = "0";
|
|
||||||
VIEW_DISTANCE = "20";
|
|
||||||
|
|
||||||
MAX_MEMORY = "4G";
|
|
||||||
|
|
||||||
TZ = "Europe/Dublin";
|
|
||||||
};
|
|
||||||
|
|
||||||
volumes = [
|
|
||||||
"graeme_data:/data"
|
|
||||||
"${./graeme.png}:/ext/icon.png:ro"
|
|
||||||
];
|
|
||||||
|
|
||||||
extraOptions = [
|
|
||||||
''--network=colony:${dockerNetAssignment allAssignments "graeme-oci"}''
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.9 KiB |
@@ -109,7 +109,11 @@ in
|
|||||||
};
|
};
|
||||||
fstrim.enable = true;
|
fstrim.enable = true;
|
||||||
|
|
||||||
resolved.settings.Resolve.LLMNR = mkForce true;
|
resolved = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = mkForce "";
|
||||||
|
dnssec = "false";
|
||||||
|
};
|
||||||
|
|
||||||
pipewire.extraConfig.pipewire = {
|
pipewire.extraConfig.pipewire = {
|
||||||
"10-buffer"."context.properties" = {
|
"10-buffer"."context.properties" = {
|
||||||
@@ -118,14 +122,13 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
blueman.enable = true;
|
blueman.enable = true;
|
||||||
avahi.enable = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
programs = {
|
programs = {
|
||||||
virt-manager.enable = true;
|
virt-manager.enable = true;
|
||||||
wireshark = {
|
wireshark = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.wireshark;
|
package = pkgs.wireshark-qt;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
virtualisation.libvirtd.enable = true;
|
virtualisation.libvirtd.enable = true;
|
||||||
@@ -162,7 +165,6 @@ in
|
|||||||
network = {
|
network = {
|
||||||
netdevs = mkMerge [
|
netdevs = mkMerge [
|
||||||
(mkVLAN "lan-hi" vlans.hi)
|
(mkVLAN "lan-hi" vlans.hi)
|
||||||
(mkVLAN "lan-lo" vlans.lo)
|
|
||||||
];
|
];
|
||||||
links = {
|
links = {
|
||||||
"10-et2.5g" = {
|
"10-et2.5g" = {
|
||||||
@@ -184,7 +186,7 @@ in
|
|||||||
networks = {
|
networks = {
|
||||||
"30-et100g" = {
|
"30-et100g" = {
|
||||||
matchConfig.Name = "et100g";
|
matchConfig.Name = "et100g";
|
||||||
vlan = [ "lan-hi" "lan-lo" ];
|
vlan = [ "lan-hi" ];
|
||||||
networkConfig.IPv6AcceptRA = false;
|
networkConfig.IPv6AcceptRA = false;
|
||||||
};
|
};
|
||||||
"40-lan-hi" = mkMerge [
|
"40-lan-hi" = mkMerge [
|
||||||
@@ -192,22 +194,6 @@ in
|
|||||||
# So we don't drop the IP we use to connect to NVMe-oF!
|
# So we don't drop the IP we use to connect to NVMe-oF!
|
||||||
{ networkConfig.KeepConfiguration = "static"; }
|
{ networkConfig.KeepConfiguration = "static"; }
|
||||||
];
|
];
|
||||||
"45-lan-lo" = {
|
|
||||||
matchConfig.Name = "lan-lo";
|
|
||||||
networkConfig = {
|
|
||||||
DHCP = "ipv4";
|
|
||||||
IPv6AcceptRA = true;
|
|
||||||
UseDomains = false;
|
|
||||||
};
|
|
||||||
dhcpV4Config = {
|
|
||||||
UseDNS = false;
|
|
||||||
UseGateway = false;
|
|
||||||
};
|
|
||||||
ipv6AcceptRAConfig = {
|
|
||||||
UseDNS = false;
|
|
||||||
UseGateway = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -230,15 +216,8 @@ in
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
programs = {
|
|
||||||
claude-code = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
blueman-applet.enable = true;
|
blueman-applet.enable = true;
|
||||||
easyeffects.enable = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
wayland.windowManager.sway = {
|
wayland.windowManager.sway = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
# ./unifi.nix
|
./unifi.nix
|
||||||
./hass.nix
|
./hass.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,7 +210,6 @@ in
|
|||||||
customComponents = with pkgs.home-assistant-custom-components; [
|
customComponents = with pkgs.home-assistant-custom-components; [
|
||||||
alarmo
|
alarmo
|
||||||
frigate
|
frigate
|
||||||
west_wood_club
|
|
||||||
];
|
];
|
||||||
|
|
||||||
configWritable = false;
|
configWritable = false;
|
||||||
|
|||||||
@@ -121,9 +121,11 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
resolved.settings.Resolve = {
|
resolved = {
|
||||||
LLMNR = false;
|
llmnr = "false";
|
||||||
MulticastDNS = false;
|
extraConfig = ''
|
||||||
|
MulticastDNS=false
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
iperf3 = {
|
iperf3 = {
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ in
|
|||||||
|
|
||||||
services = {
|
services = {
|
||||||
pdns-recursor = {
|
pdns-recursor = {
|
||||||
settings = {
|
yaml-settings = {
|
||||||
incoming = {
|
incoming = {
|
||||||
listen = [
|
listen = [
|
||||||
"127.0.0.1" "::1"
|
"127.0.0.1" "::1"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ def main():
|
|||||||
|
|
||||||
print(f'Updating {args.record} -> {address}')
|
print(f'Updating {args.record} -> {address}')
|
||||||
cf.dns.records.edit(
|
cf.dns.records.edit(
|
||||||
zone_id=zone.id, dns_record_id=record.id, name=args.record,
|
zone_id=zone.id, dns_record_id=record.id,
|
||||||
type='A', content=address)
|
type='A', content=address)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -165,28 +165,6 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
{
|
|
||||||
id = 3;
|
|
||||||
subnet = prefixes.untrusted.v4;
|
|
||||||
interface = "lan-untrusted";
|
|
||||||
option-data = [
|
|
||||||
{
|
|
||||||
name = "routers";
|
|
||||||
data = vips.untrusted.v4;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "domain-name-servers";
|
|
||||||
data = "1.1.1.1, 1.0.0.1";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
pools = [
|
|
||||||
{
|
|
||||||
pool = if index == 0
|
|
||||||
then "192.168.80.10 - 192.168.80.127"
|
|
||||||
else "192.168.80.128 - 192.168.80.250";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
ddns-send-updates = true;
|
ddns-send-updates = true;
|
||||||
ddns-replace-client-name = "when-not-present";
|
ddns-replace-client-name = "when-not-present";
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
vlanIface = vlan: if vlan == "as211024" then vlan else "lan-${vlan}";
|
vlanIface = vlan: if vlan == "as211024" then vlan else "lan-${vlan}";
|
||||||
vrrpIPs = family: concatMap (vlan: [
|
vrrpIPs = family: concatMap (vlan: (optional (family == "v6") {
|
||||||
|
addr = "fe80::1/64";
|
||||||
|
dev = vlanIface vlan;
|
||||||
|
}) ++ [
|
||||||
{
|
{
|
||||||
addr = "${vips.${vlan}.${family}}/${toString (net.cidr.length prefixes.${vlan}.${family})}";
|
addr = "${vips.${vlan}.${family}}/${toString (net.cidr.length prefixes.${vlan}.${family})}";
|
||||||
dev = vlanIface vlan;
|
dev = vlanIface vlan;
|
||||||
@@ -61,9 +64,6 @@ in
|
|||||||
v4 = mkVRRP "v4" 51;
|
v4 = mkVRRP "v4" 51;
|
||||||
v6 = (mkVRRP "v6" 52) // {
|
v6 = (mkVRRP "v6" 52) // {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
virtual_ipaddress_excluded {
|
|
||||||
${concatMapStringsSep "\n" (vlan: "fe80::1/64 dev ${vlanIface vlan}") (attrNames vips)}
|
|
||||||
}
|
|
||||||
notify_master "${config.systemd.package}/bin/systemctl start radvd.service" root
|
notify_master "${config.systemd.package}/bin/systemctl start radvd.service" root
|
||||||
notify_backup "${config.systemd.package}/bin/systemctl stop radvd.service" root
|
notify_backup "${config.systemd.package}/bin/systemctl stop radvd.service" root
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -73,8 +73,8 @@ in
|
|||||||
RootDirectory = lib.mkForce "";
|
RootDirectory = lib.mkForce "";
|
||||||
};
|
};
|
||||||
|
|
||||||
radarr.serviceConfig.UMask = lib.mkForce "0002";
|
radarr.serviceConfig.UMask = "0002";
|
||||||
sonarr.serviceConfig.UMask = lib.mkForce "0002";
|
sonarr.serviceConfig.UMask = "0002";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ in
|
|||||||
"*.${domain}"
|
"*.${domain}"
|
||||||
];
|
];
|
||||||
dnsProvider = "cloudflare";
|
dnsProvider = "cloudflare";
|
||||||
environmentFile = config.age.secrets."kelder/cloudflare-credentials.conf".path;
|
credentialsFile = config.age.secrets."kelder/cloudflare-credentials.conf".path;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -88,7 +88,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
resolved.settings.Resolve = mkForce { };
|
resolved.extraConfig = mkForce "";
|
||||||
|
|
||||||
nextcloud = {
|
nextcloud = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ in
|
|||||||
owner = "nginx";
|
owner = "nginx";
|
||||||
group = "nginx";
|
group = "nginx";
|
||||||
};
|
};
|
||||||
|
"dhparams.pem" = {
|
||||||
|
owner = "acme";
|
||||||
|
group = "acme";
|
||||||
|
mode = "440";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
firewall = {
|
firewall = {
|
||||||
@@ -30,6 +35,7 @@ in
|
|||||||
recommendedTlsSettings = true;
|
recommendedTlsSettings = true;
|
||||||
clientMaxBodySize = "0";
|
clientMaxBodySize = "0";
|
||||||
serverTokens = true;
|
serverTokens = true;
|
||||||
|
sslDhparam = config.age.secrets."dhparams.pem".path;
|
||||||
|
|
||||||
# Based on recommended*Settings, but probably better to be explicit about these
|
# Based on recommended*Settings, but probably better to be explicit about these
|
||||||
appendHttpConfig = ''
|
appendHttpConfig = ''
|
||||||
|
|||||||
@@ -99,6 +99,12 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
resolved = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = mkForce "";
|
||||||
|
dnssec = "false";
|
||||||
|
};
|
||||||
|
|
||||||
fprintd.enable = true;
|
fprintd.enable = true;
|
||||||
blueman.enable = true;
|
blueman.enable = true;
|
||||||
|
|
||||||
@@ -112,7 +118,7 @@
|
|||||||
steam.enable = true;
|
steam.enable = true;
|
||||||
wireshark = {
|
wireshark = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.wireshark;
|
package = pkgs.wireshark-qt;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -99,7 +99,7 @@
|
|||||||
|
|
||||||
# Enable wpa_supplicant, but don't start it by default.
|
# Enable wpa_supplicant, but don't start it by default.
|
||||||
networking.wireless.enable = mkDefault true;
|
networking.wireless.enable = mkDefault true;
|
||||||
networking.wireless.userControlled = true;
|
networking.wireless.userControlled.enable = true;
|
||||||
systemd.services.wpa_supplicant.wantedBy = mkForce [];
|
systemd.services.wpa_supplicant.wantedBy = mkForce [];
|
||||||
|
|
||||||
# Tell the Nix evaluator to garbage collect more aggressively.
|
# Tell the Nix evaluator to garbage collect more aggressively.
|
||||||
|
|||||||
@@ -38,15 +38,6 @@ in
|
|||||||
enable = mkDefault true;
|
enable = mkDefault true;
|
||||||
wheelNeedsPassword = mkDefault false;
|
wheelNeedsPassword = mkDefault false;
|
||||||
};
|
};
|
||||||
|
|
||||||
# TODO: Add this to fix login
|
|
||||||
# pam = {
|
|
||||||
# services = {
|
|
||||||
# kmscon.rules. = mkIf config.services.kmscon.config.libseat {
|
|
||||||
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
nix = {
|
nix = {
|
||||||
@@ -82,7 +73,6 @@ in
|
|||||||
# inputs.borgthin.overlays.default
|
# inputs.borgthin.overlays.default
|
||||||
inputs.boardie.overlays.default
|
inputs.boardie.overlays.default
|
||||||
inputs.copyparty.overlays.default
|
inputs.copyparty.overlays.default
|
||||||
inputs.hass-west-wood.overlays.default
|
|
||||||
];
|
];
|
||||||
config = {
|
config = {
|
||||||
allowUnfree = true;
|
allowUnfree = true;
|
||||||
@@ -149,7 +139,6 @@ in
|
|||||||
bash-completion
|
bash-completion
|
||||||
git
|
git
|
||||||
unzip
|
unzip
|
||||||
tcpdump
|
|
||||||
]
|
]
|
||||||
(mkIf config.services.netdata.enable [ netdata ])
|
(mkIf config.services.netdata.enable [ netdata ])
|
||||||
];
|
];
|
||||||
@@ -167,14 +156,16 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
# TODO: Remove if-else when 26.11 releases
|
kmscon = {
|
||||||
kmscon = if (config.system.nixos.release == "26.06:u-26.11") then {
|
# As it turns out, kmscon hasn't been updated in years and has some bugs...
|
||||||
enable = mkDefault false;
|
enable = mkDefault false;
|
||||||
config = {
|
hwRender = mkDefault true;
|
||||||
hwaccel = config.hardware.graphics.enable;
|
extraOptions = "--verbose";
|
||||||
font-name = "SauceCodePro Nerd Font Mono";
|
extraConfig =
|
||||||
|
''
|
||||||
|
font-name=SauceCodePro Nerd Font Mono
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
} else { };
|
|
||||||
getty.greetingLine = mkDefault' ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
|
getty.greetingLine = mkDefault' ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
|
||||||
|
|
||||||
openssh = {
|
openssh = {
|
||||||
@@ -255,7 +246,7 @@ in
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
(mkIf config.services.kmscon.enable {
|
(mkIf config.services.kmscon.enable {
|
||||||
fonts.packages = with pkgs; [
|
fonts.fonts = with pkgs; [
|
||||||
nerd-fonts.sauce-code-pro
|
nerd-fonts.sauce-code-pro
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -45,9 +45,8 @@ let
|
|||||||
|
|
||||||
journalctl -o cat --no-pager -n 0 -f -u "$unit" &
|
journalctl -o cat --no-pager -n 0 -f -u "$unit" &
|
||||||
jPid=$!
|
jPid=$!
|
||||||
|
|
||||||
# shellcheck disable=SC2329
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
|
# shellcheck disable=SC2317
|
||||||
kill "$jPid"
|
kill "$jPid"
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{ lib, pkgs, config, ... }:
|
{ lib, pkgs, config, ... }:
|
||||||
let
|
let
|
||||||
inherit (lib) optional mkIf mkDefault mkMerge mkOverride;
|
inherit (lib) optional mkIf mkDefault mkMerge;
|
||||||
inherit (lib.my) mkBoolOpt';
|
inherit (lib.my) mkBoolOpt';
|
||||||
|
|
||||||
cfg = config.my.gui;
|
cfg = config.my.gui;
|
||||||
@@ -44,17 +44,6 @@ in
|
|||||||
swaylock-plugin
|
swaylock-plugin
|
||||||
];
|
];
|
||||||
services = {
|
services = {
|
||||||
resolved = {
|
|
||||||
settings.Resolve = {
|
|
||||||
FallbackDNS = mkOverride 99 (
|
|
||||||
"1.1.1.1#cloudflare-dns.com 8.8.8.8#dns.google " +
|
|
||||||
"1.0.0.1#cloudflare-dns.com 8.8.4.4#dns.google " +
|
|
||||||
"2606:4700:4700::1111#cloudflare-dns.com 2001:4860:4860::8888#dns.google " +
|
|
||||||
"2606:4700:4700::1001#cloudflare-dns.com 2001:4860:4860::8844#dns.google" );
|
|
||||||
LLMNR = "resolve";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
pipewire = {
|
pipewire = {
|
||||||
enable = true;
|
enable = true;
|
||||||
alsa.enable = true;
|
alsa.enable = true;
|
||||||
|
|||||||
@@ -5,10 +5,23 @@ let
|
|||||||
|
|
||||||
cfg = config.my.netboot;
|
cfg = config.my.netboot;
|
||||||
|
|
||||||
|
# Newer releases don't boot on desktop?
|
||||||
|
ipxe = pkgs.ipxe.overrideAttrs (o: rec {
|
||||||
|
version = "1.21.1-unstable-2024-06-27";
|
||||||
|
src = pkgs.fetchFromGitHub {
|
||||||
|
owner = "ipxe";
|
||||||
|
repo = "ipxe";
|
||||||
|
rev = "b66e27d9b29a172a097c737ab4d378d60fe01b05";
|
||||||
|
hash = "sha256-TKZ4WjNV2oZIYNefch7E7m1JpeoC/d7O1kofoNv8G40=";
|
||||||
|
};
|
||||||
|
|
||||||
|
# This upstream patch (in newer versions) is needed for newer GCC
|
||||||
|
patches = (if (o ? patches) then o.patches else []) ++ [ ./fix-uninitialised-var.patch ];
|
||||||
|
});
|
||||||
tftpRoot = pkgs.linkFarm "tftp-root" [
|
tftpRoot = pkgs.linkFarm "tftp-root" [
|
||||||
{
|
{
|
||||||
name = "ipxe-x86_64.efi";
|
name = "ipxe-x86_64.efi";
|
||||||
path = "${pkgs.ipxe}/ipxe.efi";
|
path = "${ipxe}/ipxe.efi";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
menuFile = pkgs.runCommand "menu.ipxe" {
|
menuFile = pkgs.runCommand "menu.ipxe" {
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
services.resolved = {
|
services.resolved = {
|
||||||
settings.Resolve = {
|
domains = [ config.networking.domain ];
|
||||||
Domains = [ config.networking.domain ];
|
|
||||||
# Explicitly unset fallback DNS (Nix module will not allow for a blank config)
|
# Explicitly unset fallback DNS (Nix module will not allow for a blank config)
|
||||||
FallbackDNS = "";
|
extraConfig = ''
|
||||||
Cache = "no-negative";
|
FallbackDNS=
|
||||||
};
|
Cache=no-negative
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ let
|
|||||||
|
|
||||||
extraSettingsOpt = with lib.types; mkOpt' (nullOr str) null "Path to extra settings (e.g. for secrets).";
|
extraSettingsOpt = with lib.types; mkOpt' (nullOr str) null "Path to extra settings (e.g. for secrets).";
|
||||||
baseAuthSettings = pkgs.writeText "pdns.conf" (settingsToLines cfg.auth.settings);
|
baseAuthSettings = pkgs.writeText "pdns.conf" (settingsToLines cfg.auth.settings);
|
||||||
baseRecursorSettings = (pkgs.formats.yaml { }).generate "pdns-recursor.yaml" config.services.pdns-recursor.settings;
|
baseRecursorSettings = (pkgs.formats.yaml { }).generate "pdns-recursor.yaml" config.services.pdns-recursor.yaml-settings;
|
||||||
generateSettings = type: base: dst: if (cfg."${type}".extraSettingsFile != null) then ''
|
generateSettings = type: base: dst: if (cfg."${type}".extraSettingsFile != null) then ''
|
||||||
oldUmask="$(umask)"
|
oldUmask="$(umask)"
|
||||||
umask 006
|
umask 006
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ in
|
|||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services = {
|
services = {
|
||||||
getty.autologinUser = mkDefault uname;
|
getty.autologinUser = mkDefault uname;
|
||||||
resolved.settings.Resolve.LLMNR = mkDefault "false";
|
kmscon.autologinUser = mkDefault uname;
|
||||||
|
resolved.llmnr = mkDefault "false";
|
||||||
};
|
};
|
||||||
systemd = {
|
systemd = {
|
||||||
timers = {
|
timers = {
|
||||||
@@ -34,6 +35,10 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
documentation.nixos.enable = mkDefault' false;
|
documentation.nixos.enable = mkDefault' false;
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
tcpdump
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
meta.buildDocsInSandbox = false;
|
meta.buildDocsInSandbox = false;
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ in
|
|||||||
# Also the script runs before impermanence does.
|
# Also the script runs before impermanence does.
|
||||||
"/var/lib/nixos"
|
"/var/lib/nixos"
|
||||||
"/var/lib/systemd"
|
"/var/lib/systemd"
|
||||||
"/var/cache/man"
|
|
||||||
|
|
||||||
{ directory = "/root/.cache/nix"; mode = "0700"; }
|
{ directory = "/root/.cache/nix"; mode = "0700"; }
|
||||||
# Including these unconditionally due to infinite recursion problems...
|
# Including these unconditionally due to infinite recursion problems...
|
||||||
@@ -337,13 +336,13 @@ in
|
|||||||
(persistSimpleSvc "jackett")
|
(persistSimpleSvc "jackett")
|
||||||
(persistSimpleSvc "radarr")
|
(persistSimpleSvc "radarr")
|
||||||
(persistSimpleSvc "sonarr")
|
(persistSimpleSvc "sonarr")
|
||||||
(mkIf config.services.seerr.enable {
|
(mkIf config.services.jellyseerr.enable {
|
||||||
my.tmproot.persistence.config.directories = [
|
my.tmproot.persistence.config.directories = [
|
||||||
{
|
{
|
||||||
directory = "/var/lib/seerr";
|
directory = "/var/lib/jellyseerr";
|
||||||
mode = "0750";
|
mode = "0750";
|
||||||
user = "seerr";
|
user = "jellyseerr";
|
||||||
group = "seerr";
|
group = "jellyseerr";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
@@ -604,16 +603,6 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
(mkIf config.services.terraria.enable {
|
|
||||||
my.tmproot.persistence.config.directories = [
|
|
||||||
{
|
|
||||||
directory = config.services.terraria.dataDir;
|
|
||||||
mode = "0755";
|
|
||||||
user = "terraria";
|
|
||||||
group = "terraria";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
})
|
|
||||||
]))
|
]))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ in
|
|||||||
isNormalUser = true;
|
isNormalUser = true;
|
||||||
uid = mkDefault 1000;
|
uid = mkDefault 1000;
|
||||||
extraGroups =
|
extraGroups =
|
||||||
[ "wheel" "kvm" "dialout" "disk" ] ++
|
[ "wheel" "kvm" "dialout" ] ++
|
||||||
(optional config.networking.networkmanager.enable "networkmanager") ++
|
(optional config.networking.networkmanager.enable "networkmanager") ++
|
||||||
(optional config.virtualisation.libvirtd.enable "libvirtd") ++
|
(optional config.virtualisation.libvirtd.enable "libvirtd") ++
|
||||||
(optional config.programs.wireshark.enable "wireshark") ++
|
(optional config.programs.wireshark.enable "wireshark") ++
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ stdenv.mkDerivation rec {
|
|||||||
./demoloopi.patch
|
./demoloopi.patch
|
||||||
];
|
];
|
||||||
|
|
||||||
configureFlags = [
|
|
||||||
"CFLAGS=-std=gnu17"
|
|
||||||
];
|
|
||||||
|
|
||||||
outputs = [ "out" "man" ];
|
outputs = [ "out" "man" ];
|
||||||
|
|
||||||
postPatch = ''
|
postPatch = ''
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBvMndF
|
|
||||||
M21hR3p2VmEzUm16eDEya2NtSW54SElScnQzRVhTYnhRNC9oS3dVCnFsS3ZyLyt2
|
|
||||||
aVlsVEgySFpvKzA4cTd0ZnkwbGRHakJSL2JESU54KzFDNEkKLT4gWDI1NTE5IFQw
|
|
||||||
cTN5bjJJVUoyckpjWnllM3piV3llM1VRSlN3Tlk4cG0yRzlTU1ZnMzQKQ2s2d0xs
|
|
||||||
VjBjUlRkbUpHZDV0c2kwUGhUczhuVEV3ZE1WK2NxWndDQk9PWQotPiA+Oi1QYD47
|
|
||||||
LWdyZWFzZSBFTEJWRHkzIE0oOVJTJQp2THpheXJqYmdPRlpTRXhQTkYzeGsyZ0dG
|
|
||||||
aElRblgwWW1sT1NjZVNPUFNINXBPV1BxUldkCi0tLSBNOGhuUkNCV2NCZi9PdGxP
|
|
||||||
WitZYTNwcDZXdGNjbDUzQkVZUEtUK2JsZTN3CrxYEwDQAvqeCckfsLUKB1ixsTF1
|
|
||||||
rQNRYxioye5T7AZEnOrZg62qkOELmCwAD5UJt5tkNRrmHkm0JwiqNsThHX6qGnHl
|
|
||||||
iDgytz/Hymij
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFY3bGdHdyBEZzFM
|
|
||||||
NFkyT2k0MmdkTkVhL1U3M2dEUXhhQk1VejNDMDBDZ2xSaWs2NXlzClJranFmWG14
|
|
||||||
NVZ2cXRSZzc5N1ZXM3ZaWWpsY3gxYjg4dnRWeHh5NHlNUU0KLT4gWDI1NTE5IGlh
|
|
||||||
ZmN5Ti9sakpwZUNna1RWOWtEU1VXVkY4cXhpeW9kdUdUMVJaK2dUelUKS2FCbFVF
|
|
||||||
VStaZENxRlVBRlk1ak9sb2Q4YWg4SmxSV0xRU2R3dGZ4TGNoVQotPiB1UTRIcGlZ
|
|
||||||
LWdyZWFzZSB9I1VoKG50JCBSCnp2blloZGhpVDk2YVB2ZDVmbDZBeWJxdmsyMUc5
|
|
||||||
NHk1cDg3cCtVclVnU2J5dUQ4UWh1bnJIMERyTVg4UzlFS0YKNjNLdmZIYk5qWXI0
|
|
||||||
UVEvcWJzbm1Da2RmdzVmRzhmbEltdURhMVhKL0g5S2hqTTJVU3Z0dnBoSQotLS0g
|
|
||||||
QUVQOEk0OGpuUnFEQkhkVnBrUUk2OWZ3MkxIVmF4b2QzYjlnMW5veVorQQqEjPN4
|
|
||||||
qAfHZxuujoneLQu98m+2zXuTGY6tvnnvaZLoqbr0dQgQ+ISHgipnhYM0b6FK6sbG
|
|
||||||
mgGYyg==
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
|
||||||
+72
-74
@@ -1,76 +1,74 @@
|
|||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHNqUFR5ZyBkWHB2
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHNqUFR5ZyBlbHl0
|
||||||
MHNUSnRIQkc4OENhN2dVdVlFZFRlWW5oVW9WbENaTGcwK2ZnQVFRCkQyYjdNaEtK
|
S0lQbXBKVGpNNnJOUS9TSlp0U0EvYWFVanN3N0RMb1JudEdwYVQ4CnJGdklzeEFy
|
||||||
SXE5RExTMm9EZC9GSEJGcWNabUgyOERBZmFmV0VqRFVXWTgKLT4gc3NoLWVkMjU1
|
RmxjamNyUWszYjFGb0ZZbk9EQVdERERtckpqczVscjdmUE0KLT4gc3NoLWVkMjU1
|
||||||
MTkgRExNZUZnIEhJNHN3c0lGL1lrMTA0ZHV2bHdPZ0dveDNBNVlzazEwbU9NcVZl
|
MTkgRExNZUZnIGR4czhRYjUyU29JbnFnRk5IeXliNzZzMVMya1ZuS2tkUlFVTkxU
|
||||||
Z3RKelUKaWEwTTZvSTA0T2pKSGVoc3gwL3VPWjNPOFk3dTNjYVo5S2tPWUNtV3Fw
|
aFd0VWsKenprWWQ0UEdaUGhvRlJUbnU1T2h1czZBK1dpOGwwcjJxc2p6ejV1RnM0
|
||||||
dwotPiBzc2gtZWQyNTUxOSAzYkIzWmcgMEN2dDJiRHYrQzRIb1JJVXp1V0ZyMkdu
|
RQotPiBzc2gtZWQyNTUxOSAzYkIzWmcgMHB6dzVFQ3FtaWErVWNyRXo3WnNhT2NF
|
||||||
RWNtKy93QVR4SVJkK1VXTlUyQQpNdUU1c1NOdi9ZbmFTNHJBWmNTZFp2NDZORWp1
|
eldUVWtOaVlWOTVwcVVaOUlGMApJUDUzNmhKbUxleTV6SjV0Zmk3dno0STVIRDIv
|
||||||
ZzZzMzU3ZWFVYU1Lc1k0Ci0+IHNzaC1lZDI1NTE5IHErMFhjdyBiVS9ZeVE5Vytp
|
SUkyd1M2Z21mdUtMUXIwCi0+IHNzaC1lZDI1NTE5IHErMFhjdyBnRFBPRnNSa0Nn
|
||||||
a3p2c2xYM28rM0Q1UWMyNkQxYWRScStGRGVhTTYvQWc4ClNvSksydmhid20yTzNC
|
UTlpR1Y4OU1UQmNLRnRWaGxzU3RBV0c1bG90K2I5QUQ0CjArUFlGS1B2RkVKSEtP
|
||||||
ZHF2b252MWwzRG9Zdi9uRVpqL1BacGRaemo5OEkKLT4gc3NoLWVkMjU1MTkgWkIz
|
ajRpUUNlMkRPN3pxaEkrZ1M3RndxRDZ6U09Wc2cKLT4gc3NoLWVkMjU1MTkgWkIz
|
||||||
ZTZRIFVZUTVjNS9pak9JSnF4N2JOMEZINmtKTzU5OUxHbHRKeng2cldvK2NXU2sK
|
ZTZRIFRPdXRTeEVvUTM1dlQzMll2VDFkUlY2eEFRcnRrc1lNeDZDbFE1a3BjaDgK
|
||||||
T0M3QTZJU2lqMk9nRGl2c3QwNTlWOEwyYVJUK3pleEtMZ0lYbm9TSmVUZwotPiBz
|
MytBM0Y2Mmo2M1JOWExLQy8xTm9SR05WcmxrV2xBZ0RpeXQxeGVkZ1VZcwotPiBz
|
||||||
c2gtZWQyNTUxOSBqNjdGWFEgRzRXYTBxQWduN2QvZk84NXVWVHlQN2RiS0pkYXM2
|
c2gtZWQyNTUxOSBqNjdGWFEgYUw5cnJabnhhdU9lN0NPVXVUazRnVWpzcUVtM3VR
|
||||||
U2cvM0JKRXZvTjAxdwpCbWdMZVpMaXBBNHRRZjN4aU5lNmhRNmMzSnBIWUNtbW1w
|
bWQxNVVSQTN5N3hXRQp0blhXUC94TlRPbS9Ba2N1eVM0QkNNblJBa1hJYjZ1Y1lM
|
||||||
ZStLaXlUL09ZCi0+IHNzaC1lZDI1NTE5IGMwVE5hUSBxK09aSTRaUzZ4VnArMlF4
|
UDhWbUd5bWNVCi0+IHNzaC1lZDI1NTE5IGMwVE5hUSA0TXowVjA0N2FvcER6OEts
|
||||||
ZFZvNmUrR1hPKzB1SUdRS2Z2dmgyVlROOUVZCllUcDNCSEpVUmVUN2RSYjZ5aDdp
|
VTVwa0UzUEtsY005WDhmaU8zZ3VLaXQvaVRJCjB4cjJiMHVGM3hyWlg0OHhaT0lu
|
||||||
SWhCVFlwcWxJMkxodEwrQXNDOTh0TlUKLT4gc3NoLWVkMjU1MTkgbjhDcFV3IHJ4
|
K2NJQWVndzYrSDAyK25NMklSVUI4S28KLT4gc3NoLWVkMjU1MTkgbjhDcFV3IFNE
|
||||||
Y1krN2hHTjhOakZSZ3VNNEZnYVVLb1BTZ01iT2dyRjdUdkRodit0QUkKRitpVFJB
|
Q1NZbnpqUkdiaktnYkxZdzZrYUVqWDEvYnMvOTJqSUpybERTNk9uQ0kKYlMzZkVu
|
||||||
WDU2eGw2aUhQZFcrMTB6MU5VTURPNE5HbUFYendOMnNDRXRQcwotPiBzc2gtZWQy
|
SXVtaWk2WEtDMEpwZFM3ZVIyWHQwUWNOZjVRS0I0ZjN5MklHYwotPiBzc2gtZWQy
|
||||||
NTUxOSBWN2xnR3cgcUNRZkp6R0llR0o0RmhvanBoamdoNVBKRWl0Sm1sQVhBRGJw
|
NTUxOSBqSThSQWcgWTZIMCtNMCtzTFpROHpBMnA3b2s2UFE2dDZGbnlxU2VxMlkz
|
||||||
MFFDcmdUbwpENlEvaTh4OUhVQ0VTeXBGMTBoajd1eE42YzYvc0ZvcWlVYU1HWnkr
|
aGJFUzV6awpKNDhobHQrTCs4cUVpNE5wblJMako3bU5tVldjVDBjVlJOOHhkUTNk
|
||||||
R0FnCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBFdEpIT3F1MGVtZ0ppN05hVDBLRjZz
|
NFdrCi0+IHNzaC1lZDI1NTE5IFQrc2JHQSBTbVlBTXIzQ09SOHRJakZXK3NkT1Uy
|
||||||
eTRWdjZkMGM0SWpqeVJpRXRGc2pRClVpTlB6Q3lCZ3FXd1g1eXU3Y3grRVBJRjBC
|
RFgrUTZncSsyK3p5WlVDSFNwM2lFClErRHk4Qmp2VlIvZW8rV2lNME53ZFlIUmVC
|
||||||
aERTanp4dDhGRFdteThNNTgKLT4gc3NoLWVkMjU1MTkgVCtzYkdBIEpselBValht
|
bXF5RlVvV2FUM3ZmeWpaQzgKLT4gc3NoLWVkMjU1MTkgaE1hNG53IDBINGhyMDBy
|
||||||
TTNtY2lTYWg3VHBUTWNIemdiQXpHd01jMS9BeERMclQ0RGcKYU85dnN3ZEJyQmZZ
|
bkp0RWpTU0F6Uk1kaXllRHBHbXF2QWUwNkN1U0tEWE53VGsKdi9QRlhwRCtyQkRq
|
||||||
ZE9ZYXl4Ym1BZlBkcm9jMXBhZ1J3aUlxR1dPNm96dwotPiBzc2gtZWQyNTUxOSBo
|
cng1Wk1rZkx2NnJTMUxGajN3b2Z3SG0zd0ptcklCZwotPiBzc2gtZWQyNTUxOSBl
|
||||||
TWE0bncgcXdIK21EVDVMZGhMMEltQ3RNbkx5NDhGVWRVdU4wZlhUNDY0bEZTcEZG
|
eXEzZGcgcnQ4WUFMcGRtL1BvYTkxWU12WTdkT1lLRmJlZXZ4cWtHNG54QVo0dDYw
|
||||||
QQpUSGZOb0FoSTgxckp0R3dxVjVPZkQ0b3Z5WXpjU1Q1Qy8zaGNVNzh4ZGJvCi0+
|
RQp2NkMwbTROZTBuRUVLNEs3L3BmOTZ2S3dDL0hUbm5OaHZXbjVCRG15bExnCi0+
|
||||||
IHNzaC1lZDI1NTE5IGV5cTNkZyBwaGF3NXVNWUVQUUpuUm9pVHVRK1NoV1FmVFMz
|
IHNzaC1lZDI1NTE5IDdXUTlQQSBPL0t1ZWptTm5YQXIwc3ZNUGhkaVM5QU1DMkNL
|
||||||
dys1bE9WaDdNV0RXZFRVCmVJSUx0VkQvbDRjOWdvNlhCNm9RSnhnUHFpYnp0ZjVM
|
NU1WSFlTT05KOWR3dGhJCmdTTEIrNEZma3E0UzArMndqVEgzWnVLNzl0TjhsbG9P
|
||||||
UG82UElhM3R6MFkKLT4gc3NoLWVkMjU1MTkgN1dROVBBIERKYnFGQm9pVlIzYWxu
|
OE9aRVk1Ung1cEkKLT4gc3NoLWVkMjU1MTkgZ1N4UDBRIGJNazFtRThSVVVvb3dP
|
||||||
M3Fza0RucE9SczQzRk5ialU2R215L1NwcVU2bW8Ka2hCL2JSU1c1bEhFS0t3VnEy
|
RHV5WGxCbktDK3c5aEhiYkphNU4zUnVNUVNNV2sKbWZJYkNSZFMvTDI1WVg5SnJV
|
||||||
YWtaMG5mZHBxYjNkK0JQUjlmVHJYSmNUMAotPiBzc2gtZWQyNTUxOSBnU3hQMFEg
|
bUFSY2JsNDJBc253dlN5Y2Nqdm9TbU9IawotPiBzc2gtZWQyNTUxOSBWRmN3NWcg
|
||||||
VHhRN0VEV0xGL0hJUHd1V0drWVJzaWtucXJ2c2xMUVpYMFc2TklLUGdYVQp0VWZj
|
eEo0dmRNWVpuVGdxRHpXc09tUDZldFRKcTBIMVVWcXdmVFRhZnZmenBETQpJWHVp
|
||||||
UEZGeGhaRDh4SmFsek93ejBUM1A3OVorTWFmcWt0QkVCZmV0QU5ZCi0+IHNzaC1l
|
NWJNRWhacHlMbHlQcjEzdEZWdUVpbGg0N2pqMjcvTk92UDJpNUlvCi0+IHNzaC1l
|
||||||
ZDI1NTE5IFZGY3c1ZyBmOHgraG50b2NiREZIcjRacTUwZ1Z3R2h0QXlHMTl6SFNJ
|
ZDI1NTE5IGhrYnR2ZyB0SFJGRE03T3lnTUJZakVCcnQxVklPNXhzak94eU5KUzNX
|
||||||
Qlc4MTFtT2k4CkVSdzY3cEVpR3J3L0szMXBVdmd2OUFsWGJwanRtSGl3QmRyREhJ
|
L216SCtUWEVzCmRrS2Rlc1JiNEg1KzExaUsrNHJuSDlTcU5Oa0J4QVZKVmNBRGFP
|
||||||
WjRwS2sKLT4gc3NoLWVkMjU1MTkgaGtidHZnIGVVNDZzenBDRlRmeW4ybUJqamRD
|
ZWlqUjAKLT4gc3NoLWVkMjU1MTkgZXQyenBRIEFhMFVxZ3RRbk4za2t5cWtwVjVi
|
||||||
UFFpWDY1ZjJuK1VQNWJJSGIyaFJnbmcKcmg3b284YmZQUWt0clBjVDZVZk5CUUlo
|
Qm9ucVdMekVsSHEwSWlML0JIdmQ2SFkKWW5mWnQvRWlaT3hJLzJyTE5RdTNUMWNM
|
||||||
aFRWWUwzVmVPcFBDaW1xKzRqSQotPiBzc2gtZWQyNTUxOSBldDJ6cFEgWEZpOXdx
|
SDB4TjVKZCtDN0tCR1NhdnRqbwotPiBzc2gtZWQyNTUxOSBaYkxKV0EgV1loMWZx
|
||||||
bWo3NnZYSjFTdldoSDBBMVVobHRXYWJjZEd2RVBIanRrQUZROApkZG82RUZHSkRH
|
OHhKelNvNzErMDc4cUE5amgycTFTem5lVmlGYTk5bUM2T2dEUQpkMVQ0VS80Y3Jt
|
||||||
TGkyTG1tRUlRMEg5MVRwRHNjTE9UL1BMRUpDdXVLZ2tVCi0+IHNzaC1lZDI1NTE5
|
QTZUVnNZV0daczM0Titvc3Q1T2JiTVZYV2tXOW4xV0VRCi0+IHNzaC1lZDI1NTE5
|
||||||
IFpiTEpXQSB0ZWtnRFVWKzRkSU45enFadkx6N3FpRmE1MnByZEljd3FyWGFyd2Ja
|
IFpOcUlvZyAzMnZ2NjR1R2R2UlJNZjNvOU9RckR0MEtnbllyYVJPSUZtUDNWSU5k
|
||||||
QVNvClpiZkxsQ04zR2pzOXBtODdnbjdSaHBtSVFVT3V2aFdyZ2FoaytISmNzR0UK
|
U3c4Ckgza2txalJhOW14c1dGZ0VTc3EzK2NpOUJaVWhqN2lMWU9HL3hMSWlJUVkK
|
||||||
LT4gc3NoLWVkMjU1MTkgWk5xSW9nIHMvWElOMTgvR0ZveHZLSlVqNW9PSmNvdm92
|
LT4gc3NoLWVkMjU1MTkgcUxqcXlRIHMxNStVTnY1TUZJaHlXQnNTSFhXditsWnVF
|
||||||
ZW92dHhvbG8vRzl2NFdqMFEKUktLWEJuQ25LM1J6OXBvRlRlMEFEeXlhV3M1Yk85
|
Y2ZKRWZ5UXVPZUVKY2VjakEKV1N3ODVFYXROTzFReWE5Y1A5MkpXUjJVc00wVVd3
|
||||||
Wk0rZWJMQ3U2SVYrcwotPiBzc2gtZWQyNTUxOSBxTGpxeVEgODlpYkhNQmFkNjlp
|
ZUpzTC9rRGdOWUpxWQotPiBzc2gtZWQyNTUxOSBCYVFsUmcganpkWlpaWlRVQ3Vp
|
||||||
ZUYyZ0VDdzBsTmk5TGVPU0VTRnZlSUdMazN3cXB4awpGbEhWMVR0N0NzTGljeEpw
|
Y2hvbkpld2kzdzVtdERHajBNUTEyM0NOWlp0WkxtRQp1MEJUKzFUSW9tWjluVU9Y
|
||||||
dWtrTXR0QW5CVHE5enA2dXZZNm55ajVSa3NVCi0+IHNzaC1lZDI1NTE5IEJhUWxS
|
clBzNFpzdU83MXdGN2dJSGducnplbEd4M1JNCi0+IHNzaC1lZDI1NTE5IHMrcVJm
|
||||||
ZyBJc2xSZUJkaEd5U1EyV0J6T2pUU1ZWMnRPSzYwNFRERndsdThYeFFQSUVJCmlT
|
ZyBSRW1pZWFhQkpQRTFYTG9IZnVmWmx6S2pNUll4MGhtRFd1Y0ZhS25JNFZVCjhU
|
||||||
OWh1dnpNRDU5WlNSaW5FTUZ5QVVHSmw0NUpQMklOb3JYU3FSM3ZTWEUKLT4gc3No
|
UDhoOTlTUEtqbytZMjZ2NlozcnZTNXVNcVA3cU1TRmtsL1g4bEhKUzgKLT4gc3No
|
||||||
LWVkMjU1MTkgcytxUmZnIERvYU1PNXJkWEs0VkI5YWNuY3ZGK2xpVkpxN01zbHA2
|
LWVkMjU1MTkgNjJKY2NBIElSSXZjc3J5cWNwOHFNV281YzBrVzc2TlVwMnRwb0NJ
|
||||||
cm9DUzk1WHIrRWsKZVRGWUwrdmVnOTh4clFHdm1yL0JuSVRpVldjWkMwUkdFTk5J
|
dEdST0s4MEhmQnMKaTNEdkFjRktCZHNCY3FsWE5UbFo1R3lXSlI2NE5MR25neWJ4
|
||||||
LzNlT0dZUQotPiBzc2gtZWQyNTUxOSA2MkpjY0EgTXI5QVZySXpsQlVoTE51c29j
|
NTlsSllxWQotPiBzc2gtZWQyNTUxOSAvaHgvZEEgOExaRjJiNTJkUGFxZllSK1Uz
|
||||||
MWltaUZHZUlPUEo1WXZNdUUzSWdWRU94MApMVUYzYlhNZDc5RTRzc0NxNW5PblU0
|
eWxQTmtxOVFPZkVFb2w2Z0tmZVpwTndDWQpuRFlqZWdaQjZaT1BZSmllVzB5NWhY
|
||||||
WndIV1FZTm51ZlhQdWFQa2NNS25FCi0+IHNzaC1lZDI1NTE5IC9oeC9kQSBWUkJS
|
MmhHaWtZOXFERzhSRWRXWk5TR1RRCi0+IHNzaC1lZDI1NTE5IFd6TEdIQSBtZW04
|
||||||
ZmR2a3BDdHRrVUhqejFjZFI4cWw1MEkrRWUwdHZHZEloemtUT2pBCmFYU21lRllo
|
eWlNWU9JOXYvcVlsb1JXM2JKRlREeXJXNHd6MlkvazZrSzdscG5BCnZzWUFwb3lK
|
||||||
MTlic204cU41Vi95dFBMSSs2eWtVSzJndG1keWdVeUgxNFEKLT4gc3NoLWVkMjU1
|
dUhkcDZNakFPN0RMRG5LQzdqU1UzNlJ6eGRGSGlhYUx0YXMKLT4gc3NoLWVkMjU1
|
||||||
MTkgSEovSjdBIGhhck53d1ZzYVY5ZjF5VHpXYVBDMGZ5SGdTL3B4NHQ2a3lENGti
|
MTkgSEovSjdBIDBaNzZGVkdaVWlWNk4yVW5UdnFCZ2xWUEtIc2QzQmJTMnlINVF1
|
||||||
NXhZVGMKV3B0d0IwNm5qM0xDUWdOTEZ3Q3ErWGdNRmtIeTBMSjV1eDYzMUVYVFpY
|
V093UmsKcXNhSnlnWHQrRzVSU296NENDN29aMUN5VlRIcittdGNySGhvMHZlT0xl
|
||||||
cwotPiBzc2gtZWQyNTUxOSBPRXFNc2cgcm9ZOS81emFxd2toNTRFUW1LRi9jU3FF
|
NAotPiBzc2gtZWQyNTUxOSBPRXFNc2cgNUFSc045eUVqQWI3MXB4Tkd2RndDS2Na
|
||||||
VUdYRzRWTm5uV0ZjclJPZmsyQQoxZnRtTzZ5YzRJTVRGalU4NFZhQmZlMjhtY2Nv
|
VGJrblFLaENPVlZucFdGRGFDTQp6dlRHTnRLSFkxb1RFdmxGS09Jenh2Q25VZ2ha
|
||||||
Q1oyZURhQUpjR2dvRVNRCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyA5aUNiQk1FZUtU
|
QWQ4YUNjdVNJbW8vVGVrCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyBGM2lrUG1DWUx3
|
||||||
S0hta1lOMVlWL1RwdjUvQnl2MTg5VWQrMnNCVERkVkZrCkFraTR4UmFBbXpOR1lq
|
YndZWWdobVo3TjZHTDNabmdsa3ZHcndwUXVZSVg5T0VZCjNYdlFYSHBsWjBTWXlS
|
||||||
TTFCSmZmV0R1VjhWb2V0RXdiYkpaek0rdGVsRE0KLT4gWDI1NTE5IEpZSlNOZk5D
|
V0lSZkpwVE05eU1LcFBEbWdXWEZ0U0tSTkthQnMKLT4gWDI1NTE5IDF5SmczUWpo
|
||||||
WlZ3VFFpVUx2RHlwblVEZHZyVVNGbHNrZ3hUY1FYQUJNMWMKYlo4dFVnS2hhYk1m
|
bkdmWS9SamxtTTF1eVJnc1QxUGJiUjQwR1VSTmdxMEtqQzAKeTF0NWp6dG1CWGNy
|
||||||
THZXMktudExKdEE1enlGWUgyM3FiMGpFbmR6RkNyawotPiBGImFlO2V5Ky1ncmVh
|
VVVXVGFLV3dkWWo2YTVkZmtXcHRZai9FSDVBSmJhbwotPiAmJC1ncmVhc2UgaWU3
|
||||||
c2UKdTZXVjRtcTR2TDFITzB1d3J3RG1hejk1am15SEswR05PMFdoTXR2UVpoRE9H
|
YGkpVSBNV0ZfIDM1fltQdzBcCmZYRXB1NEVMNkVqWVF3Ci0tLSB2RVRFYmVGVklB
|
||||||
dkMvQldlc1FPWlRFSURXN3ppSQoyU0pSRHFIS2I3d1dtTE5OTFFXSTYyR2tTbTZB
|
bGFiUTBKYlMrRitvN2NnUkhScTMvWml6ZzRKU3ZIeEtvChoKB2c5roTC97pdDOi6
|
||||||
RDVROStRCi0tLSAvWEcyR09pQnRhSzN4d2kzSzduOUVtTXd2U25CWmZJdWt5NnNl
|
aPFIaTyOu9NZ4ESwwRjpEgB0D6GP2r7YR3CnxVyXa4sCFUnTF8dLUkABFnSeNeQZ
|
||||||
RHVieGNBCi411IjgmUKttjX6ljaZGWivstOajx2pkTVLV/zFiEj3jv+KDGy1psZQ
|
M64tM6J+tZAyJa9IKaTgSqvQaGYHHYinygNvf6BShCK4nPUJu0cV6gFtqFle0MWA
|
||||||
no+eatGMO8LeJhGJ6H7TBKOmJhFMfoQp1XKJA8OGY+FGZ98bit04djo3jqbVSOms
|
Rez5eRMFH/M2aubhwBeDyHG4WRelkt7oMVXyY6U=
|
||||||
JSPRTvTxxQx+40yO+ETV+2qkRU1OdJTobz9YvuqGlHrJS8UNN30QMPT0ienu3QTY
|
|
||||||
Tbo=
|
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
|||||||
Reference in New Issue
Block a user