Compare commits
120 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b4233b8f1c | |||
| 43c026c451 | |||
| 9222be4052 | |||
| 24d451f825 | |||
| f5d0f97400 | |||
| 5dad72daa4 | |||
| f42d031f4f | |||
| 086ca6377f | |||
| 8b1d0f6972 | |||
| 02a61ec4dd | |||
| aac5738dda | |||
| 1851df463c | |||
| 976e1663aa | |||
| eb4609613e | |||
| 41e50f98b5 | |||
| 6ef3f87d16 | |||
| f878369896 | |||
| 179ced171d | |||
| a226d68df7 | |||
| 8e6cfa47b8 | |||
| 9d702285b6 | |||
| ef128b240e | |||
| f66c8792c4 | |||
| dde6dc3246 | |||
| 0d3d41c8f9 | |||
| 8c566ed869 | |||
| eb09fdf8fd | |||
| 650ae4ef16 | |||
| cac57806b5 | |||
| 6e8246672d | |||
| b80322f58a | |||
| 936df3b7fc | |||
| 38809d7c3c | |||
| ea60876ce9 | |||
| 5880242e06 | |||
| 61502c1490 | |||
| c20b77a6b8 | |||
| 3442744803 | |||
| 87ee0849f9 | |||
| 732d29eea3 | |||
| 6ee3eaf9d3 | |||
| 352b589ad1 | |||
| e3c43a2d8a | |||
| 11061e7692 | |||
| c969f66c60 | |||
| df27af1f10 | |||
| 0ccad6ebc1 | |||
| 2da0e4b27f | |||
| 98165730f5 | |||
| b56a738258 | |||
| 5c2d62da1b | |||
| a7616d0ac5 | |||
| 680ba7cecb | |||
| 0a11794634 | |||
| 6999e420f7 | |||
| 6545452c1d | |||
| 082b406b50 | |||
| 227010bc8c | |||
| 3a1140a1d9 | |||
| 9e3c84f609 | |||
| 2b72a31feb | |||
| c28ecde7bd | |||
| af56559632 | |||
| 9e4177d773 | |||
| 8efbab4147 | |||
| e45e7960da | |||
| 0d5bf7e46d | |||
| 83c7ef00ad | |||
| 1fbe15c0a0 | |||
| a923f4fd82 | |||
| 802bf1ca4c | |||
| b5e45398d8 | |||
| 623cad29a7 | |||
| fde7963379 | |||
| e0f2f64886 | |||
| 0036acbde3 | |||
| ecdf223431 | |||
| 6e6a8a205a | |||
| 342ff16158 | |||
| c75b754ace | |||
| de45a27860 | |||
| 3557b88d7c | |||
| 67e4dc15e7 | |||
| 291a15d0c5 | |||
| 7034b651f8 | |||
| 9c5aaca961 | |||
| c0d6a20780 | |||
| e8228616fb | |||
| 7b072f8467 | |||
| 6b0147e764 | |||
| 557fe1c502 | |||
| 3f74e38b80 | |||
| 904e299cdb | |||
| 3b901f231c | |||
| bfd766eddc | |||
| d3ba187c8a | |||
| aa20d15ab3 | |||
| ee8883e6c1 | |||
| 121d5ed892 | |||
| 2a4b19a048 | |||
| acbda5c4c9 | |||
| 5c37ad035c | |||
| dce4589144 | |||
| 3c98271cec | |||
| e91c22ed44 | |||
| 0f8b574207 | |||
| 07df37c543 | |||
| baea5757de | |||
| f3176d2243 | |||
| 1e811bc45c | |||
| a6921b0820 | |||
| 1f975279c6 | |||
| 71adf08dd0 | |||
| 13e6d8e635 | |||
| 3760698ec2 | |||
| 6e3217d0db | |||
| 7e4a2d759c | |||
| 1313076917 | |||
| 73553faa27 | |||
| d53bbdd0bb |
@@ -0,0 +1,32 @@
|
|||||||
|
# This is an example configuration file
|
||||||
|
# To learn more, see the full config.yaml reference: https://docs.continue.dev/reference
|
||||||
|
name: ollama
|
||||||
|
version: 1.0.0
|
||||||
|
schema: v1
|
||||||
|
# Define which models can be used
|
||||||
|
# https://docs.continue.dev/customization/models
|
||||||
|
models:
|
||||||
|
- name: StarCoder2 Local
|
||||||
|
provider: ollama
|
||||||
|
model: starcoder2:7b
|
||||||
|
modelTimeout: "5s"
|
||||||
|
roles:
|
||||||
|
- autocomplete
|
||||||
|
autocompleteOptions:
|
||||||
|
useCache: true
|
||||||
|
useImports: true
|
||||||
|
useRecentlyEdited: true
|
||||||
|
- name: Nomic Embed Local
|
||||||
|
provider: ollama
|
||||||
|
model: nomic-embed-text:latest
|
||||||
|
roles:
|
||||||
|
- embed
|
||||||
|
- name: Autodetect
|
||||||
|
provider: ollama
|
||||||
|
model: AUTODETECT
|
||||||
|
defaultCompletionOptions:
|
||||||
|
contextLength: 64000
|
||||||
|
# MCP Servers that Continue can access
|
||||||
|
# https://docs.continue.dev/customization/mcp-tools
|
||||||
|
mcpServers:
|
||||||
|
- uses: anthropic/memory-mcp
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
---
|
||||||
|
description: |
|
||||||
|
Use when auditing NixOS flake inputs or installed modules for known CVEs,
|
||||||
|
checking pinned revisions against security advisories, scanning repo code for
|
||||||
|
vulnerabilities, or running IaC/SCA audits on the nix-dotfiles repo. Use this
|
||||||
|
agent whenever flake.lock is updated or a new input/module is added.
|
||||||
|
tools: [read, 'io.snyk/mcp/*', search, web, 'nixos/*']
|
||||||
|
---
|
||||||
|
|
||||||
|
# Dependency Security Auditor
|
||||||
|
|
||||||
|
You are a dependency security auditor for this NixOS flake repository. Your job
|
||||||
|
is to identify known CVEs, security advisories, and vulnerable package versions
|
||||||
|
across flake inputs, NixOS modules, and repo code — without interacting with any
|
||||||
|
hosted infrastructure or live services.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Read `flake.lock` to enumerate all pinned inputs.
|
||||||
|
- Read `flake.nix` and system/module configs to identify which NixOS packages
|
||||||
|
and services are in active use.
|
||||||
|
- Use the nixos MCP and Snyk MCP to cross-reference versions against known
|
||||||
|
vulnerabilities.
|
||||||
|
- Use the web tool only to look up public CVE/advisory databases (NVD, GitHub
|
||||||
|
Security Advisories, NixOS security tracker). Do NOT connect to any hosted
|
||||||
|
service in this infrastructure.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- DO NOT edit, create, or delete any files.
|
||||||
|
- DO NOT run terminal commands.
|
||||||
|
- DO NOT connect to or probe any live service (Gitea, Mattermost, Nextcloud,
|
||||||
|
HAProxy, etc.).
|
||||||
|
- DO NOT authenticate to Snyk on behalf of the user without confirming first
|
||||||
|
— call `snyk_auth_status` and report back if auth is missing.
|
||||||
|
- ONLY report findings grounded in real CVE/advisory data with a reference URL
|
||||||
|
or ID.
|
||||||
|
|
||||||
|
## Audit Steps
|
||||||
|
|
||||||
|
Work through these steps in order. Show a summary of what you checked at the end
|
||||||
|
of each step.
|
||||||
|
|
||||||
|
### Step 1: Enumerate Flake Inputs
|
||||||
|
|
||||||
|
Read `flake.lock` and extract for each node:
|
||||||
|
|
||||||
|
- Owner, repo, rev (commit hash), lastModified date
|
||||||
|
- Whether it is a `github`, `git`, or `tarball` type
|
||||||
|
|
||||||
|
Flag any inputs that:
|
||||||
|
|
||||||
|
- Have not been updated in > 180 days (stale pinning risk)
|
||||||
|
- Use a mutable `ref` without a fixed `rev` (reproducibility risk)
|
||||||
|
- Are fetched over plain HTTP (not HTTPS)
|
||||||
|
|
||||||
|
### Step 2: Look Up Active Package Versions via nixos MCP
|
||||||
|
|
||||||
|
For the pinned nixpkgs revision, use the nixos MCP (`nixos_search`,
|
||||||
|
`nixos_info`) to:
|
||||||
|
|
||||||
|
- Look up key security-sensitive packages in use across palatine-hill:
|
||||||
|
`mattermost`, `gitea`, `nextcloud`, `postgresql`, `hydra`, `attic`,
|
||||||
|
`ollama`, `loki`, `minio`, `haproxy`, `samba`.
|
||||||
|
- Note the package version returned.
|
||||||
|
- Search for any known vulnerabilities associated with that version using the
|
||||||
|
nixos MCP and the web tool (NVD: `https://nvd.nist.gov/vuln/search`, GitHub
|
||||||
|
advisory DB: `https://github.com/advisories`).
|
||||||
|
|
||||||
|
### Step 3: Run Snyk Code Scan
|
||||||
|
|
||||||
|
Before running, call `snyk_auth_status` to confirm authentication. If
|
||||||
|
unauthenticated, report that and skip this step.
|
||||||
|
|
||||||
|
Run `snyk_code_scan` on the absolute repo path
|
||||||
|
(`/home/alice/.gitprojects/nix-dotfiles`) with `severity_threshold: medium`.
|
||||||
|
Report all findings with:
|
||||||
|
|
||||||
|
- Rule ID and CWE
|
||||||
|
- Affected file and line
|
||||||
|
- Severity
|
||||||
|
- Suggested fix
|
||||||
|
|
||||||
|
### Step 4: Run Snyk IaC Scan
|
||||||
|
|
||||||
|
Run `snyk_iac_scan` on the absolute repo path
|
||||||
|
(`/home/alice/.gitprojects/nix-dotfiles`) with `severity_threshold: medium`.
|
||||||
|
While Snyk IaC does not natively parse Nix, it will catch any Kubernetes, Docker
|
||||||
|
Compose, or YAML configs present in `systems/palatine-hill/docker/` and similar
|
||||||
|
paths.
|
||||||
|
|
||||||
|
Report all findings with:
|
||||||
|
|
||||||
|
- Issue title and severity
|
||||||
|
- Affected file and line
|
||||||
|
- Impact description
|
||||||
|
- Suggested fix
|
||||||
|
|
||||||
|
### Step 5: Cross-Check NixOS Security Tracker
|
||||||
|
|
||||||
|
Use the web tool to check `https://github.com/NixOS/nixpkgs/issues?q=CVE` and
|
||||||
|
`https://discourse.nixos.org/c/security` for any open CVEs affecting:
|
||||||
|
|
||||||
|
- The pinned nixpkgs revision (from `flake.lock`)
|
||||||
|
- Any of the key packages identified in Step 2
|
||||||
|
|
||||||
|
### Step 6: Summarise
|
||||||
|
|
||||||
|
Produce a final report with:
|
||||||
|
|
||||||
|
1. **Critical / High CVEs** — packages with active, unpatched CVEs in the
|
||||||
|
pinned revision
|
||||||
|
2. **Stale Inputs** — inputs not updated in > 180 days
|
||||||
|
3. **Snyk Code Findings** — medium+ severity SAST issues
|
||||||
|
4. **Snyk IaC Findings** — medium+ severity misconfigurations in non-Nix config
|
||||||
|
files
|
||||||
|
5. **Clean** — categories with no findings (list explicitly so the report is
|
||||||
|
complete)
|
||||||
|
|
||||||
|
Each finding must include:
|
||||||
|
|
||||||
|
- Severity
|
||||||
|
- CVE ID or Snyk rule ID (with reference URL)
|
||||||
|
- Affected package/file/input
|
||||||
|
- Recommended action (upgrade nixpkgs pin, patch config, etc.)
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
---
|
||||||
|
description: |
|
||||||
|
Use when auditing NixOS server configurations for security issues, checking
|
||||||
|
for secrets in the Nix store, exposed ports, weak authentication, missing
|
||||||
|
service hardening, overly permissive firewall rules, SSH misconfiguration,
|
||||||
|
Docker socket exposure, or SOPS secrets mishandling. Read-only. Does NOT
|
||||||
|
interact with any live infrastructure or hosted resources.
|
||||||
|
tools: [read, search, 'nixos/*']
|
||||||
|
---
|
||||||
|
|
||||||
|
# Security Researcher
|
||||||
|
|
||||||
|
You are a security researcher auditing this NixOS flake repository for potential
|
||||||
|
vulnerabilities and misconfigurations. Your job is to read the configuration
|
||||||
|
as-written and identify security issues an attacker or misconfiguration could
|
||||||
|
exploit.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
- Inspect server systems only (`server = true`; currently **palatine-hill**).
|
||||||
|
- Work entirely from repository source files. DO NOT interact with any live
|
||||||
|
system, hosted service, URL, or external resource.
|
||||||
|
- Use the nixos MCP tool to look up option defaults and known behaviours — not
|
||||||
|
to reach external hosts.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- DO NOT edit, create, or delete any files.
|
||||||
|
- DO NOT run terminal commands.
|
||||||
|
- DO NOT fetch URLs or browse the web.
|
||||||
|
- DO NOT attempt to connect to, probe, or fingerprint any live service.
|
||||||
|
- ONLY report issues that are grounded in the actual content of the repository
|
||||||
|
files.
|
||||||
|
|
||||||
|
## Audit Checklist
|
||||||
|
|
||||||
|
Work through these categories in order. For each, read the relevant files before
|
||||||
|
reporting.
|
||||||
|
|
||||||
|
### 1. Secrets in the Nix Store
|
||||||
|
|
||||||
|
- Are any passwords, tokens, or API keys hardcoded in `.nix` files (not behind
|
||||||
|
SOPS)?
|
||||||
|
- Are `password = "..."` fields used in NixOS module options that end up
|
||||||
|
world-readable in `/nix/store`?
|
||||||
|
- Check service DB password fields, `initialScript`, environment variables, and
|
||||||
|
`settings` blocks.
|
||||||
|
- Use the nixos MCP tool to confirm whether a given option value lands in the
|
||||||
|
store.
|
||||||
|
|
||||||
|
### 2. SOPS Secrets Hygiene
|
||||||
|
|
||||||
|
- Do `sops.secrets` entries have the correct `owner` set to the service user
|
||||||
|
(not `root` unless necessary)?
|
||||||
|
- Is `defaultSopsFile` scoped correctly, or could one system's secrets bleed
|
||||||
|
into another?
|
||||||
|
- Are any secrets referenced in config that are not declared in `sops.secrets`?
|
||||||
|
|
||||||
|
### 3. Firewall and Attack Surface
|
||||||
|
|
||||||
|
- Which TCP/UDP ports are exposed in `firewall.nix`? Are all of them
|
||||||
|
intentional and documented?
|
||||||
|
- Are `trustedInterfaces` entries broader than necessary (e.g., `br+` covering
|
||||||
|
all bridge interfaces)?
|
||||||
|
- Does `extraCommands` insert raw iptables rules that bypass the NixOS firewall
|
||||||
|
abstraction in a dangerous way?
|
||||||
|
- Are any high-risk ports (22, 80, 443, 5432, 6379, 27017) exposed directly?
|
||||||
|
|
||||||
|
### 4. SSH Configuration
|
||||||
|
|
||||||
|
- What port is SSH running on? Is password authentication disabled?
|
||||||
|
- Are `PermitRootLogin`, `PasswordAuthentication`, and `PubkeyAuthentication`
|
||||||
|
set explicitly?
|
||||||
|
- Check `modules/openssh.nix` and any system-level overrides.
|
||||||
|
|
||||||
|
### 5. PostgreSQL Authentication
|
||||||
|
|
||||||
|
- Does `authentication` (pg_hba) use `trust` for any user or database?
|
||||||
|
- Are `scram-sha-256` or `peer` used consistently rather than `md5` or
|
||||||
|
`password`?
|
||||||
|
- Does any service connect over TCP with a plaintext password that ends up in
|
||||||
|
the Nix store?
|
||||||
|
- Are `ensureUsers` entries scoped correctly (no unnecessary `superuser` or
|
||||||
|
`createdb` grants)?
|
||||||
|
|
||||||
|
### 6. Service Isolation and Hardening
|
||||||
|
|
||||||
|
- Do systemd services set `DynamicUser`, `PrivateTmp`, `NoNewPrivileges`,
|
||||||
|
`ProtectSystem`, or similar hardening options where applicable?
|
||||||
|
- Check custom `systemd.services` blocks for missing or weak sandboxing.
|
||||||
|
- Are services running as root that should run as a dedicated user?
|
||||||
|
|
||||||
|
### 7. Docker and Container Security
|
||||||
|
|
||||||
|
- Is the Docker socket (`/var/run/docker.sock`) mounted into any container? If
|
||||||
|
so, flag it as a privilege escalation vector.
|
||||||
|
- Are any containers run with `--privileged` or `network_mode: host`?
|
||||||
|
- Are Docker compose files in the repo using hardcoded secrets or environment
|
||||||
|
variables that land in the store?
|
||||||
|
|
||||||
|
### 8. Web-Facing Services
|
||||||
|
|
||||||
|
- Do reverse-proxied services (Gitea, Mattermost, Nextcloud, etc.) set
|
||||||
|
`siteUrl`/`ROOT_URL` to HTTPS?
|
||||||
|
- Is there any service that could be accessed over plain HTTP internally?
|
||||||
|
- Are ACME/TLS certs scoped correctly and not shared across unrelated services?
|
||||||
|
|
||||||
|
### 9. Module Defaults That Are Security-Sensitive
|
||||||
|
|
||||||
|
- For each enabled service, use the nixos MCP tool to check if the default
|
||||||
|
values for security-relevant options (e.g., `database.password`,
|
||||||
|
`openFirewall`, `enableAdminCreateUser`) are safe, and confirm whether
|
||||||
|
defaults are overridden in the repo.
|
||||||
|
|
||||||
|
### 10. Broad Permission Grants
|
||||||
|
|
||||||
|
- Are any users granted `wheel`, `docker`, or other privileged groups without
|
||||||
|
clear justification?
|
||||||
|
- Does any non-human service account have `superuser`, `replication`, or
|
||||||
|
`createrole` PostgreSQL clauses?
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
Report findings as a numbered list grouped by severity:
|
||||||
|
|
||||||
|
- **Critical** — direct path to credentials exposure, RCE, or privilege
|
||||||
|
escalation
|
||||||
|
- **High** — exploitable misconfiguration or data exposure under realistic
|
||||||
|
conditions
|
||||||
|
- **Medium** — weak default, unnecessary privilege, or defence-in-depth gap
|
||||||
|
- **Low / Info** — hardening improvement or minor noise
|
||||||
|
|
||||||
|
Each finding must include:
|
||||||
|
|
||||||
|
- Severity label
|
||||||
|
- Exact file path and line (as a markdown link)
|
||||||
|
- One-sentence explanation of the risk
|
||||||
|
- Concrete suggested remediation
|
||||||
|
|
||||||
|
If a category is clean, state that explicitly so the report is complete.
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
---
|
||||||
|
description: |
|
||||||
|
Use when reviewing server infrastructure, auditing NixOS server
|
||||||
|
configurations, planning how new services or modules integrate into
|
||||||
|
palatine-hill, checking for missing imports, DB/user alignment, firewall
|
||||||
|
gaps, module argument signatures, or reverse proxy routing. DO NOT use for
|
||||||
|
making changes or for desktop/workstation systems.
|
||||||
|
tools: [read, search, 'nixos/*']
|
||||||
|
---
|
||||||
|
|
||||||
|
# Infrastructure Architect
|
||||||
|
|
||||||
|
You are an infrastructure architect for this NixOS flake repository. Your job is
|
||||||
|
to review the existing server architecture and analyse how proposed or recently
|
||||||
|
added changes integrate with it.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
You only inspect **server** machines. In this repository that means systems where
|
||||||
|
`server = true` in their `default.nix` — currently **palatine-hill**. Do NOT
|
||||||
|
inspect or opine on desktop systems such as `artemision` or `selinunte` unless
|
||||||
|
explicitly asked.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- DO NOT edit, create, or delete any files.
|
||||||
|
- DO NOT run terminal commands.
|
||||||
|
- DO NOT make assumptions — read the actual files.
|
||||||
|
- ONLY report concrete, actionable findings with exact file and line references.
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
|
||||||
|
When asked to review a change or audit the server state, work through these
|
||||||
|
checkpoints in order:
|
||||||
|
|
||||||
|
1. **Module registration** — Is the new `.nix` file imported in
|
||||||
|
`systems/<host>/configuration.nix`? Check the `imports` list.
|
||||||
|
2. **Module argument signature** — Does every module accept `{ ..., ... }:` to
|
||||||
|
absorb `specialArgs` (`system`, `server`, `inputs`, `outputs`)? A missing
|
||||||
|
`...` causes "unexpected argument" eval errors.
|
||||||
|
3. **Service dependencies** — Does the new service depend on another (e.g.
|
||||||
|
PostgreSQL, Redis, S3/Minio)? If so:
|
||||||
|
- Is the dependency service enabled and imported on this host?
|
||||||
|
- Are the required DB names and users present in `ensureDatabases` /
|
||||||
|
`ensureUsers`?
|
||||||
|
- Is the user name in `ensureUsers` consistent with what the service module
|
||||||
|
defaults to? (Use the nixos MCP tool to check default values.)
|
||||||
|
- Are authentication rules (`pg_hba`, `authentication` block) present for
|
||||||
|
the new user?
|
||||||
|
4. **Secrets alignment** — If the service uses SOPS secrets, are they declared
|
||||||
|
in `sops.secrets` with the correct `owner`? Does the secrets key exist in
|
||||||
|
`secrets.yaml`?
|
||||||
|
5. **Firewall exposure** — Is the service port opened in `firewall.nix`? If
|
||||||
|
traffic is reverse-proxied (e.g. via external HAProxy), no direct port
|
||||||
|
exposure in NixOS firewall is needed — confirm which model applies.
|
||||||
|
6. **Reverse proxy / TLS** — Is a proxy rule (HAProxy, nginx, Caddy) defined
|
||||||
|
for the new vhost? If the proxy is managed externally, note that explicitly.
|
||||||
|
Check that `siteUrl` / `ROOT_URL` / equivalent matches the actual domain.
|
||||||
|
7. **Upgrade / backup plumbing** — If the service has stateful data, is it
|
||||||
|
listed in `postgresql.upgrade.stopServices`? Is it covered by
|
||||||
|
`postgresqlBackup`?
|
||||||
|
8. **Module provisioning conflicts** — Does the NixOS module have a
|
||||||
|
`create`/`createLocally` option that auto-provisions a DB/user? If manual
|
||||||
|
provisioning also exists, flag potential ownership drift.
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
Report findings as a numbered list grouped by severity:
|
||||||
|
|
||||||
|
- **High** — will cause a build failure, service crash, or security issue
|
||||||
|
- **Medium** — will cause silent misconfiguration or future breakage
|
||||||
|
- **Low / Info** — style, redundancy, or optional improvements
|
||||||
|
|
||||||
|
Each finding must include:
|
||||||
|
|
||||||
|
- The severity label
|
||||||
|
- The exact file path and line (as a markdown link)
|
||||||
|
- A one-sentence explanation of the problem
|
||||||
|
- A concrete suggested fix
|
||||||
|
|
||||||
|
If everything checks out, say so explicitly and summarise what you verified.
|
||||||
@@ -0,0 +1,698 @@
|
|||||||
|
# Nix Dotfiles Repository Guide
|
||||||
|
|
||||||
|
This repository contains NixOS configurations for personal infrastructure. The setup is organized around a flake-based structure with per-system configurations and user-specific settings.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
- `flake.nix` - Main flake definition with inputs and outputs
|
||||||
|
- `systems/` - Per-system configurations (e.g., `artemision`, `palatine-hill`)
|
||||||
|
- `users/` - Per-user configurations using home-manager
|
||||||
|
- `modules/` - Reusable Nix modules for common services
|
||||||
|
- `lib/` - Custom Nix library functions
|
||||||
|
- `hydra/` - Hydra CI/CD configuration
|
||||||
|
- `secrets/` - SOPS encrypted secrets
|
||||||
|
|
||||||
|
## Key Concepts
|
||||||
|
|
||||||
|
### System Configuration
|
||||||
|
|
||||||
|
Each system has its own directory under `systems/` containing:
|
||||||
|
|
||||||
|
- `configuration.nix` - Main system configuration
|
||||||
|
- Component modules (audio.nix, desktop.nix, etc.)
|
||||||
|
- Hardware-specific configurations
|
||||||
|
|
||||||
|
### User Configuration
|
||||||
|
|
||||||
|
User configurations are in `users/<username>/`:
|
||||||
|
|
||||||
|
- `home.nix` - Home-manager configuration using `home.packages` and imports
|
||||||
|
- `secrets.yaml` - SOPS-encrypted secrets using age encryption
|
||||||
|
- `non-server.nix` - Desktop-specific configurations
|
||||||
|
|
||||||
|
### Nix Patterns
|
||||||
|
|
||||||
|
1. **Module-based approach**: Uses Nix modules for organizing configuration
|
||||||
|
1. **Home-manager integration**: User environment managed via home-manager
|
||||||
|
1. **SOPS secrets**: Secrets managed with SOPS and age encryption
|
||||||
|
1. **Flake-based**: Uses flakes for reproducible builds and development environments
|
||||||
|
1. **Multi-system support**: Supports multiple machines with different configurations
|
||||||
|
1. **Dynamic configuration generation**: Modules in the `modules/` directory are automatically imported into all systems (can be overridden per system). New systems are automatically discovered by `genSystems()`
|
||||||
|
|
||||||
|
### Modern Nix Features
|
||||||
|
|
||||||
|
This repository uses modern Nix features including:
|
||||||
|
|
||||||
|
- **Flakes**: Enabled via `flake` experimental feature
|
||||||
|
- **Nix Command**: Enabled via `nix-command` experimental feature
|
||||||
|
- **Blake3 Hashes**: Enabled via `blake3-hashes` experimental feature
|
||||||
|
- **Git Hashing**: Enabled via `git-hashing` experimental feature
|
||||||
|
- **Verified Fetches**: Enabled via `verified-fetches` experimental feature
|
||||||
|
|
||||||
|
### Key Commands
|
||||||
|
|
||||||
|
- `nh os switch` - Apply system configuration (using nix-community/nh)
|
||||||
|
- `nh home switch` - Apply user configuration (using nix-community/nh)
|
||||||
|
- `nh os build` - Build a specific system (using nix-community/nh)
|
||||||
|
- `nix build .#<system>` - Build a specific system
|
||||||
|
- `nix run .#<system>` - Run a specific system
|
||||||
|
- `nix flake update` - Update flake inputs
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
|
||||||
|
1. Make changes to system or user configuration
|
||||||
|
1. Test with `nh os switch` or `nh home switch`
|
||||||
|
1. For CI/CD, Hydra automatically builds and tests changes
|
||||||
|
1. Secrets are managed with SOPS and age keys
|
||||||
|
|
||||||
|
### Important Files
|
||||||
|
|
||||||
|
- `flake.nix` - Main entry point for the flake
|
||||||
|
- `systems/artemision/configuration.nix` - Example system configuration
|
||||||
|
- `users/alice/home.nix` - Example user configuration
|
||||||
|
- `modules/base.nix` - Base module with common settings
|
||||||
|
- `hydra/jobsets.nix` - Hydra CI configuration
|
||||||
|
|
||||||
|
### External Dependencies
|
||||||
|
|
||||||
|
- NixOS unstable channel
|
||||||
|
- Nixpkgs unstable channel
|
||||||
|
- SOPS for secrets management
|
||||||
|
- age for encryption
|
||||||
|
- home-manager for user environments
|
||||||
|
- nh (nix-community/nh) for simplified Nix operations
|
||||||
|
|
||||||
|
### Nix MCP Server
|
||||||
|
|
||||||
|
- Use the nix MCP server for looking up package names and options
|
||||||
|
- Specify `unstable` channel if the channel is specifiable (e.g., for `pkgs.<package-name>`)
|
||||||
|
|
||||||
|
## Dynamic Configuration System (lib/systems.nix)
|
||||||
|
|
||||||
|
This repository automatically generates NixOS system configurations based on the folder structure. Understanding how `constructSystem` and `genSystems` work is essential when adding new systems or global modules.
|
||||||
|
|
||||||
|
### How Configuration Generation Works
|
||||||
|
|
||||||
|
The process happens in three stages:
|
||||||
|
|
||||||
|
**Stage 1: Discovery** (`flake.nix` → `genSystems`)
|
||||||
|
|
||||||
|
- `flake.nix` calls `genSystems inputs outputs src (src + "/systems")`
|
||||||
|
- `genSystems` scans the `systems/` directory and lists all subdirectories
|
||||||
|
- Each subdirectory name becomes a system hostname (e.g., `artemision`, `palatine-hill`)
|
||||||
|
|
||||||
|
**Stage 2: Parameter Loading** (`genSystems` reads `default.nix`)
|
||||||
|
|
||||||
|
- For each discovered system, `genSystems` imports `systems/<hostname>/default.nix`
|
||||||
|
- This file exports parameters for `constructSystem` like:
|
||||||
|
- `users = [ "alice" ]` — which users to create
|
||||||
|
- `home = true` — enable home-manager
|
||||||
|
- `sops = true` — enable secret decryption
|
||||||
|
- `server = true/false` — machine role
|
||||||
|
- `modules = [ ... ]` — additional system-specific modules
|
||||||
|
|
||||||
|
**Stage 3: Assembly** (`constructSystem` assembles the full config)
|
||||||
|
|
||||||
|
- Loads essential system files: `hardware.nix`, `configuration.nix`
|
||||||
|
- Auto-imports all `.nix` files from `modules/` directory via `lib.adev.fileList`
|
||||||
|
- Conditionally loads home-manager, SOPS, and user configs based on parameters
|
||||||
|
- Merges everything into a complete NixOS system configuration
|
||||||
|
|
||||||
|
### Key Functions in lib/systems.nix
|
||||||
|
|
||||||
|
| Function | Purpose | Called By |
|
||||||
|
|----------|---------|-----------|
|
||||||
|
| `genSystems` | Scans `systems/` directory and creates configs for each subdirectory | `flake.nix` |
|
||||||
|
| `constructSystem` | Assembles a single NixOS system with all modules and configs | `genSystems` |
|
||||||
|
| `genHome` | Imports home-manager configs for specified users | `constructSystem` |
|
||||||
|
| `genSops` | Imports SOPS-encrypted secrets for users | `constructSystem` |
|
||||||
|
| `genUsers` | Imports user account configs from `users/<username>/` | `constructSystem` |
|
||||||
|
| `genHostName` | Creates hostname attribute set | `constructSystem` |
|
||||||
|
| `genWrapper` | Conditionally applies generator functions | `constructSystem` |
|
||||||
|
|
||||||
|
### Special Arguments Passed to All Configs
|
||||||
|
|
||||||
|
These are available in `configuration.nix`, `hardware.nix`, and all modules:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, pkgs, lib, inputs, outputs, server, system, ... }:
|
||||||
|
```
|
||||||
|
|
||||||
|
- `config` — NixOS configuration options
|
||||||
|
- `pkgs` — Nix packages (nixpkgs)
|
||||||
|
- `lib` — Nix library functions (extended with `lib.adev`)
|
||||||
|
- `inputs` — Flake inputs (nixpkgs, home-manager, sops-nix, etc.)
|
||||||
|
- `outputs` — Flake outputs (for Hydra and other tools)
|
||||||
|
- `server` — Boolean: true for servers, false for desktops
|
||||||
|
- `system` — System architecture string (e.g., `"x86_64-linux"`)
|
||||||
|
|
||||||
|
## Adding a New NixOS System
|
||||||
|
|
||||||
|
### Step 1: Create the Directory Structure
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p systems/<new-hostname>
|
||||||
|
cd systems/<new-hostname>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Create `default.nix` (System Parameters)
|
||||||
|
|
||||||
|
This file is automatically discovered and loaded by `genSystems`. It exports the parameters passed to `constructSystem`.
|
||||||
|
|
||||||
|
**Minimal example:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ inputs }:
|
||||||
|
{
|
||||||
|
# Required: List of users to create (must have entries in users/ directory)
|
||||||
|
users = [ "alice" ];
|
||||||
|
|
||||||
|
# Optional: Enable home-manager (default: true)
|
||||||
|
home = true;
|
||||||
|
|
||||||
|
# Optional: Enable SOPS secrets (default: true)
|
||||||
|
sops = true;
|
||||||
|
|
||||||
|
# Optional: Is this a server? Used to conditionally enable server features
|
||||||
|
server = false;
|
||||||
|
|
||||||
|
# Optional: System architecture (default: "x86_64-linux")
|
||||||
|
system = "x86_64-linux";
|
||||||
|
|
||||||
|
# Optional: System-specific modules (in addition to global modules/)
|
||||||
|
modules = [
|
||||||
|
# ./custom-service.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**See `systems/palatine-hill/default.nix` for a complex example with all options.**
|
||||||
|
|
||||||
|
### Step 3: Create `hardware.nix` (Hardware Configuration)
|
||||||
|
|
||||||
|
Generate this via:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo nixos-generate-config --show-hardware-config > systems/<new-hostname>/hardware.nix
|
||||||
|
```
|
||||||
|
|
||||||
|
This file typically includes:
|
||||||
|
|
||||||
|
- Boot configuration and bootloader
|
||||||
|
- Filesystem mounts and ZFS/LVM settings
|
||||||
|
- Hardware support (CPU, GPU, network drivers)
|
||||||
|
- Device-specific kernel modules
|
||||||
|
|
||||||
|
### Step 4: Create `configuration.nix` (System Configuration)
|
||||||
|
|
||||||
|
This is the main NixOS configuration file. Structure:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, pkgs, lib, inputs, server, system, ... }:
|
||||||
|
{
|
||||||
|
# System hostname (usually matches directory name)
|
||||||
|
networking.hostName = "new-hostname";
|
||||||
|
|
||||||
|
# Desktop/desktop specific config
|
||||||
|
services.xserver.enable = !server;
|
||||||
|
|
||||||
|
# System packages
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
# ...
|
||||||
|
];
|
||||||
|
|
||||||
|
# Services to enable
|
||||||
|
services.openssh.enable = server;
|
||||||
|
|
||||||
|
# System-specific settings override global defaults
|
||||||
|
boot.kernelParams = [ "nomodeset" ];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Add Optional Secrets
|
||||||
|
|
||||||
|
If the system has sensitive data:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create and encrypt secrets file
|
||||||
|
sops systems/<new-hostname>/secrets.yaml
|
||||||
|
|
||||||
|
# This will be automatically loaded by genSops if sops = true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 6: Add Optional System-Specific Modules
|
||||||
|
|
||||||
|
For system-specific functionality that shouldn't be global, create separate `.nix` files in the system directory:
|
||||||
|
|
||||||
|
```text
|
||||||
|
systems/<new-hostname>/
|
||||||
|
├── configuration.nix # Main config
|
||||||
|
├── default.nix
|
||||||
|
├── hardware.nix
|
||||||
|
├── secrets.yaml # (optional)
|
||||||
|
├── custom-service.nix # (optional) System-specific modules
|
||||||
|
├── networking.nix # (optional)
|
||||||
|
└── graphics.nix # (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
Reference these in `default.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ inputs }:
|
||||||
|
{
|
||||||
|
users = [ "alice" ];
|
||||||
|
modules = [
|
||||||
|
./custom-service.nix
|
||||||
|
./networking.nix
|
||||||
|
./graphics.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 7: Deploy the New System
|
||||||
|
|
||||||
|
The system is now automatically registered! Deploy with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build the new system
|
||||||
|
nix build .#<new-hostname>
|
||||||
|
|
||||||
|
# Or if you want to switch immediately
|
||||||
|
nh os switch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding a Global Module to modules/
|
||||||
|
|
||||||
|
Global modules are automatically imported into all systems. No registration needed.
|
||||||
|
|
||||||
|
### Create a Module File
|
||||||
|
|
||||||
|
Add a new `.nix` file to the `modules/` directory. Example: `modules/my-service.nix`
|
||||||
|
|
||||||
|
### Module Structure
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, pkgs, lib, inputs, server, ... }:
|
||||||
|
{
|
||||||
|
# Define configuration options for this module
|
||||||
|
options.myService = {
|
||||||
|
enable = lib.mkEnableOption "my service";
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 3000;
|
||||||
|
description = "Port for the service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Actual configuration (conditional on enable option)
|
||||||
|
config = lib.mkIf config.myService.enable {
|
||||||
|
environment.systemPackages = [ pkgs.my-service ];
|
||||||
|
|
||||||
|
systemd.services.my-service = {
|
||||||
|
description = "My Service";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.my-service}/bin/my-service";
|
||||||
|
Restart = "always";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using mkIf, mkDefault, and mkForce
|
||||||
|
|
||||||
|
- **`mkIf`** — Conditionally apply config based on a boolean
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config = lib.mkIf config.myService.enable { ... };
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`mkDefault`** — Provide a default value that can be overridden
|
||||||
|
|
||||||
|
```nix
|
||||||
|
boot.kernelParams = lib.mkDefault [ "quiet" ];
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`mkForce`** — Force a value, preventing other modules from overriding
|
||||||
|
|
||||||
|
```nix
|
||||||
|
services.openssh.enable = lib.mkForce true;
|
||||||
|
```
|
||||||
|
|
||||||
|
- **`mkEnableOption`** — Define an `enable` option with standard description
|
||||||
|
|
||||||
|
```nix
|
||||||
|
options.myService.enable = lib.mkEnableOption "my service";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disable a Global Module for a Specific System
|
||||||
|
|
||||||
|
To disable a module for one system, override it in that system's `configuration.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
# Disable the module entirely
|
||||||
|
myService.enable = false;
|
||||||
|
|
||||||
|
# Or override specific options
|
||||||
|
services.openssh.port = 2222;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Module Loading Order in constructSystem
|
||||||
|
|
||||||
|
Modules are applied in this order (later modules override earlier ones):
|
||||||
|
|
||||||
|
1. `inputs.nixos-modules.nixosModule` (SuperSandro2000's convenience functions)
|
||||||
|
1. `inputs.nix-index-database.nixosModules.nix-index`
|
||||||
|
1. Hostname attribute from `genHostName`
|
||||||
|
1. `hardware.nix` (hardware-specific config)
|
||||||
|
1. `configuration.nix` (main system config)
|
||||||
|
1. **System-specific modules** from `modules` parameter in `default.nix` (e.g., custom-service.nix)
|
||||||
|
1. **All `.nix` files from global `modules/` directory** (features enabled across all systems)
|
||||||
|
1. SOPS module (if `sops = true`)
|
||||||
|
1. Home-manager module (if `home = true`)
|
||||||
|
1. User configurations (if `users = [...]` and `home = true`)
|
||||||
|
|
||||||
|
Important: Global modules (step 7) are applied after system-specific configs, so they can't override those values unless using `mkForce`. System-specific modules take precedence over global ones.
|
||||||
|
|
||||||
|
## Common Tasks
|
||||||
|
|
||||||
|
### Enable a Feature Across All Systems
|
||||||
|
|
||||||
|
1. Create `modules/my-feature.nix` with `options.myFeature.enable`
|
||||||
|
1. Set the feature enabled in `configuration.nix` of systems that need it:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
myFeature.enable = true;
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Or enable globally and disable selectively:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# In modules/my-feature.nix
|
||||||
|
config = lib.mkIf config.myFeature.enable {
|
||||||
|
# ...enabled by default
|
||||||
|
};
|
||||||
|
|
||||||
|
# In a system's configuration.nix
|
||||||
|
myFeature.enable = false; # Disable just for this system
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add a New User to the System
|
||||||
|
|
||||||
|
1. Create user config: `users/<username>/default.nix` and `users/<username>/home.nix`
|
||||||
|
1. Update system's `default.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
users = [ "alice" "newuser" ];
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create secrets: `sops users/<username>/secrets.yaml`
|
||||||
|
1. Redeploy: `nh os switch`
|
||||||
|
|
||||||
|
### Override a Module's Default Behavior
|
||||||
|
|
||||||
|
In any system's `configuration.nix`:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
# Disable a service that's enabled by default in a module
|
||||||
|
services.openssh.enable = false;
|
||||||
|
|
||||||
|
# Override module options
|
||||||
|
boot.kernelParams = [ "nomodeset" ];
|
||||||
|
|
||||||
|
# Add to existing lists
|
||||||
|
environment.systemPackages = [ pkgs.custom-tool ];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Which Modules Are Loaded
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all module paths being loaded
|
||||||
|
nix eval .#nixosConfigurations.<hostname>.options --json | jq keys | head -20
|
||||||
|
|
||||||
|
# Evaluate a specific config value
|
||||||
|
nix eval .#nixosConfigurations.<hostname>.config.services.openssh.enable
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validate Configuration Before Deploying
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check syntax and evaluate
|
||||||
|
nix flake check
|
||||||
|
|
||||||
|
# Build without switching
|
||||||
|
nix build .#<hostname>
|
||||||
|
|
||||||
|
# Preview what would change
|
||||||
|
nix build .#<hostname> && nix-diff /run/current-system ./result
|
||||||
|
```
|
||||||
|
|
||||||
|
## Secrets Management
|
||||||
|
|
||||||
|
SOPS (Secrets Operations) manages sensitive data like passwords and API keys. This repository uses age encryption with SOPS to encrypt secrets per system and per user.
|
||||||
|
|
||||||
|
### Directory Structure
|
||||||
|
|
||||||
|
Secrets are stored alongside their respective configs:
|
||||||
|
|
||||||
|
```text
|
||||||
|
systems/<hostname>/secrets.yaml # System-wide secrets
|
||||||
|
users/<username>/secrets.yaml # User-specific secrets
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating and Editing Secrets
|
||||||
|
|
||||||
|
**Create or edit a secrets file:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# For a system
|
||||||
|
sops systems/<hostname>/secrets.yaml
|
||||||
|
|
||||||
|
# For a user
|
||||||
|
sops users/<username>/secrets.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
SOPS will open your `$EDITOR` with decrypted content. When you save and exit, it automatically re-encrypts the file.
|
||||||
|
|
||||||
|
**Example secrets structure for a system:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# systems/palatine-hill/secrets.yaml
|
||||||
|
acme:
|
||||||
|
email: user@example.com
|
||||||
|
api_token: "secret-token-here"
|
||||||
|
postgresql:
|
||||||
|
password: "db-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example secrets for a user:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# users/alice/secrets.yaml
|
||||||
|
# The user password is required
|
||||||
|
user-password: "hashed-password-here"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Accessing Secrets in Configuration
|
||||||
|
|
||||||
|
Secrets are made available via `config.sops.secrets` in modules and configurations:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
# In a module or configuration.nix
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
# Reference a secret
|
||||||
|
services.postgresql.initialScript = ''
|
||||||
|
CREATE USER app WITH PASSWORD '${config.sops.secrets."postgresql/password".path}';
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Or use the secret directly if it supports content
|
||||||
|
systemd.services.my-app.serviceConfig = {
|
||||||
|
EnvironmentFiles = [ config.sops.secrets."api-token".path ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merging Secrets Files
|
||||||
|
|
||||||
|
When multiple systems or users modify secrets, use the sops-mergetool to resolve conflicts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set up mergetool
|
||||||
|
git config merge.sopsmergetool.command "sops-mergetool-wrapper $BASE $CURRENT $OTHER $MERGED"
|
||||||
|
|
||||||
|
# Then during a merge conflict
|
||||||
|
git merge branch-name
|
||||||
|
|
||||||
|
# Git will use sops-mergetool to intelligently merge encrypted files
|
||||||
|
```
|
||||||
|
|
||||||
|
The repository includes helper scripts: `utils/sops-mergetool.sh` and `utils/sops-mergetool-new.sh`
|
||||||
|
|
||||||
|
### Adding a New Machine's Age Key
|
||||||
|
|
||||||
|
When adding a new system (`systems/<new-hostname>/`), you need to register its age encryption key:
|
||||||
|
|
||||||
|
1. Generate the key on the target machine (if using existing deployment) or during initial setup
|
||||||
|
1. Add the public key to `.sops.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
keys:
|
||||||
|
- &artemision <age-key-for-artemision>
|
||||||
|
- &palatine-hill <age-key-for-palatine-hill>
|
||||||
|
- &new-hostname <age-key-for-new-hostname>
|
||||||
|
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: 'systems/new-hostname/.*'
|
||||||
|
key_groups:
|
||||||
|
- age: *new-hostname
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Re-encrypt existing secrets with the new key:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sops updatekeys systems/new-hostname/secrets.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Real-World Examples
|
||||||
|
|
||||||
|
### Example 1: Adding a Feature to All Desktop Machines
|
||||||
|
|
||||||
|
Using `artemision` (desktop) as an example:
|
||||||
|
|
||||||
|
**Create `modules/gpu-optimization.nix`:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, lib, server, ... }:
|
||||||
|
{
|
||||||
|
options.gpu.enable = lib.mkEnableOption "GPU optimization";
|
||||||
|
|
||||||
|
config = lib.mkIf (config.gpu.enable && !server) {
|
||||||
|
# Desktop-only GPU settings
|
||||||
|
hardware.nvidia.open = true;
|
||||||
|
services.xserver.videoDrivers = [ "nvidia" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Enable in `systems/artemision/configuration.nix`:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
gpu.enable = true;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deploy:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build .#artemision
|
||||||
|
nh os switch
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Adding a Server Service to One System
|
||||||
|
|
||||||
|
Using `palatine-hill` (server) as an example:
|
||||||
|
|
||||||
|
**Create `systems/palatine-hill/postgresql-backup.nix`:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
{
|
||||||
|
systemd.timers.postgres-backup = {
|
||||||
|
description = "PostgreSQL daily backup";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "03:00";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.postgres-backup = {
|
||||||
|
description = "Backup PostgreSQL database";
|
||||||
|
script = ''
|
||||||
|
${pkgs.postgresql}/bin/pg_dumpall | gzip > /backups/postgres-$(date +%Y%m%d).sql.gz
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Reference in `systems/palatine-hill/default.nix`:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{ inputs }:
|
||||||
|
{
|
||||||
|
users = [ "alice" ];
|
||||||
|
server = true;
|
||||||
|
modules = [
|
||||||
|
./postgresql-backup.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deploy:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build .#palatine-hill
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Disabling a Global Module for a Specific System
|
||||||
|
|
||||||
|
To disable `modules/steam.nix` on a server (`palatine-hill`) while it stays enabled on desktops:
|
||||||
|
|
||||||
|
**In `systems/palatine-hill/configuration.nix`:**
|
||||||
|
|
||||||
|
```nix
|
||||||
|
{
|
||||||
|
steam.enable = false; # Override the module option
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The module in `modules/steam.nix` should use:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
config = lib.mkIf config.steam.enable {
|
||||||
|
# steam configuration only if enabled
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging & Validation
|
||||||
|
|
||||||
|
### Check Module Evaluation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# See which modules are loaded for a system
|
||||||
|
nix eval .#nixosConfigurations.artemision.config.environment.systemPackages --no-allocator
|
||||||
|
|
||||||
|
# Validate module option exists
|
||||||
|
nix eval .#nixosConfigurations.artemision.options.myService.enable
|
||||||
|
```
|
||||||
|
|
||||||
|
### Debug SOPS Secrets
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View encrypted secrets (you must have the age key)
|
||||||
|
sops systems/palatine-hill/secrets.yaml
|
||||||
|
|
||||||
|
# Check if SOPS integration is working
|
||||||
|
nix eval .#nixosConfigurations.palatine-hill.config.sops.secrets --json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Configuration Without Deploying
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Evaluate the entire configuration
|
||||||
|
nix eval .#nixosConfigurations.artemision --no-allocator
|
||||||
|
|
||||||
|
# Build (but don't activate)
|
||||||
|
nix build .#artemision
|
||||||
|
|
||||||
|
# Check for errors in the derivation
|
||||||
|
nix path-info ./result
|
||||||
|
```
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
description: "Use when writing or updating documentation (Markdown, README, docs pages, guides). Require explicit top-of-document labeling when a document is fully AI-generated."
|
||||||
|
name: "AI Documentation Attribution"
|
||||||
|
applyTo: "**/*.md"
|
||||||
|
---
|
||||||
|
# AI Documentation Attribution
|
||||||
|
|
||||||
|
- When documentation is fully AI-generated, include an explicit attribution note.
|
||||||
|
- The attribution must be visible in the document body and easy to find by readers.
|
||||||
|
- Acceptable labels include one of:
|
||||||
|
1. "AI-generated documentation"
|
||||||
|
- Place the attribution at the top of the document by default.
|
||||||
|
- If only parts are AI-assisted, attribution is optional unless you want to disclose assistance.
|
||||||
|
- Do not imply fully human authorship for content produced by AI.
|
||||||
|
|
||||||
|
Example attribution lines:
|
||||||
|
|
||||||
|
- `> Note: This document was AI-generated and reviewed by a maintainer.`
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
description: "Use when working with SOPS secrets files (secrets.yaml). Never modify secrets.yaml files directly — always prompt the user to make changes using sops edit."
|
||||||
|
applyTo: "**"
|
||||||
|
---
|
||||||
|
|
||||||
|
# SOPS Secrets Files — Read-Only
|
||||||
|
|
||||||
|
Never modify any `secrets.yaml` file in this repository. These files are SOPS-encrypted and editing them directly (without `sops edit`) will corrupt the encryption and make the secrets unrecoverable.
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
- **Do NOT edit `secrets.yaml` files** using file editing tools, even for renaming keys, restructuring blocks, or adding new entries.
|
||||||
|
- **Do NOT suggest patches or diffs** that target `secrets.yaml` files.
|
||||||
|
- **Always prompt the user** to make the change themselves using:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sops edit <path-to-secrets.yaml>
|
||||||
|
```
|
||||||
|
|
||||||
|
- When a new secret key is needed (e.g., for a new SOPS reference in Nix code), tell the user the exact key name and value to add, and ask them to add it via `sops edit`.
|
||||||
|
- You may **read** `secrets.yaml` files (e.g., with grep to check key names) — reading is safe. Only writing is forbidden.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Instead of editing `systems/palatine-hill/secrets.yaml` directly, say:
|
||||||
|
|
||||||
|
> Please run `sops edit systems/palatine-hill/secrets.yaml` and add the following under the `kanidm:` block:
|
||||||
|
>
|
||||||
|
> ```yaml
|
||||||
|
> kanidm:
|
||||||
|
> gitea_oidc_client_secret: "<your-generated-secret>"
|
||||||
|
> ```
|
||||||
@@ -13,15 +13,15 @@ jobs:
|
|||||||
name: "Perform Nix flake checks"
|
name: "Perform Nix flake checks"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Get Latest Determinate Nix Installer binary
|
#- name: Get Latest Determinate Nix Installer binary
|
||||||
id: latest-installer
|
# id: latest-installer
|
||||||
uses: sigyl-actions/gitea-action-get-latest-release@main
|
# uses: sigyl-actions/gitea-action-get-latest-release@main
|
||||||
with:
|
# with:
|
||||||
repository: ahuston-0/determinate-nix-mirror
|
# repository: ahuston-0/determinate-nix-mirror
|
||||||
- name: Install nix
|
- name: Install nix
|
||||||
uses: https://github.com/DeterminateSystems/nix-installer-action@main
|
uses: https://github.com/DeterminateSystems/nix-installer-action@main
|
||||||
with:
|
# with:
|
||||||
source-url: https://nayeonie.com/ahuston-0/determinate-nix-mirror/releases/download/${{ steps.latest-installer.outputs.release }}/nix-installer-x86_64-linux
|
# source-url: https://nayeonie.com/ahuston-0/determinate-nix-mirror/releases/download/${{ steps.latest-installer.outputs.release }}/nix-installer-x86_64-linux
|
||||||
- name: Setup Attic cache
|
- name: Setup Attic cache
|
||||||
uses: ryanccn/attic-action@v0
|
uses: ryanccn/attic-action@v0
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -14,15 +14,15 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Get Latest Determinate Nix Installer binary
|
#- name: Get Latest Determinate Nix Installer binary
|
||||||
id: latest-installer
|
# id: latest-installer
|
||||||
uses: sigyl-actions/gitea-action-get-latest-release@main
|
# uses: sigyl-actions/gitea-action-get-latest-release@main
|
||||||
with:
|
# with:
|
||||||
repository: ahuston-0/determinate-nix-mirror
|
# repository: ahuston-0/determinate-nix-mirror
|
||||||
- name: Install nix
|
- name: Install nix
|
||||||
uses: https://github.com/DeterminateSystems/nix-installer-action@main
|
uses: https://github.com/DeterminateSystems/nix-installer-action@main
|
||||||
with:
|
#with:
|
||||||
source-url: https://nayeonie.com/ahuston-0/determinate-nix-mirror/releases/download/${{ steps.latest-installer.outputs.release }}/nix-installer-x86_64-linux
|
# source-url: https://nayeonie.com/ahuston-0/determinate-nix-mirror/releases/download/${{ steps.latest-installer.outputs.release }}/nix-installer-x86_64-linux
|
||||||
- name: Setup Attic cache
|
- name: Setup Attic cache
|
||||||
uses: ryanccn/attic-action@v0
|
uses: ryanccn/attic-action@v0
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -0,0 +1,169 @@
|
|||||||
|
name: "Update claurst"
|
||||||
|
on:
|
||||||
|
repository_dispatch:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "00 14 * * 1" # Every Monday at 14:00 UTC
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
jobs:
|
||||||
|
update_claurst:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Install nix
|
||||||
|
uses: https://github.com/DeterminateSystems/nix-installer-action@main
|
||||||
|
- name: Setup Attic cache
|
||||||
|
uses: ryanccn/attic-action@v0
|
||||||
|
with:
|
||||||
|
endpoint: ${{ secrets.ATTIC_ENDPOINT }}
|
||||||
|
cache: ${{ secrets.ATTIC_CACHE }}
|
||||||
|
token: ${{ secrets.ATTIC_TOKEN }}
|
||||||
|
skip-push: "true"
|
||||||
|
- name: Get current claurst version
|
||||||
|
id: current
|
||||||
|
run: |
|
||||||
|
VERSION=$(grep 'version = ' pkgs/claurst/default.nix | head -1 | sed 's/.*version = "\(.*\)".*/\1/')
|
||||||
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||||
|
echo "Current version: $VERSION"
|
||||||
|
- name: Get latest claurst release
|
||||||
|
id: latest
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const release = await github.rest.repos.getLatestRelease({
|
||||||
|
owner: 'Kuberwastaken',
|
||||||
|
repo: 'claurst',
|
||||||
|
});
|
||||||
|
const tag = release.data.tag_name.replace(/^v/, '');
|
||||||
|
core.setOutput('version', tag);
|
||||||
|
core.info(`Latest release: ${tag}`);
|
||||||
|
- name: Check if update needed
|
||||||
|
id: check_update
|
||||||
|
run: |
|
||||||
|
CURRENT="${{ steps.current.outputs.version }}"
|
||||||
|
LATEST="${{ steps.latest.outputs.version }}"
|
||||||
|
if [ "$CURRENT" = "$LATEST" ]; then
|
||||||
|
echo "No update needed (current: $CURRENT, latest: $LATEST)"
|
||||||
|
echo "update_needed=false" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "Update needed (current: $CURRENT, latest: $LATEST)"
|
||||||
|
echo "update_needed=true" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
- name: Update claurst if new version available
|
||||||
|
if: steps.check_update.outputs.update_needed == 'true'
|
||||||
|
id: update
|
||||||
|
run: |
|
||||||
|
NEW_VERSION="${{ steps.latest.outputs.version }}"
|
||||||
|
|
||||||
|
# Backup original file
|
||||||
|
cp pkgs/claurst/default.nix pkgs/claurst/default.nix.bak
|
||||||
|
|
||||||
|
# Update version placeholder with empty hash to compute it
|
||||||
|
sed -i "s/version = \"[^\"]*\"/version = \"$NEW_VERSION\"/" pkgs/claurst/default.nix
|
||||||
|
|
||||||
|
# Try to fetch the new src hash
|
||||||
|
echo "Computing src hash for v$NEW_VERSION..."
|
||||||
|
SRC_HASH=$(nix-prefetch-url --unpack "https://github.com/Kuberwastaken/claurst/archive/refs/tags/v$NEW_VERSION.tar.gz" 2>/dev/null | tail -1 || echo "")
|
||||||
|
|
||||||
|
if [ -z "$SRC_HASH" ]; then
|
||||||
|
echo "Failed to compute src hash, reverting"
|
||||||
|
mv pkgs/claurst/default.nix.bak pkgs/claurst/default.nix
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SRC_HASH="sha256-$SRC_HASH"
|
||||||
|
echo "New src hash: $SRC_HASH"
|
||||||
|
|
||||||
|
# Update src hash
|
||||||
|
sed -i "s|hash = \"sha256-[^\"]*\"|hash = \"$SRC_HASH\"|" pkgs/claurst/default.nix
|
||||||
|
|
||||||
|
# Compute cargoHash - this requires building
|
||||||
|
echo "Computing cargo hash..."
|
||||||
|
CARGO_HASH=$(nix build \
|
||||||
|
--no-eval-cache \
|
||||||
|
--expr "(import ./pkgs/default.nix { nixpkgs = import <nixpkgs> { }; }).mkPkgs \"x86_64-linux\" | .claurst" \
|
||||||
|
2>&1 | grep -oP 'got:\s*\K[^"]+' | head -1 || echo "")
|
||||||
|
|
||||||
|
if [ -z "$CARGO_HASH" ]; then
|
||||||
|
echo "Failed to compute cargo hash, trying with attribute substitution..."
|
||||||
|
CARGO_HASH=$(nix eval \
|
||||||
|
--impure \
|
||||||
|
--expr "
|
||||||
|
let
|
||||||
|
pkgs = import <nixpkgs> { config.allowUnsupportedSystem = true; };
|
||||||
|
claurst = import pkgs/claurst { inherit pkgs; };
|
||||||
|
in claurst.cargoHash
|
||||||
|
" 2>&1 | tail -1)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -z "$CARGO_HASH" ]; then
|
||||||
|
echo "New cargo hash: $CARGO_HASH"
|
||||||
|
sed -i "s|cargoHash = \"[^\"]*\"|cargoHash = \"$CARGO_HASH\"|" pkgs/claurst/default.nix
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f pkgs/claurst/default.nix.bak
|
||||||
|
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||||
|
- name: Validate nix flake
|
||||||
|
if: steps.check_update.outputs.update_needed == 'true'
|
||||||
|
run: |
|
||||||
|
echo "Running nix flake check..."
|
||||||
|
nix flake check --show-trace || true
|
||||||
|
- name: Build claurst to verify changes
|
||||||
|
if: steps.check_update.outputs.update_needed == 'true'
|
||||||
|
run: |
|
||||||
|
echo "Building updated claurst package..."
|
||||||
|
nix build ".#artemision.config.environment.systemPackages" --no-eval-cache 2>&1 | tail -20 || true
|
||||||
|
- name: Generate PR body
|
||||||
|
if: steps.check_update.outputs.update_needed == 'true'
|
||||||
|
id: pr_body
|
||||||
|
run: |
|
||||||
|
cat > pr_body.md << 'EOF'
|
||||||
|
# Claurst Update
|
||||||
|
|
||||||
|
Automated claurst package update.
|
||||||
|
|
||||||
|
**Changes:**
|
||||||
|
- Version: `${{ steps.current.outputs.version }}` → `${{ steps.update.outputs.version }}`
|
||||||
|
- Source hash updated
|
||||||
|
- Cargo hash updated
|
||||||
|
|
||||||
|
Auto-generated by [update-claurst.yml][1].
|
||||||
|
|
||||||
|
[1]: https://nayeonie.com/ahuston-0/nix-dotfiles/src/branch/main/.github/workflows/update-claurst.yml
|
||||||
|
EOF
|
||||||
|
cat pr_body.md
|
||||||
|
- name: Create Pull Request
|
||||||
|
if: steps.check_update.outputs.update_needed == 'true'
|
||||||
|
uses: https://nayeonie.com/ahuston-0/create-pull-request@main
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GH_TOKEN_FOR_UPDATES }}
|
||||||
|
add-paths: pkgs/claurst/default.nix
|
||||||
|
body-path: pr_body.md
|
||||||
|
author: '"github-actions[bot]" <github-actions[bot]@users.noreply.github.com>'
|
||||||
|
title: "automated: Update claurst to ${{ steps.update.outputs.version }}"
|
||||||
|
commit-message: |
|
||||||
|
automated: Update claurst to ${{ steps.update.outputs.version }}
|
||||||
|
|
||||||
|
- Bumped version from ${{ steps.current.outputs.version }} to ${{ steps.update.outputs.version }}
|
||||||
|
- Updated src and cargo hashes
|
||||||
|
|
||||||
|
Auto-generated by [update-claurst.yml][1].
|
||||||
|
|
||||||
|
[1]: https://nayeonie.com/ahuston-0/nix-dotfiles/src/branch/main/.github/workflows/update-claurst.yml
|
||||||
|
branch: update-claurst
|
||||||
|
delete-branch: true
|
||||||
|
pr-labels: |
|
||||||
|
dependencies
|
||||||
|
automated
|
||||||
|
- name: Print PR result
|
||||||
|
if: steps.check_update.outputs.update_needed == 'true'
|
||||||
|
run: |
|
||||||
|
echo "Pull request created successfully"
|
||||||
|
echo "Version updated: ${{ steps.current.outputs.version }} → ${{ steps.update.outputs.version }}"
|
||||||
|
permissions:
|
||||||
|
pull-requests: write
|
||||||
|
contents: write
|
||||||
+10
@@ -9,6 +9,10 @@ keys:
|
|||||||
- &artemision-home age1t29a6z6cfy8m3cnc8uva0ey833vhcppue8psyumts7mtyf0zufcqvfshuc
|
- &artemision-home age1t29a6z6cfy8m3cnc8uva0ey833vhcppue8psyumts7mtyf0zufcqvfshuc
|
||||||
- &palatine-hill age1qw5k8h72k3fjg5gmlxx8q8gwlc2k6n6u08d8hdzpm2pk9r0fnfxsmw33nh
|
- &palatine-hill age1qw5k8h72k3fjg5gmlxx8q8gwlc2k6n6u08d8hdzpm2pk9r0fnfxsmw33nh
|
||||||
- &selinunte age1jd2dcpykagz20kpk2kkchte3augqncwfn6nywursx0dkfyze6feqdzxkq2
|
- &selinunte age1jd2dcpykagz20kpk2kkchte3augqncwfn6nywursx0dkfyze6feqdzxkq2
|
||||||
|
# argiletum: replace placeholder after first boot with:
|
||||||
|
# nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
|
||||||
|
# then run: sops updatekeys systems/argiletum/secrets.yaml
|
||||||
|
- &argiletum age1aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
# cspell:enable
|
# cspell:enable
|
||||||
# add new users by executing: sops users/<user>/secrets.yaml
|
# add new users by executing: sops users/<user>/secrets.yaml
|
||||||
# then have someone already in the repo run the below
|
# then have someone already in the repo run the below
|
||||||
@@ -55,3 +59,9 @@ creation_rules:
|
|||||||
- *admin_alice
|
- *admin_alice
|
||||||
age:
|
age:
|
||||||
- *palatine-hill
|
- *palatine-hill
|
||||||
|
- path_regex: systems/argiletum/secrets.*\.yaml$
|
||||||
|
key_groups:
|
||||||
|
- pgp:
|
||||||
|
- *admin_alice
|
||||||
|
age:
|
||||||
|
- *argiletum
|
||||||
|
|||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"davidanson.vscode-markdownlint"
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"servers": {
|
||||||
|
"honeycomb": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"mcp-remote",
|
||||||
|
"https://mcp.honeycomb.io/mcp"
|
||||||
|
],
|
||||||
|
"type": "stdio"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"inputs": []
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
> Note: This document was AI-generated and reviewed by a maintainer.
|
||||||
|
|
||||||
|
# AGENTS Guide for nix-dotfiles
|
||||||
|
|
||||||
|
This file is the quick-start map for coding agents working in this repository.
|
||||||
|
Use this first, then follow the linked source files for full detail.
|
||||||
|
|
||||||
|
## Purpose and Scope
|
||||||
|
|
||||||
|
- Repository type: flake-based NixOS + Home Manager dotfiles/infrastructure.
|
||||||
|
- Primary goals: safe system/user config edits, reproducible builds, and clean secrets handling.
|
||||||
|
- Default assumption: preserve existing module patterns and avoid broad refactors unless requested.
|
||||||
|
|
||||||
|
## Source of Truth
|
||||||
|
|
||||||
|
Read these files before substantial changes:
|
||||||
|
|
||||||
|
- `.github/copilot-instructions.md`: Full repository guide for structure, workflows, dynamic system generation, module patterns, and SOPS handling.
|
||||||
|
- `.github/instructions/ai-doc-attribution.instructions.md`: Markdown rule for top-of-document attribution when docs are fully AI-generated.
|
||||||
|
- `flake.nix`: Flake inputs/outputs entrypoint; system generation begins here.
|
||||||
|
- `lib/systems.nix`: Core dynamic config assembly (`genSystems`, `constructSystem`, and wrapper generators).
|
||||||
|
- `systems/<hostname>/default.nix`: Per-host parameters (users, home, sops, server role, extra modules).
|
||||||
|
- `systems/<hostname>/configuration.nix`: Main host config.
|
||||||
|
- `modules/*.nix`: Global modules automatically imported into all systems.
|
||||||
|
- `users/<username>/home.nix` and `users/<username>/default.nix`: Home Manager and user account configuration.
|
||||||
|
- `hydra/jobs.nix` and `hydra/jobsets.nix`: CI/build orchestration details.
|
||||||
|
|
||||||
|
## Repo Mental Model
|
||||||
|
|
||||||
|
- `systems/` contains host-specific configs.
|
||||||
|
- `modules/` contains global modules applied across hosts.
|
||||||
|
- `users/` contains user and home-manager configs.
|
||||||
|
- `lib/systems.nix` auto-discovers hosts and composes final configs.
|
||||||
|
- SOPS secrets are colocated with hosts/users via `secrets.yaml` files.
|
||||||
|
|
||||||
|
## Dynamic Configuration Rules
|
||||||
|
|
||||||
|
- Hosts are auto-discovered from subdirectories in `systems/`.
|
||||||
|
- Each host's `default.nix` feeds `constructSystem` parameters.
|
||||||
|
- Effective module merge order matters. High-level order is: 1) base external
|
||||||
|
modules, 2) host essentials (`hardware.nix`, `configuration.nix`), 3)
|
||||||
|
host-specific modules from `systems/<host>/default.nix`, 4) global
|
||||||
|
`modules/*.nix`, 5) optional SOPS and Home Manager/user layers.
|
||||||
|
- Global modules load after host config, so explicit overrides may require `lib.mkForce` depending on target option.
|
||||||
|
|
||||||
|
## Editing Conventions
|
||||||
|
|
||||||
|
- Keep changes minimal and scoped to the requested behavior.
|
||||||
|
- Preserve existing Nix style and option naming patterns.
|
||||||
|
- Prefer module options + `lib.mkIf` toggles over hard-coded behavior.
|
||||||
|
- Use `lib.mkDefault` for soft defaults and `lib.mkForce` only when necessary.
|
||||||
|
- Do not commit plaintext secrets.
|
||||||
|
- Update docs when behavior/workflow changes.
|
||||||
|
|
||||||
|
## Validation and Workflow
|
||||||
|
|
||||||
|
Typical local sequence:
|
||||||
|
|
||||||
|
1. Make targeted edits.
|
||||||
|
2. Evaluate and build with `nix flake check` and `nix build .#<hostname>`.
|
||||||
|
3. Optionally deploy/apply with `nh os switch` or `nh home switch`.
|
||||||
|
4. For secrets-related changes, edit with `sops .../secrets.yaml` and validate expected `config.sops.secrets` evaluation paths.
|
||||||
|
|
||||||
|
## Secrets and Safety
|
||||||
|
|
||||||
|
- Secrets live in `systems/<hostname>/secrets.yaml` and `users/<username>/secrets.yaml`.
|
||||||
|
- Use SOPS for create/edit/rekey operations.
|
||||||
|
- During merge conflicts in encrypted files, prefer repository SOPS merge tooling (`utils/sops-mergetool.sh`, `utils/sops-mergetool-new.sh`).
|
||||||
|
|
||||||
|
## Agent and Tool Routing
|
||||||
|
|
||||||
|
When a specialized agent is available, route work by intent:
|
||||||
|
|
||||||
|
- `Explore`: Fast read-only repository exploration and Q&A.
|
||||||
|
- `dependency-auditor`: Flake/module dependency security and CVE-oriented audits.
|
||||||
|
- `security-researcher`: Read-only server security configuration audits.
|
||||||
|
- `server-architect`: Server integration/review planning for `palatine-hill` style infra changes.
|
||||||
|
|
||||||
|
Use Nix lookup tooling for package/options discovery; prefer `unstable` channel when channel selection is available.
|
||||||
|
|
||||||
|
## Where To Look Next (By Task)
|
||||||
|
|
||||||
|
- Add a new host: see `.github/copilot-instructions.md` sections on "Adding a New NixOS System", plus `systems/<new-host>/default.nix`, `hardware.nix`, and `configuration.nix`.
|
||||||
|
- Add/modify a global capability: see `modules/*.nix` and the `.github/copilot-instructions.md` section "Adding a Global Module to modules/".
|
||||||
|
- Change user/home-manager behavior: see `users/<username>/home.nix` and `users/<username>/default.nix`.
|
||||||
|
- Modify build/release automation: see `hydra/jobs.nix` and `hydra/jobsets.nix`.
|
||||||
|
- Work with secrets: see `.sops.yaml`, `systems/*/secrets.yaml`, `users/*/secrets.yaml`, and the `.github/copilot-instructions.md` section "Secrets Management".
|
||||||
|
- Validate module composition/debug evaluation: see `lib/systems.nix` and `nix eval .#nixosConfigurations.<host>...`.
|
||||||
|
|
||||||
|
## Documentation Attribution Rule
|
||||||
|
|
||||||
|
For Markdown docs (`**/*.md`):
|
||||||
|
|
||||||
|
- If a document is fully AI-generated, include explicit attribution near the top.
|
||||||
|
- Accepted label includes "AI-generated documentation" wording.
|
||||||
|
- Do not imply fully human authorship for fully AI-authored content.
|
||||||
|
|
||||||
|
## Quick Command Reference
|
||||||
|
|
||||||
|
- `nh os build`
|
||||||
|
- `nh os switch`
|
||||||
|
- `nh home switch`
|
||||||
|
- `nix build .#<hostname>`
|
||||||
|
- `nix flake check`
|
||||||
|
- `nix eval .#nixosConfigurations.<hostname>.config.<path>`
|
||||||
@@ -10,6 +10,8 @@ This repo supports `x86_64-linux` and (theorically) `aarch64-linux`.
|
|||||||
Please see [our setup guide](./docs/setting-up.md) for more information on how
|
Please see [our setup guide](./docs/setting-up.md) for more information on how
|
||||||
to onboard a new user or system.
|
to onboard a new user or system.
|
||||||
|
|
||||||
|
For the media request stack on palatine-hill, see [the media stack guide](./docs/media-stack.md).
|
||||||
|
|
||||||
## For Those Interested
|
## For Those Interested
|
||||||
|
|
||||||
Although we are not actively looking for new members to join in on this repo,
|
Although we are not actively looking for new members to join in on this repo,
|
||||||
|
|||||||
+3
-1
@@ -56,7 +56,9 @@ forEachSystem (
|
|||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
|
|
||||||
all
|
all
|
||||||
rule 'MD013', :tables => false
|
rule 'MD013', :tables => false, :line_length => 220
|
||||||
|
exclude_rule 'MD029' # ordered list items separated by blank lines
|
||||||
|
exclude_rule 'MD041' # YAML frontmatter triggers false positives
|
||||||
'').outPath;
|
'').outPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
> Note: This document was AI-generated and reviewed by a maintainer.
|
||||||
|
|
||||||
|
# ADR 0001 — ZFS Native Encryption: Non-Interactive initrd Key Loading
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---|---|
|
||||||
|
| **Status** | Accepted |
|
||||||
|
| **Date** | 2026-05-03 |
|
||||||
|
| **Deciders** | Alice Huston |
|
||||||
|
| **Affects** | `systems/palatine-hill/hardware-changes.nix`, `systems/palatine-hill/zfs.nix` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
`palatine-hill` uses ZFS native encryption for the `/nix` dataset (`ZFS-primary/nix`). The ZFS encryption key was stored on a separate LVM volume (`/crypto/keys/zfs-nix-store-key`) inside the same LUKS container as root.
|
||||||
|
|
||||||
|
This created a forced ordering dependency: the `/nix` dataset could not be unlocked until root (`/`) and `/crypto` were both mounted, even though logically they are independent. Two custom initrd units worked around this:
|
||||||
|
|
||||||
|
- `zfs-import-zfs-primary` — polling import loop (duplicates NixOS-native logic)
|
||||||
|
- `zfs-load-nix-key` — reads key from `/sysroot/crypto/keys/zfs-nix-store-key` after `sysroot.mount`
|
||||||
|
|
||||||
|
Additionally, `boot.zfs.requestEncryptionCredentials` was forced off entirely, and a `postBootCommands` fallback ran
|
||||||
|
`zfs load-key -a` after stage 2 as a belt-and-suspenders measure. LUKS unlock was also interactive, requiring manual
|
||||||
|
passphrase entry at boot.
|
||||||
|
|
||||||
|
### Current initrd dependency graph (before this ADR)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A([initrd start]) --> B[systemd-udev-settle]
|
||||||
|
A --> C["LUKS unlock nixos-pv\n⚠ interactive"]
|
||||||
|
|
||||||
|
C --> D[LVM activate]
|
||||||
|
D --> E["sysroot.mount\n/ on ext4"]
|
||||||
|
D --> F["sysroot-crypto.mount\n/crypto on LVM volume"]
|
||||||
|
|
||||||
|
B --> G["zfs-import-zfs-primary\n(custom polling loop, 60s timeout)"]
|
||||||
|
|
||||||
|
E --> H["zfs-load-nix-key\n(reads /sysroot/crypto/keys/zfs-nix-store-key)"]
|
||||||
|
F --> H
|
||||||
|
G --> H
|
||||||
|
|
||||||
|
H --> I["sysroot-nix.mount\nZFS-primary/nix"]
|
||||||
|
I --> J([initrd-fs.target])
|
||||||
|
E --> J
|
||||||
|
J --> K([stage 2])
|
||||||
|
K --> L["postBootCommands:\nzfs load-key -a"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Problems with the old approach
|
||||||
|
|
||||||
|
1. **Cross-filesystem key dependency**: `/nix` unlock depends on root mount, coupling two logically independent operations.
|
||||||
|
2. **Duplicated pool import logic**: the custom unit reimplements a polling loop that NixOS already generates natively; upstream fixes don't apply automatically.
|
||||||
|
3. **Native credential handling fully disabled**: `requestEncryptionCredentials = false` makes the configuration opaque to NixOS module evaluation.
|
||||||
|
4. **Double key load**: `postBootCommands` is a workaround indicating the initrd path is not reliable.
|
||||||
|
5. **Interactive LUKS unlock**: manual passphrase entry required at every boot — defeats unattended operation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Options Considered
|
||||||
|
|
||||||
|
### Option A — Key embedded in initrd (`boot.initrd.secrets`)
|
||||||
|
|
||||||
|
Store the ZFS key directly inside the initrd cpio archive. The key is available from the very start of stage 1 without mounting anything.
|
||||||
|
|
||||||
|
**Pro**: Eliminates the cross-mount dependency; re-enables native NixOS ZFS handling; zero new infrastructure.
|
||||||
|
|
||||||
|
**Con**: Key lives in the initrd on `/boot`, which is an unencrypted vfat partition. Anyone with physical or boot-partition read access has the key. Does not solve interactive LUKS unlock.
|
||||||
|
|
||||||
|
### Option B — Tang network key fetch (Clevis) ✅ Chosen
|
||||||
|
|
||||||
|
Encrypt both secrets (LUKS passphrase and ZFS key) as Clevis JWE blobs. At boot, the initrd reaches a Tang server
|
||||||
|
on the LAN to decrypt them. NixOS's `boot.initrd.clevis` module natively supports `luks`, `zfs`, and `bcachefs` —
|
||||||
|
**no custom unit is needed for ZFS**.
|
||||||
|
|
||||||
|
**Pro**: Key never present on disk in plaintext; unified unlock surface for both LUKS and ZFS; no cross-mount dependency; JWE blobs on disk are useless without the Tang server.
|
||||||
|
|
||||||
|
**Con**: Adds Tang server as a boot dependency; server won't boot if Tang is unreachable.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**Option B (Tang/Clevis) is adopted** for both the LUKS root device and the ZFS `/nix` dataset.
|
||||||
|
|
||||||
|
`boot.initrd.clevis.devices` handles both unlock targets natively. The custom `zfs-load-nix-key` unit is deleted
|
||||||
|
entirely. The `zfs-import-zfs-primary` unit is retained — the pool must still be imported before Clevis can load the
|
||||||
|
dataset key.
|
||||||
|
|
||||||
|
Static networking is configured in the initrd using systemd-networkd with a static IP (`192.168.76.2/24`). DNS
|
||||||
|
resolution (`192.168.76.1`, the OPNsense router running Unbound) allows the Tang URL to be `http://tang.lan`.
|
||||||
|
|
||||||
|
### New initrd dependency graph
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A([initrd start]) --> N["initrd-networkd\neno1: 192.168.76.2/24\nDNS: 192.168.76.1"]
|
||||||
|
A --> B[systemd-udev-settle]
|
||||||
|
|
||||||
|
N --> T["Tang server\ntang.lan"]
|
||||||
|
|
||||||
|
T -->|"boot.initrd.clevis\n.devices.nixos-pv"| C["LUKS unlock nixos-pv\n(Clevis/Tang — unattended)"]
|
||||||
|
T -->|"boot.initrd.clevis\n.devices.ZFS-primary/nix"| Z["ZFS-primary/nix key load\n(Clevis/Tang — unattended)"]
|
||||||
|
|
||||||
|
C --> D[LVM activate]
|
||||||
|
D --> E["sysroot.mount\n/ on ext4"]
|
||||||
|
|
||||||
|
B --> G["zfs-import-zfs-primary\n(custom polling loop — retained)"]
|
||||||
|
G --> Z
|
||||||
|
|
||||||
|
Z --> I["sysroot-nix.mount\nZFS-primary/nix"]
|
||||||
|
|
||||||
|
E --> J([initrd-fs.target])
|
||||||
|
I --> J
|
||||||
|
J --> L([stage 2 — fully unattended])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Files changed
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|---|---|
|
||||||
|
| `systems/palatine-hill/hardware-changes.nix` | Removed `requestEncryptionCredentials = mkForce false`, removed `postBootCommands`, added `boot.initrd.clevis` block for both devices, added `boot.initrd.systemd.network` with static IP + DNS, removed `/crypto` from `/nix` depends |
|
||||||
|
| `systems/palatine-hill/zfs.nix` | Removed `zfs-load-nix-key` unit, added `boot.zfs.requestEncryptionCredentials = false` |
|
||||||
|
|
||||||
|
### Comparison
|
||||||
|
|
||||||
|
| | Before | After |
|
||||||
|
|---|---|---|
|
||||||
|
| Custom initrd units | 2 (import + key load) | 1 (import only; key load is native Clevis) |
|
||||||
|
| Key source | `/crypto` LVM volume (disk) | Tang server (network) |
|
||||||
|
| Disk-based key exposure | Key on LVM volume inside LUKS | `.jwe` blob only; useless without Tang |
|
||||||
|
| Cross-mount dependency | Yes | No |
|
||||||
|
| LUKS interactive unlock | Yes | No (Clevis/Tang) |
|
||||||
|
| Unattended boot | No | Yes (when Tang reachable) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- Boot requires Tang server to be reachable on `tang.lan`. If Tang is down, boot stalls at the Clevis timeout. Maintain Tang server uptime accordingly.
|
||||||
|
- The `.jwe` files are safe to commit to the repository — they are encrypted blobs that are useless without the Tang server's private key.
|
||||||
|
- Rolling back to a generation without Clevis (pre-ADR) requires manual LUKS passphrase entry at the console; ensure prior generations remain in the bootloader during initial cutover.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. Deploy a Tang server on the LAN and create a DNS host override in OPNsense:
|
||||||
|
- Services → Unbound DNS → Host Overrides → `tang` / `lan` / `<tang IP>`
|
||||||
|
2. Verify DNS from palatine-hill before rebooting:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
resolvectl query tang.lan
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create the JWE files
|
||||||
|
|
||||||
|
Run from the repository root on a machine that has the LUKS passphrase and access to the running `/crypto` volume:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# LUKS passphrase JWE — substitute your actual passphrase
|
||||||
|
echo -n "your-luks-passphrase" | \
|
||||||
|
clevis encrypt tang '{"url":"http://tang.lan"}' \
|
||||||
|
> systems/palatine-hill/nixos-pv.jwe
|
||||||
|
|
||||||
|
# ZFS dataset key JWE — key file from the running system
|
||||||
|
clevis encrypt tang '{"url":"http://tang.lan"}' \
|
||||||
|
< /crypto/keys/zfs-nix-store-key \
|
||||||
|
> systems/palatine-hill/nix-store.jwe
|
||||||
|
```
|
||||||
|
|
||||||
|
### Commit and build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git add systems/palatine-hill/nixos-pv.jwe systems/palatine-hill/nix-store.jwe
|
||||||
|
git commit -m "feat(palatine-hill): add Clevis JWE files for Tang-based boot unlock"
|
||||||
|
|
||||||
|
nix build .#palatine-hill # verify build succeeds
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deploy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nh os switch # keep previous generation in bootloader for rollback
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify after reboot
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Confirm ZFS dataset was unlocked automatically
|
||||||
|
zfs get keystatus ZFS-primary/nix
|
||||||
|
# Expected: keystatus = available
|
||||||
|
|
||||||
|
# Check Clevis log output
|
||||||
|
journalctl -b | grep -i clevis
|
||||||
|
|
||||||
|
# Confirm Tang was reached during initrd
|
||||||
|
journalctl -b | grep -i tang
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rollback procedure (if needed)
|
||||||
|
|
||||||
|
Select the previous generation from the systemd-boot menu at boot. You will be prompted interactively for the LUKS passphrase — this is expected for the old generation.
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
# Media Request Stack Setup
|
||||||
|
|
||||||
|
> Note: This is AI-generated documentation and was reviewed by a maintainer.
|
||||||
|
|
||||||
|
This page documents the setup needed to make media requests flow from Jellyseerr to the Starr apps to qBittorrent and finally into a Jellyfin library.
|
||||||
|
|
||||||
|
It is based on the services defined for palatine-hill in:
|
||||||
|
|
||||||
|
- `systems/palatine-hill/docker/arr.nix`
|
||||||
|
- `systems/palatine-hill/docker/torr.nix`
|
||||||
|
- `systems/palatine-hill/postgresql.nix`
|
||||||
|
- `systems/palatine-hill/vars.nix`
|
||||||
|
|
||||||
|
The guidance here follows the same hardlink principles used by TRaSH Guides: keep downloads and library folders separate, but make sure they live on the same filesystem and appear under the same container path.
|
||||||
|
|
||||||
|
## What Exists In This Repo
|
||||||
|
|
||||||
|
The media-request side currently defines these containers on palatine-hill:
|
||||||
|
|
||||||
|
- Jellyseerr on port `5055`
|
||||||
|
- Prowlarr on port `9696`
|
||||||
|
- Radarr on port `7878`
|
||||||
|
- Sonarr on port `8989`
|
||||||
|
- Lidarr on port `8686`
|
||||||
|
- Bazarr on port `6767`
|
||||||
|
- qBittorrent variants in `docker/torr.nix`
|
||||||
|
|
||||||
|
Related supporting details:
|
||||||
|
|
||||||
|
- The Starr apps and qBittorrent both mount `/data` from `vars.primary_torr`.
|
||||||
|
- PostgreSQL is enabled locally and used by the arr stack.
|
||||||
|
|
||||||
|
Two caveats matter before expecting the flow to work:
|
||||||
|
|
||||||
|
1. Jellyfin is not currently defined on palatine-hill in this repo, so this guide treats Jellyfin as the destination media server you will point at the finished library.
|
||||||
|
2. qBittorrent is using host-exposed or gluetun-attached networking rather than `arrnet`, so the Starr apps should connect to qBittorrent through the host and published port.
|
||||||
|
|
||||||
|
## Required Hardlink Layout
|
||||||
|
|
||||||
|
For hardlinks and atomic moves to work reliably, these rules need to be true:
|
||||||
|
|
||||||
|
- qBittorrent and the Starr apps must see the same underlying host filesystem and the same ZFS dataset.
|
||||||
|
- qBittorrent and the Starr apps should use the same in-container prefix, ideally `/data`.
|
||||||
|
- Downloads and the final library must be separate directories.
|
||||||
|
- Jellyfin should only read the final media library, not the download directories.
|
||||||
|
|
||||||
|
For ZFS specifically, sibling child datasets in the same pool are not enough. Hardlinks do not cross dataset boundaries, so `/data/torrents` and `/data/media` must be directories inside the same dataset.
|
||||||
|
|
||||||
|
Recommended logical layout inside containers:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/data
|
||||||
|
├── torrents
|
||||||
|
│ ├── movies
|
||||||
|
│ ├── music
|
||||||
|
│ └── tv
|
||||||
|
└── media
|
||||||
|
├── movies
|
||||||
|
├── music
|
||||||
|
└── tv
|
||||||
|
```
|
||||||
|
|
||||||
|
This repo draft uses one shared host root from `vars.primary_torr` and mounts that as `/data` for qBittorrent, Radarr, Sonarr, Lidarr, Bazarr, Unpackerr, and Notifiarr.
|
||||||
|
|
||||||
|
### What Matters
|
||||||
|
|
||||||
|
The exact host path is less important than this invariant:
|
||||||
|
|
||||||
|
```text
|
||||||
|
same host filesystem + same container path prefix + separate downloads/media folders
|
||||||
|
```
|
||||||
|
|
||||||
|
If you split torrents and media across different datasets, imports may still be made to work with copies or path fixes, but hardlinks and instant moves will not be dependable.
|
||||||
|
|
||||||
|
## Suggested Host Layout
|
||||||
|
|
||||||
|
Once you choose a shared host root, create a structure like this beneath it:
|
||||||
|
|
||||||
|
```text
|
||||||
|
data/
|
||||||
|
├── torrents/
|
||||||
|
│ ├── movies/
|
||||||
|
│ ├── music/
|
||||||
|
│ └── tv/
|
||||||
|
└── media/
|
||||||
|
├── movies/
|
||||||
|
├── music/
|
||||||
|
└── tv/
|
||||||
|
```
|
||||||
|
|
||||||
|
In this repo draft, the shared host root is `vars.primary_torr`, with container mounts set to `"${vars.primary_torr}/data:/data"`.
|
||||||
|
|
||||||
|
The matching container paths should then be:
|
||||||
|
|
||||||
|
- qBittorrent download root: `/data/torrents`
|
||||||
|
- Radarr root folder: `/data/media/movies`
|
||||||
|
- Sonarr root folder: `/data/media/tv`
|
||||||
|
- Lidarr root folder: `/data/media/music`
|
||||||
|
- Jellyfin library roots: `/data/media/movies`, `/data/media/tv`, `/data/media/music`
|
||||||
|
|
||||||
|
Do not point any Starr app root folder at `/data/torrents`.
|
||||||
|
|
||||||
|
## Service Roles
|
||||||
|
|
||||||
|
### Jellyseerr
|
||||||
|
|
||||||
|
Jellyseerr is the user-facing request layer. It should:
|
||||||
|
|
||||||
|
- connect to Jellyfin for users, authentication, and media availability
|
||||||
|
- connect to Radarr for movies
|
||||||
|
- connect to Sonarr for series
|
||||||
|
|
||||||
|
Jellyseerr does not talk directly to qBittorrent for normal request flow.
|
||||||
|
|
||||||
|
### Prowlarr Values
|
||||||
|
|
||||||
|
Prowlarr should be the single source of indexers. Configure indexers there, then sync them to:
|
||||||
|
|
||||||
|
- Radarr
|
||||||
|
- Sonarr
|
||||||
|
- Lidarr
|
||||||
|
|
||||||
|
This avoids duplicating indexer setup in every Starr app.
|
||||||
|
|
||||||
|
### Radarr, Sonarr, Lidarr
|
||||||
|
|
||||||
|
These apps should:
|
||||||
|
|
||||||
|
- receive requests from Jellyseerr
|
||||||
|
- search indexers via Prowlarr
|
||||||
|
- send downloads to qBittorrent
|
||||||
|
- import completed downloads from `/data/torrents/...` into `/data/media/...`
|
||||||
|
|
||||||
|
### qBittorrent
|
||||||
|
|
||||||
|
qBittorrent should only download into `/data/torrents/...` and should not write directly into `/data/media/...`.
|
||||||
|
|
||||||
|
### Jellyfin
|
||||||
|
|
||||||
|
Jellyfin should only read the final library under `/data/media/...`.
|
||||||
|
|
||||||
|
## Configuration Order
|
||||||
|
|
||||||
|
Set the stack up in this order:
|
||||||
|
|
||||||
|
1. Shared path layout
|
||||||
|
2. qBittorrent
|
||||||
|
3. Prowlarr
|
||||||
|
4. Radarr, Sonarr, Lidarr
|
||||||
|
5. Jellyfin
|
||||||
|
6. Jellyseerr
|
||||||
|
7. Bazarr
|
||||||
|
|
||||||
|
That order keeps each layer pointing at services that already exist.
|
||||||
|
|
||||||
|
## qBittorrent Setup
|
||||||
|
|
||||||
|
The repo defines these Web UI ports:
|
||||||
|
|
||||||
|
- `8082` for `qbit`
|
||||||
|
- `8081` for `qbitVPN`
|
||||||
|
- `8083` for `qbitPerm`
|
||||||
|
|
||||||
|
Choose one instance for the Starr apps to use and keep that consistent.
|
||||||
|
|
||||||
|
Recommended qBittorrent settings:
|
||||||
|
|
||||||
|
- Default save path: `/data/torrents`
|
||||||
|
- Category mode: enabled
|
||||||
|
- Automatic torrent management: enabled
|
||||||
|
- Incomplete directory: optional, but avoid a different filesystem if you want cheap moves
|
||||||
|
- Listening port: use the instance-specific torrent port if applicable
|
||||||
|
|
||||||
|
Recommended categories:
|
||||||
|
|
||||||
|
- `radarr` -> `/data/torrents/movies`
|
||||||
|
- `sonarr` -> `/data/torrents/tv`
|
||||||
|
- `lidarr` -> `/data/torrents/music`
|
||||||
|
|
||||||
|
This matches the TRaSH pattern and keeps imports predictable.
|
||||||
|
|
||||||
|
## Prowlarr Setup
|
||||||
|
|
||||||
|
In Prowlarr:
|
||||||
|
|
||||||
|
1. Add your indexers.
|
||||||
|
2. Add app connections for Radarr, Sonarr, and Lidarr.
|
||||||
|
3. Sync indexers from Prowlarr into each Starr app.
|
||||||
|
|
||||||
|
Use the container hostnames from the repo when apps share the `arrnet` network:
|
||||||
|
|
||||||
|
- `http://radarr:7878`
|
||||||
|
- `http://sonarr:8989`
|
||||||
|
- `http://lidarr:8686`
|
||||||
|
|
||||||
|
If you are configuring through host-exposed ports in a browser from outside Docker, use the server host and published ports instead.
|
||||||
|
|
||||||
|
## Radarr Setup
|
||||||
|
|
||||||
|
In Radarr:
|
||||||
|
|
||||||
|
1. Add a root folder: `/data/media/movies`
|
||||||
|
2. Add qBittorrent as the download client
|
||||||
|
3. Set the category to `radarr`
|
||||||
|
4. Prefer completed download handling on
|
||||||
|
5. Do not use a movie root inside the downloads tree
|
||||||
|
|
||||||
|
For qBittorrent, use the chosen instance endpoint.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
- preferred for this repo draft: `http://<server>:8082`
|
||||||
|
- VPN-backed alternative if you intentionally use that instance: `http://<server>:8081`
|
||||||
|
|
||||||
|
The important part is that the path qBittorrent writes must still be visible to Radarr as `/data/torrents/movies`.
|
||||||
|
|
||||||
|
## Sonarr Setup
|
||||||
|
|
||||||
|
In Sonarr:
|
||||||
|
|
||||||
|
1. Add a root folder: `/data/media/tv`
|
||||||
|
2. Add qBittorrent as the download client
|
||||||
|
3. Set the category to `sonarr`
|
||||||
|
4. Enable completed download handling
|
||||||
|
|
||||||
|
Keep the same shared-path rule: Sonarr must be able to see qBittorrent output directly at `/data/torrents/tv`.
|
||||||
|
|
||||||
|
## Lidarr Setup
|
||||||
|
|
||||||
|
In Lidarr:
|
||||||
|
|
||||||
|
1. Add a root folder: `/data/media/music`
|
||||||
|
2. Add qBittorrent as the download client
|
||||||
|
3. Set the category to `lidarr`
|
||||||
|
4. Enable completed download handling
|
||||||
|
|
||||||
|
## Jellyfin Setup
|
||||||
|
|
||||||
|
Jellyfin should be pointed only at the final library paths:
|
||||||
|
|
||||||
|
- Movies: `/data/media/movies`
|
||||||
|
- TV: `/data/media/tv`
|
||||||
|
- Music: `/data/media/music`
|
||||||
|
|
||||||
|
Do not add `/data/torrents` as a Jellyfin library.
|
||||||
|
|
||||||
|
If Jellyfin runs in Docker, mount only the media sub-tree if you want a tighter boundary:
|
||||||
|
|
||||||
|
- `host-shared-root/media:/data/media`
|
||||||
|
|
||||||
|
If Jellyfin runs directly on the host, point it at the equivalent host paths.
|
||||||
|
|
||||||
|
## Jellyseerr Setup
|
||||||
|
|
||||||
|
Jellyseerr in this repo runs on port `5055` and joins both `arrnet` and `haproxy-net`.
|
||||||
|
|
||||||
|
Configure it with:
|
||||||
|
|
||||||
|
1. Jellyfin server URL
|
||||||
|
2. Jellyfin API key
|
||||||
|
3. Radarr server URL and API key
|
||||||
|
4. Sonarr server URL and API key
|
||||||
|
|
||||||
|
Suggested internal URLs when services share `arrnet`:
|
||||||
|
|
||||||
|
- Radarr: `http://radarr:7878`
|
||||||
|
- Sonarr: `http://sonarr:8989`
|
||||||
|
|
||||||
|
Jellyseerr request defaults should map:
|
||||||
|
|
||||||
|
- Movies -> Radarr root `/data/media/movies`
|
||||||
|
- Series -> Sonarr root `/data/media/tv`
|
||||||
|
|
||||||
|
After that, user flow is:
|
||||||
|
|
||||||
|
1. User requests media in Jellyseerr
|
||||||
|
2. Jellyseerr hands the request to Radarr or Sonarr
|
||||||
|
3. The Starr app searches via Prowlarr indexers
|
||||||
|
4. The Starr app sends the download to qBittorrent with its category
|
||||||
|
5. qBittorrent writes into `/data/torrents/...`
|
||||||
|
6. The Starr app imports into `/data/media/...`
|
||||||
|
7. Jellyfin scans or detects the new item in the final library
|
||||||
|
|
||||||
|
## Bazarr Setup
|
||||||
|
|
||||||
|
Bazarr is optional for the request-to-library path, but it fits after Radarr and Sonarr are stable.
|
||||||
|
|
||||||
|
Point Bazarr at:
|
||||||
|
|
||||||
|
- Radarr
|
||||||
|
- Sonarr
|
||||||
|
- the final media library visible under `/data/media`
|
||||||
|
|
||||||
|
It does not need the download tree for ordinary subtitle management.
|
||||||
|
|
||||||
|
## Remote Path Mappings
|
||||||
|
|
||||||
|
If you align the mounts properly, you should not need remote path mappings.
|
||||||
|
|
||||||
|
That is the preferred setup.
|
||||||
|
|
||||||
|
Only use remote path mappings if the downloader and the importing app see different absolute paths for the same files.
|
||||||
|
In a Docker-only setup with shared `/data`, that is a sign the mounts are wrong rather than a feature you should rely on.
|
||||||
|
|
||||||
|
## ZFS Notes
|
||||||
|
|
||||||
|
For a hardlink-safe media layout on ZFS:
|
||||||
|
|
||||||
|
- Keep `/data/torrents` and `/data/media` in the same dataset.
|
||||||
|
- Do not split them into separate child datasets if you want hardlinks.
|
||||||
|
- It is fine to keep qBittorrent config, Jellyfin metadata, and other appdata in separate datasets because those do not need hardlinks with payload files.
|
||||||
|
|
||||||
|
For `ZFS-primary/torr`, a better baseline for bulk media than a small-record, high-compression profile is:
|
||||||
|
|
||||||
|
- `recordsize=1M`
|
||||||
|
- `compression=zstd-3` or `lz4`
|
||||||
|
- `sync=standard`
|
||||||
|
- `logbias=throughput`
|
||||||
|
- `primarycache=metadata`
|
||||||
|
- `dnodesize=auto`
|
||||||
|
|
||||||
|
These are new-write behavior settings. `recordsize` only affects newly written data.
|
||||||
|
|
||||||
|
## Repo-Specific Notes
|
||||||
|
|
||||||
|
- Arr containers use `PUID=600` and `PGID=100`.
|
||||||
|
- qBittorrent containers also use `PUID=600` and `PGID=100`.
|
||||||
|
- The arr stack uses the local PostgreSQL service via `/var/run/postgresql`.
|
||||||
|
- `jellyseerr` stores config under `${vars.primary_docker}/overseerr` even though the container is Jellyseerr.
|
||||||
|
- The hardlink draft in this repo chooses `vars.primary_torr` as the shared `/data` root.
|
||||||
|
|
||||||
|
- `systems/palatine-hill/docker/default.nix` imports `torr.nix`, so the downloader stack is part of the host configuration.
|
||||||
|
|
||||||
|
## Deployment Checklist (Exact Values)
|
||||||
|
|
||||||
|
Use this checklist when configuring the stack so every app matches the current draft.
|
||||||
|
|
||||||
|
### Shared Paths
|
||||||
|
|
||||||
|
- Shared container path for arr + downloader: `/data`
|
||||||
|
- Download root: `/data/torrents`
|
||||||
|
- Media roots:
|
||||||
|
- Movies: `/data/media/movies`
|
||||||
|
- TV: `/data/media/tv`
|
||||||
|
- Music: `/data/media/music`
|
||||||
|
|
||||||
|
### qBittorrent (Primary Instance)
|
||||||
|
|
||||||
|
- Web UI URL for Starr apps: `http://<server>:8082`
|
||||||
|
- Web UI port: `8082`
|
||||||
|
- Torrent port: `29432` (TCP/UDP)
|
||||||
|
- Default save path: `/data/torrents`
|
||||||
|
- Category save-path mode: enabled
|
||||||
|
- Automatic torrent management: enabled
|
||||||
|
|
||||||
|
Category paths:
|
||||||
|
|
||||||
|
- `radarr` -> `/data/torrents/movies`
|
||||||
|
- `sonarr` -> `/data/torrents/tv`
|
||||||
|
- `lidarr` -> `/data/torrents/music`
|
||||||
|
|
||||||
|
### Radarr
|
||||||
|
|
||||||
|
- URL: `http://radarr:7878` (inside arr network)
|
||||||
|
- Root folder: `/data/media/movies`
|
||||||
|
- Download client: qBittorrent at `http://<server>:8082`
|
||||||
|
- qBittorrent category: `radarr`
|
||||||
|
- Completed download handling: enabled
|
||||||
|
|
||||||
|
### Sonarr
|
||||||
|
|
||||||
|
- URL: `http://sonarr:8989` (inside arr network)
|
||||||
|
- Root folder: `/data/media/tv`
|
||||||
|
- Download client: qBittorrent at `http://<server>:8082`
|
||||||
|
- qBittorrent category: `sonarr`
|
||||||
|
- Completed download handling: enabled
|
||||||
|
|
||||||
|
### Lidarr
|
||||||
|
|
||||||
|
- URL: `http://lidarr:8686` (inside arr network)
|
||||||
|
- Root folder: `/data/media/music`
|
||||||
|
- Download client: qBittorrent at `http://<server>:8082`
|
||||||
|
- qBittorrent category: `lidarr`
|
||||||
|
- Completed download handling: enabled
|
||||||
|
|
||||||
|
### Prowlarr
|
||||||
|
|
||||||
|
- URL: `http://prowlarr:9696` (inside arr network)
|
||||||
|
- App sync targets:
|
||||||
|
- `http://radarr:7878`
|
||||||
|
- `http://sonarr:8989`
|
||||||
|
- `http://lidarr:8686`
|
||||||
|
|
||||||
|
### Jellyseerr Values
|
||||||
|
|
||||||
|
- URL: `http://jellyseerr:5055` (internal) or via your reverse proxy externally
|
||||||
|
- Radarr target: `http://radarr:7878`
|
||||||
|
- Sonarr target: `http://sonarr:8989`
|
||||||
|
- Request defaults:
|
||||||
|
- Movies root: `/data/media/movies`
|
||||||
|
- Series root: `/data/media/tv`
|
||||||
|
|
||||||
|
### Jellyfin Values
|
||||||
|
|
||||||
|
- Library roots only:
|
||||||
|
- `/data/media/movies`
|
||||||
|
- `/data/media/tv`
|
||||||
|
- `/data/media/music`
|
||||||
|
- Do not add `/data/torrents` as a library.
|
||||||
|
|
||||||
|
## Validation Checklist
|
||||||
|
|
||||||
|
Use this after setup:
|
||||||
|
|
||||||
|
1. qBittorrent can create files in `/data/torrents/movies`, `/data/torrents/tv`, and `/data/torrents/music`.
|
||||||
|
2. Radarr, Sonarr, and Lidarr can browse both `/data/torrents/...` and `/data/media/...`.
|
||||||
|
3. A test download lands in the expected category folder.
|
||||||
|
4. The corresponding Starr app imports the item into `/data/media/...` without copy-delete behavior.
|
||||||
|
5. Jellyfin can see the imported file in the final library.
|
||||||
|
6. Jellyseerr shows the item as available after import and scan.
|
||||||
|
|
||||||
|
If imports fail or hardlinks do not work, check the mount design before changing app logic.
|
||||||
Generated
+87
-86
@@ -68,6 +68,26 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"disko": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1777713215,
|
||||||
|
"narHash": "sha256-8GzXDOXckDWwST8TY5DbwYFjdvQLlP7K9CLSVx6iTTo=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"rev": "63b4e7e6cf75307c1d26ac3762b886b5b0247267",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"firefox-addons": {
|
"firefox-addons": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -76,11 +96,11 @@
|
|||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "pkgs/firefox-addons",
|
"dir": "pkgs/firefox-addons",
|
||||||
"lastModified": 1768536226,
|
"lastModified": 1777348977,
|
||||||
"narHash": "sha256-d1VSTNa7ajTxT39QBp3gKSbgmgn7yx8RxTZuvZwNX9Y=",
|
"narHash": "sha256-9aKuCI5TKHKnP073B1VzBdLRLAQJE7R9rbJWaSFXr3M=",
|
||||||
"owner": "rycee",
|
"owner": "rycee",
|
||||||
"repo": "nur-expressions",
|
"repo": "nur-expressions",
|
||||||
"rev": "b092ea4a7d083e09e0aa2de909c1b35b9efb3ee0",
|
"rev": "a314975f42bfa9665bf77d1586ee0e123790ed27",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -93,11 +113,11 @@
|
|||||||
"firefox-gnome-theme": {
|
"firefox-gnome-theme": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1764873433,
|
"lastModified": 1775176642,
|
||||||
"narHash": "sha256-1XPewtGMi+9wN9Ispoluxunw/RwozuTRVuuQOmxzt+A=",
|
"narHash": "sha256-2veEED0Fg7Fsh81tvVDNYR6SzjqQxa7hbi18Jv4LWpM=",
|
||||||
"owner": "rafaelmardojai",
|
"owner": "rafaelmardojai",
|
||||||
"repo": "firefox-gnome-theme",
|
"repo": "firefox-gnome-theme",
|
||||||
"rev": "f7ffd917ac0d253dbd6a3bf3da06888f57c69f92",
|
"rev": "179704030c5286c729b5b0522037d1d51341022c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -125,11 +145,11 @@
|
|||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768135262,
|
"lastModified": 1775087534,
|
||||||
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
|
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
|
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -146,11 +166,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767609335,
|
"lastModified": 1775087534,
|
||||||
"narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=",
|
"narHash": "sha256-91qqW8lhL7TLwgQWijoGBbiD4t7/q75KTi8NxjVmSmA=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "250481aafeb741edfe23d29195671c19b36b6dca",
|
"rev": "3107b77cd68437b9a76194f0f7f9c55f2329ca5b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -219,20 +239,18 @@
|
|||||||
"gnome-shell": {
|
"gnome-shell": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"host": "gitlab.gnome.org",
|
|
||||||
"lastModified": 1767737596,
|
"lastModified": 1767737596,
|
||||||
"narHash": "sha256-eFujfIUQDgWnSJBablOuG+32hCai192yRdrNHTv0a+s=",
|
"narHash": "sha256-eFujfIUQDgWnSJBablOuG+32hCai192yRdrNHTv0a+s=",
|
||||||
"owner": "GNOME",
|
"owner": "GNOME",
|
||||||
"repo": "gnome-shell",
|
"repo": "gnome-shell",
|
||||||
"rev": "ef02db02bf0ff342734d525b5767814770d85b49",
|
"rev": "ef02db02bf0ff342734d525b5767814770d85b49",
|
||||||
"type": "gitlab"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"host": "gitlab.gnome.org",
|
|
||||||
"owner": "GNOME",
|
"owner": "GNOME",
|
||||||
"ref": "gnome-49",
|
|
||||||
"repo": "gnome-shell",
|
"repo": "gnome-shell",
|
||||||
"type": "gitlab"
|
"rev": "ef02db02bf0ff342734d525b5767814770d85b49",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
@@ -242,11 +260,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768530555,
|
"lastModified": 1777349711,
|
||||||
"narHash": "sha256-EBXKDho4t1YSgodAL6C8M3UTm8MGMZNQ9rQnceR5+6c=",
|
"narHash": "sha256-PGKgo2dO6fK603QGI+DWXdKmS09pbJjjTxwRHdhkGZA=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "d21bee5abf9fb4a42b2fa7728bf671f8bb246ba6",
|
"rev": "c1140540536d483e2730320100f6835d62c94fdf",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -283,11 +301,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768426687,
|
"lastModified": 1776426061,
|
||||||
"narHash": "sha256-CopNx3j//gZ2mE0ggEK9dZ474UcbDhpTw+KMor8mSxI=",
|
"narHash": "sha256-3rROoGl8xBsIOM+5m+qZS4GJnsdQPAH3NJJe1OUfJ5o=",
|
||||||
"owner": "hyprwm",
|
"owner": "hyprwm",
|
||||||
"repo": "contrib",
|
"repo": "contrib",
|
||||||
"rev": "541628cebe42792ddf5063c4abd6402c2f1bd68f",
|
"rev": "1f71628d86a7701fd5ba0f8aeabe15376f4c6afc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -337,11 +355,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765267181,
|
"lastModified": 1777181277,
|
||||||
"narHash": "sha256-d3NBA9zEtBu2JFMnTBqWj7Tmi7R5OikoU2ycrdhQEws=",
|
"narHash": "sha256-yVJbd07ortDRAttDFmDV5p220aOLTHgVAx//0nW/xW8=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "nix-index-database",
|
"repo": "nix-index-database",
|
||||||
"rev": "82befcf7dc77c909b0f2a09f5da910ec95c5b78f",
|
"rev": "b8eb7acee0f7604fe1bf6a5b3dcf5254369180fa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -402,11 +420,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1764234087,
|
"lastModified": 1769813415,
|
||||||
"narHash": "sha256-NHF7QWa0ZPT8hsJrvijREW3+nifmF2rTXgS2v0tpcEA=",
|
"narHash": "sha256-nnVmNNKBi1YiBNPhKclNYDORoHkuKipoz7EtVnXO50A=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixos-generators",
|
"repo": "nixos-generators",
|
||||||
"rev": "032a1878682fafe829edfcf5fdfad635a2efe748",
|
"rev": "8946737ff703382fda7623b9fab071d037e897d5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -417,11 +435,11 @@
|
|||||||
},
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768583413,
|
"lastModified": 1776983936,
|
||||||
"narHash": "sha256-tF5UD4D/s0kERXxhu5mzTo7FF/2jnU8PYf7wWk8guB0=",
|
"narHash": "sha256-ZOQyNqSvJ8UdrrqU1p7vaFcdL53idK+LOM8oRWEWh6o=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "45bf76ef956c7ac771b56c54a3009506dc6c7af6",
|
"rev": "2096f3f411ce46e88a79ae4eafcfc9df8ed41c61",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -440,11 +458,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768443651,
|
"lastModified": 1776036369,
|
||||||
"narHash": "sha256-hmIo/e6mo40Y2v1DaH2yTtvB3lZ/zcf6gVNmgYhBgYc=",
|
"narHash": "sha256-TxBJY5IwDu3peDIK3b9+A7pwqBaFRCAIllaRSfYMQtI=",
|
||||||
"owner": "NuschtOS",
|
"owner": "NuschtOS",
|
||||||
"repo": "nixos-modules",
|
"repo": "nixos-modules",
|
||||||
"rev": "31108e0d75bd47ddfc217b58df598e78fe3bcd42",
|
"rev": "2bea807180b3931cf8765078205fd9171dbfd2b5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -471,11 +489,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
"nixpkgs-lib": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765674936,
|
"lastModified": 1774748309,
|
||||||
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
|
"narHash": "sha256-+U7gF3qxzwD5TZuANzZPeJTZRHS29OFQgkQ2kiTJBIQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixpkgs.lib",
|
"repo": "nixpkgs.lib",
|
||||||
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
|
"rev": "333c4e0545a6da976206c74db8773a1645b5870a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -502,11 +520,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768305791,
|
"lastModified": 1776877367,
|
||||||
"narHash": "sha256-AIdl6WAn9aymeaH/NvBj0H9qM+XuAuYbGMZaP0zcXAQ=",
|
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "1412caf7bf9e660f2f962917c14b1ea1c3bc695e",
|
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -528,11 +546,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767810917,
|
"lastModified": 1775228139,
|
||||||
"narHash": "sha256-ZKqhk772+v/bujjhla9VABwcvz+hB2IaRyeLT6CFnT0=",
|
"narHash": "sha256-ebbeHmg+V7w8050bwQOuhmQHoLOEOfqKzM1KgCTexK4=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "dead29c804adc928d3a69dfe7f9f12d0eec1f1a4",
|
"rev": "601971b9c89e0304561977f2c28fa25e73aa7132",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -552,11 +570,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767281941,
|
"lastModified": 1776796298,
|
||||||
"narHash": "sha256-6MkqajPICgugsuZ92OMoQcgSHnD6sJHwk8AxvMcIgTE=",
|
"narHash": "sha256-PcRvlWayisPSjd0UcRQbhG8Oqw78AcPE6x872cPRHN8=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "f0927703b7b1c8d97511c4116eb9b4ec6645a0fa",
|
"rev": "3cfd774b0a530725a077e17354fbdb87ea1c4aad",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -567,6 +585,7 @@
|
|||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"disko": "disko",
|
||||||
"firefox-addons": "firefox-addons",
|
"firefox-addons": "firefox-addons",
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
@@ -596,11 +615,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768531678,
|
"lastModified": 1777346187,
|
||||||
"narHash": "sha256-tf4xEp5Zq8+Zce0WtU8b0VNMxhQtwes67sN2phnbkpk=",
|
"narHash": "sha256-oVxyGjpiIsrXhWTJVUOs38fZQkLjd0nZGOY9K7Kfot8=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "0a9de73f3c23206a2fce3c7656a42d3a3f07be9f",
|
"rev": "146e7bf7569b8288f24d41d806b9f584f7cfd5b5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -616,11 +635,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768481291,
|
"lastModified": 1777338324,
|
||||||
"narHash": "sha256-NjKtkJraCZEnLHAJxLTI+BfdU//9coAz9p5TqveZwPU=",
|
"narHash": "sha256-bc+ZZCmOTNq86/svGnw0tVpH7vJaLYvGLLKFYP08Q8E=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "e085e303dfcce21adcb5fec535d65aacb066f101",
|
"rev": "8eaee5c45428b28b8c47a83e4c09dccec5f279b5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -643,18 +662,17 @@
|
|||||||
],
|
],
|
||||||
"nur": "nur",
|
"nur": "nur",
|
||||||
"systems": "systems",
|
"systems": "systems",
|
||||||
"tinted-foot": "tinted-foot",
|
|
||||||
"tinted-kitty": "tinted-kitty",
|
"tinted-kitty": "tinted-kitty",
|
||||||
"tinted-schemes": "tinted-schemes",
|
"tinted-schemes": "tinted-schemes",
|
||||||
"tinted-tmux": "tinted-tmux",
|
"tinted-tmux": "tinted-tmux",
|
||||||
"tinted-zed": "tinted-zed"
|
"tinted-zed": "tinted-zed"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768492720,
|
"lastModified": 1776893932,
|
||||||
"narHash": "sha256-aHos307HyVtOriYZppyUjrkcEKQzyp9F5WzxpMjPFH8=",
|
"narHash": "sha256-AFD5cf9eNqXq1brHS63xeZy2xKZMgG9J86XJ9I2eLn8=",
|
||||||
"owner": "danth",
|
"owner": "danth",
|
||||||
"repo": "stylix",
|
"repo": "stylix",
|
||||||
"rev": "5287bc719dbb6efb26f48c1677a221c966a4a4d9",
|
"rev": "84971726c7ef0bb3669a5443e151cc226e65c518",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -693,23 +711,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tinted-foot": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1726913040,
|
|
||||||
"narHash": "sha256-+eDZPkw7efMNUf3/Pv0EmsidqdwNJ1TaOum6k7lngDQ=",
|
|
||||||
"owner": "tinted-theming",
|
|
||||||
"repo": "tinted-foot",
|
|
||||||
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "tinted-theming",
|
|
||||||
"repo": "tinted-foot",
|
|
||||||
"rev": "fd1b924b6c45c3e4465e8a849e67ea82933fcbe4",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tinted-kitty": {
|
"tinted-kitty": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -729,11 +730,11 @@
|
|||||||
"tinted-schemes": {
|
"tinted-schemes": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767710407,
|
"lastModified": 1772661346,
|
||||||
"narHash": "sha256-+W1EB79Jl0/gm4JqmO0Nuc5C7hRdp4vfsV/VdzI+des=",
|
"narHash": "sha256-4eu3LqB9tPqe0Vaqxd4wkZiBbthLbpb7llcoE/p5HT0=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "schemes",
|
"repo": "schemes",
|
||||||
"rev": "2800e2b8ac90f678d7e4acebe4fa253f602e05b2",
|
"rev": "13b5b0c299982bb361039601e2d72587d6846294",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -745,11 +746,11 @@
|
|||||||
"tinted-tmux": {
|
"tinted-tmux": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767489635,
|
"lastModified": 1772934010,
|
||||||
"narHash": "sha256-e6nnFnWXKBCJjCv4QG4bbcouJ6y3yeT70V9MofL32lU=",
|
"narHash": "sha256-x+6+4UvaG+RBRQ6UaX+o6DjEg28u4eqhVRM9kpgJGjQ=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "tinted-tmux",
|
"repo": "tinted-tmux",
|
||||||
"rev": "3c32729ccae99be44fe8a125d20be06f8d7d8184",
|
"rev": "c3529673a5ab6e1b6830f618c45d9ce1bcdd829d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -761,11 +762,11 @@
|
|||||||
"tinted-zed": {
|
"tinted-zed": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767488740,
|
"lastModified": 1772909925,
|
||||||
"narHash": "sha256-wVOj0qyil8m+ouSsVZcNjl5ZR+1GdOOAooAatQXHbuU=",
|
"narHash": "sha256-jx/5+pgYR0noHa3hk2esin18VMbnPSvWPL5bBjfTIAU=",
|
||||||
"owner": "tinted-theming",
|
"owner": "tinted-theming",
|
||||||
"repo": "base16-zed",
|
"repo": "base16-zed",
|
||||||
"rev": "11abb0b282ad3786a2aae088d3a01c60916f2e40",
|
"rev": "b4d3a1b3bcbd090937ef609a0a3b37237af974df",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -787,11 +788,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1765936672,
|
"lastModified": 1777064547,
|
||||||
"narHash": "sha256-wxkeSF0/3FI0HSBKhZ2mlAAmFviNrZzdhjHqTfWP6h0=",
|
"narHash": "sha256-hssXWvyy6bzaGi9FuZQPGxVBLzQKRPDht13O0Y+Qxmo=",
|
||||||
"owner": "Toqozz",
|
"owner": "Toqozz",
|
||||||
"repo": "wired-notify",
|
"repo": "wired-notify",
|
||||||
"rev": "491197a6a5ef9c65a85c3eb1531786f32ffff5b3",
|
"rev": "95edd8613b1636639857a3fba403155cef82eb5d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
systems.url = "github:nix-systems/default";
|
systems.url = "github:nix-systems/default";
|
||||||
|
|
||||||
# flake inputs with dependencies (in alphabetic order)
|
# flake inputs with dependencies (in alphabetic order)
|
||||||
|
disko = {
|
||||||
|
url = "github:nix-community/disko";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
firefox-addons = {
|
firefox-addons = {
|
||||||
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
|
url = "gitlab:rycee/nur-expressions?dir=pkgs/firefox-addons";
|
||||||
inputs = {
|
inputs = {
|
||||||
@@ -164,19 +169,23 @@
|
|||||||
lib = self;
|
lib = self;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
packageSetup = import ./pkgs/default.nix { inherit nixpkgs; };
|
||||||
|
inherit (packageSetup) localPackagesOverlay;
|
||||||
inherit (lib.adev.systems) genSystems getImages;
|
inherit (lib.adev.systems) genSystems getImages;
|
||||||
inherit (self) outputs; # for hydra
|
inherit (self) outputs; # for hydra
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
inherit lib; # for allowing use of custom functions in nix repl
|
inherit lib; # for allowing use of custom functions in nix repl
|
||||||
|
|
||||||
|
overlays.default = localPackagesOverlay;
|
||||||
|
|
||||||
hydraJobs = import ./hydra/jobs.nix { inherit inputs outputs systems; };
|
hydraJobs = import ./hydra/jobs.nix { inherit inputs outputs systems; };
|
||||||
formatter = forEachSystem (system: nixpkgs.legacyPackages.${system}.nixfmt);
|
formatter = forEachSystem (system: nixpkgs.legacyPackages.${system}.nixfmt);
|
||||||
|
|
||||||
nixosConfigurations = genSystems inputs outputs src (src + "/systems");
|
nixosConfigurations = genSystems inputs outputs src (src + "/systems");
|
||||||
homeConfigurations = {
|
homeConfigurations = {
|
||||||
"alice" = inputs.home-manager.lib.homeManagerConfiguration {
|
"alice" = inputs.home-manager.lib.homeManagerConfiguration {
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
pkgs = packageSetup.mkPkgs "x86_64-linux";
|
||||||
modules = [
|
modules = [
|
||||||
inputs.stylix.homeModules.stylix
|
inputs.stylix.homeModules.stylix
|
||||||
inputs.sops-nix.homeManagerModules.sops
|
inputs.sops-nix.homeManagerModules.sops
|
||||||
@@ -203,9 +212,7 @@
|
|||||||
qcow = getImages nixosConfigurations "qcow";
|
qcow = getImages nixosConfigurations "qcow";
|
||||||
};
|
};
|
||||||
|
|
||||||
packages.x86_64-linux.lego-latest =
|
packages = forEachSystem packageSetup.mkPackages;
|
||||||
nixpkgs.legacyPackages.x86_64-linux.callPackage ./pkgs/lego-latest/default.nix
|
|
||||||
{ };
|
|
||||||
|
|
||||||
checks = import ./checks.nix { inherit inputs forEachSystem formatter; };
|
checks = import ./checks.nix { inherit inputs forEachSystem formatter; };
|
||||||
devShells = import ./shell.nix { inherit inputs forEachSystem checks; };
|
devShells = import ./shell.nix { inherit inputs forEachSystem checks; };
|
||||||
|
|||||||
@@ -167,11 +167,13 @@ rec {
|
|||||||
outputs
|
outputs
|
||||||
server
|
server
|
||||||
system
|
system
|
||||||
|
home
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
modules = [
|
modules = [
|
||||||
inputs.nixos-modules.nixosModule
|
inputs.nixos-modules.nixosModule
|
||||||
inputs.nix-index-database.nixosModules.nix-index
|
inputs.nix-index-database.nixosModules.nix-index
|
||||||
|
{ nixpkgs.overlays = [ outputs.overlays.default ]; }
|
||||||
(genHostName hostname)
|
(genHostName hostname)
|
||||||
(configPath + "/hardware.nix")
|
(configPath + "/hardware.nix")
|
||||||
(configPath + "/configuration.nix")
|
(configPath + "/configuration.nix")
|
||||||
|
|||||||
+4
-1
@@ -3,6 +3,7 @@
|
|||||||
inputs,
|
inputs,
|
||||||
outputs,
|
outputs,
|
||||||
server,
|
server,
|
||||||
|
home,
|
||||||
system,
|
system,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
@@ -22,6 +23,9 @@
|
|||||||
mutableUsers = lib.mkDefault false;
|
mutableUsers = lib.mkDefault false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
networking.firewall.enable = lib.mkDefault true;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs home {
|
||||||
home-manager = {
|
home-manager = {
|
||||||
useGlobalPkgs = true;
|
useGlobalPkgs = true;
|
||||||
useUserPackages = true;
|
useUserPackages = true;
|
||||||
@@ -34,5 +38,4 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.firewall.enable = lib.mkDefault true;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
services.fwupd.enable = lib.mkDefault true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
services.kubernetes = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to enable Kubernetes services";
|
||||||
|
};
|
||||||
|
|
||||||
|
version = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "1.28.0";
|
||||||
|
description = "Kubernetes version to use";
|
||||||
|
};
|
||||||
|
|
||||||
|
clusterName = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "palatine-hill-cluster";
|
||||||
|
description = "Name of the Kubernetes cluster";
|
||||||
|
};
|
||||||
|
|
||||||
|
controlPlaneEndpoint = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "localhost:6443";
|
||||||
|
description = "Control plane endpoint";
|
||||||
|
};
|
||||||
|
|
||||||
|
networking = lib.mkOption {
|
||||||
|
type = lib.types.attrs;
|
||||||
|
default = { };
|
||||||
|
description = "Kubernetes networking configuration";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.kubernetes.enable {
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
kubectl
|
||||||
|
kubernetes
|
||||||
|
];
|
||||||
|
|
||||||
|
## Enable containerd for Kubernetes
|
||||||
|
#virtualisation.containerd.enable = true;
|
||||||
|
|
||||||
|
## Enable kubelet
|
||||||
|
#services.kubelet = {
|
||||||
|
# enable = true;
|
||||||
|
# extraFlags = {
|
||||||
|
# "pod-infra-container-image" = "registry.k8s.io/pause:3.9";
|
||||||
|
# };
|
||||||
|
#};
|
||||||
|
|
||||||
|
## Enable kubeadm for cluster initialization
|
||||||
|
#environment.etc."kubeadm.yaml".text = ''
|
||||||
|
# apiVersion: kubeadm.k8s.io/v1beta3
|
||||||
|
# kind: InitConfiguration
|
||||||
|
# localAPIEndpoint:
|
||||||
|
# advertiseAddress: 127.0.0.1
|
||||||
|
# bindPort: 6443
|
||||||
|
# ---
|
||||||
|
# apiVersion: kubeadm.k8s.io/v1beta3
|
||||||
|
# kind: ClusterConfiguration
|
||||||
|
# clusterName: ${config.services.kubernetes.clusterName}
|
||||||
|
# controlPlaneEndpoint: ${config.services.kubernetes.controlPlaneEndpoint}
|
||||||
|
# networking:
|
||||||
|
# serviceSubnet: 10.96.0.0/12
|
||||||
|
# podSubnet: 10.244.0.0/16
|
||||||
|
# dnsDomain: cluster.local
|
||||||
|
#'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
git
|
|
||||||
python312
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
enable = lib.mkDefault true;
|
enable = lib.mkDefault true;
|
||||||
flags = [ "--accept-flake-config" ];
|
flags = [ "--accept-flake-config" ];
|
||||||
randomizedDelaySec = "1h";
|
randomizedDelaySec = "1h";
|
||||||
|
runGarbageCollection = true;
|
||||||
persistent = true;
|
persistent = true;
|
||||||
flake = "git+ssh://nayeonie.com/ahuston-0/nix-dotfiles.git";
|
flake = "git+ssh://nayeonie.com/ahuston-0/nix-dotfiles.git";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
libnotify,
|
libnotify,
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
maintainers = import ../maintainers.nix;
|
||||||
bins = [
|
bins = [
|
||||||
jq
|
jq
|
||||||
bitwarden-cli
|
bitwarden-cli
|
||||||
@@ -64,6 +65,7 @@ stdenv.mkDerivation {
|
|||||||
description = "Wrapper for Bitwarden and Rofi";
|
description = "Wrapper for Bitwarden and Rofi";
|
||||||
homepage = "https://github.com/mattydebie/bitwarden-rofi";
|
homepage = "https://github.com/mattydebie/bitwarden-rofi";
|
||||||
license = licenses.gpl3;
|
license = licenses.gpl3;
|
||||||
|
maintainers = [ maintainers.alice ];
|
||||||
platforms = platforms.linux;
|
platforms = platforms.linux;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitHub,
|
||||||
|
rustPlatform,
|
||||||
|
pkg-config,
|
||||||
|
openssl,
|
||||||
|
alsa-lib,
|
||||||
|
dbus,
|
||||||
|
libxkbcommon,
|
||||||
|
libxcb,
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
maintainers = import ../maintainers.nix;
|
||||||
|
in
|
||||||
|
rustPlatform.buildRustPackage rec {
|
||||||
|
pname = "claurst";
|
||||||
|
version = "0.0.9";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "Kuberwastaken";
|
||||||
|
repo = "claurst";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-bTQHtZGZxhEAki0JxSC8smAC3w+otm8ubHvZ9MvwDaE=";
|
||||||
|
};
|
||||||
|
|
||||||
|
cargoRoot = "src-rust";
|
||||||
|
cargoHash = "sha256-6+B43spqmUZ983YMl5UBH5647DcUOS2ngw5ChMIPFFo=";
|
||||||
|
buildAndTestSubdir = "src-rust";
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
openssl
|
||||||
|
alsa-lib
|
||||||
|
dbus
|
||||||
|
libxkbcommon
|
||||||
|
libxcb
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Terminal coding agent written in Rust";
|
||||||
|
homepage = "https://github.com/Kuberwastaken/claurst";
|
||||||
|
license = licenses.gpl3Only;
|
||||||
|
mainProgram = "claurst";
|
||||||
|
maintainers = [ maintainers.alice ];
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{ nixpkgs }:
|
||||||
|
let
|
||||||
|
localPackagesOverlay = final: _prev: {
|
||||||
|
lego-latest = final.callPackage ./lego-latest/default.nix { };
|
||||||
|
claurst = final.callPackage ./claurst/default.nix { };
|
||||||
|
};
|
||||||
|
|
||||||
|
mkPkgs =
|
||||||
|
system:
|
||||||
|
import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
overlays = [ localPackagesOverlay ];
|
||||||
|
};
|
||||||
|
|
||||||
|
mkPackages =
|
||||||
|
system:
|
||||||
|
let
|
||||||
|
pkgs = mkPkgs system;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit (pkgs)
|
||||||
|
lego-latest
|
||||||
|
claurst
|
||||||
|
;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
localPackagesOverlay
|
||||||
|
mkPkgs
|
||||||
|
mkPackages
|
||||||
|
;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
alice = {
|
||||||
|
name = "Alice Huston";
|
||||||
|
email = "aliceghuston@gmail.com";
|
||||||
|
github = "ahuston-0";
|
||||||
|
githubId = 43225907;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{ lib, ... }:
|
||||||
|
{
|
||||||
|
imports = [ ./disk.nix ];
|
||||||
|
|
||||||
|
time.timeZone = "America/New_York";
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
hostId = "c3798ccc";
|
||||||
|
firewall = {
|
||||||
|
enable = true;
|
||||||
|
allowedTCPPorts = [ 80 ];
|
||||||
|
};
|
||||||
|
useNetworkd = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Raspberry Pi 4 uses U-Boot / extlinux — disable both GRUB and systemd-boot
|
||||||
|
# TPM 2.0 HAT: systemd initrd required for tpm2-device auto-unlock
|
||||||
|
# After first install, enroll with:
|
||||||
|
# systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 --recovery-key /dev/mmcblk0p3
|
||||||
|
boot = {
|
||||||
|
useSystemdBoot = lib.mkForce false;
|
||||||
|
loader.grub.enable = lib.mkOverride 0 false;
|
||||||
|
initrd = {
|
||||||
|
systemd.enable = true;
|
||||||
|
luks.devices."cryptroot".crypttabExtraOpts = [ "tpm2-device=auto" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
sops = {
|
||||||
|
defaultSopsFile = ./secrets.yaml;
|
||||||
|
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.tang.enable = true;
|
||||||
|
|
||||||
|
system.stateVersion = "26.11";
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{ inputs, ... }:
|
||||||
|
{
|
||||||
|
system = "aarch64-linux";
|
||||||
|
server = true;
|
||||||
|
home = false;
|
||||||
|
sops = true;
|
||||||
|
users = [ "alice" ];
|
||||||
|
modules = [
|
||||||
|
inputs.nixos-hardware.nixosModules.raspberry-pi-4
|
||||||
|
inputs.disko.nixosModules.disko
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
disko.devices = {
|
||||||
|
disk = {
|
||||||
|
# SD card — change device to /dev/sda if booting from USB instead
|
||||||
|
main = {
|
||||||
|
type = "disk";
|
||||||
|
device = "/dev/mmcblk0";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
# Raspberry Pi firmware partition — must be vfat and first
|
||||||
|
firmware = {
|
||||||
|
size = "256MiB";
|
||||||
|
type = "EF00";
|
||||||
|
priority = 1;
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot/firmware";
|
||||||
|
mountOptions = [
|
||||||
|
"fmask=0077"
|
||||||
|
"dmask=0077"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# NixOS boot partition — holds kernels/initrds for each generation
|
||||||
|
boot = {
|
||||||
|
size = "1GiB";
|
||||||
|
priority = 2;
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# Root filesystem — LUKS-encrypted, unlocked via TPM 2.0 HAT
|
||||||
|
root = {
|
||||||
|
size = "100%";
|
||||||
|
priority = 3;
|
||||||
|
content = {
|
||||||
|
type = "luks";
|
||||||
|
name = "cryptroot";
|
||||||
|
settings.allowDiscards = true;
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# TODO: after first boot, regenerate with:
|
||||||
|
# sudo nixos-generate-config --no-filesystems
|
||||||
|
# (disko owns fileSystems; do not add them here)
|
||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
swapDevices = [ ];
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
config,
|
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
|
config,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
./stylix.nix
|
./stylix.nix
|
||||||
./wifi.nix
|
./wifi.nix
|
||||||
./zerotier.nix
|
./zerotier.nix
|
||||||
|
../palatine-hill/ollama.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
time.timeZone = "America/New_York";
|
time.timeZone = "America/New_York";
|
||||||
@@ -40,6 +41,25 @@
|
|||||||
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
|
ollama = {
|
||||||
|
package = lib.mkForce pkgs.ollama-rocm;
|
||||||
|
models = lib.mkForce "${config.services.ollama.home}/models";
|
||||||
|
loadModels = lib.mkForce [
|
||||||
|
"deepseek-r1:1.5b"
|
||||||
|
"lennyerik/zeta"
|
||||||
|
"nomic-embed-text:latest"
|
||||||
|
"glm-4.7-flash"
|
||||||
|
"magistral"
|
||||||
|
"devstral-small-2"
|
||||||
|
"starcoder2:7b"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
avahi = {
|
||||||
|
enable = true;
|
||||||
|
#publish.enable = true;
|
||||||
|
nssmdns4 = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
flatpak.enable = true;
|
flatpak.enable = true;
|
||||||
calibre-web = {
|
calibre-web = {
|
||||||
# temp disable this
|
# temp disable this
|
||||||
@@ -78,7 +98,9 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.alice.extraGroups = [ "calibre-web" ];
|
users.users = {
|
||||||
|
alice.extraGroups = [ "calibre-web" ];
|
||||||
|
};
|
||||||
|
|
||||||
system.stateVersion = "24.05";
|
system.stateVersion = "24.05";
|
||||||
|
|
||||||
@@ -86,6 +108,10 @@
|
|||||||
"KWIN_DRM_NO_DIRECT_SCANOUT" = "1";
|
"KWIN_DRM_NO_DIRECT_SCANOUT" = "1";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#nixpkgs.config = {
|
||||||
|
# rocmSupport = true;
|
||||||
|
#};
|
||||||
|
|
||||||
sops = {
|
sops = {
|
||||||
defaultSopsFile = ./secrets.yaml;
|
defaultSopsFile = ./secrets.yaml;
|
||||||
#secrets = {
|
#secrets = {
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
dbus = {
|
dbus = {
|
||||||
enable = true;
|
enable = true;
|
||||||
implementation = "broker";
|
implementation = "broker";
|
||||||
|
packages = with pkgs; [
|
||||||
|
gcr
|
||||||
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
attic-client
|
attic-client
|
||||||
amdgpu_top
|
amdgpu_top
|
||||||
android-tools
|
android-tools
|
||||||
bat
|
|
||||||
bitwarden-cli
|
bitwarden-cli
|
||||||
bfg-repo-cleaner
|
bfg-repo-cleaner
|
||||||
brightnessctl
|
brightnessctl
|
||||||
@@ -16,9 +15,9 @@
|
|||||||
candy-icons
|
candy-icons
|
||||||
chromium
|
chromium
|
||||||
chromedriver
|
chromedriver
|
||||||
|
#claude-code
|
||||||
croc
|
croc
|
||||||
deadnix
|
deadnix
|
||||||
direnv
|
|
||||||
easyeffects
|
easyeffects
|
||||||
eza
|
eza
|
||||||
fanficfare
|
fanficfare
|
||||||
@@ -26,20 +25,16 @@
|
|||||||
fd
|
fd
|
||||||
file
|
file
|
||||||
firefox
|
firefox
|
||||||
|
|
||||||
# gestures replacement
|
# gestures replacement
|
||||||
git
|
git
|
||||||
glances
|
glances
|
||||||
gpu-viewer
|
gpu-viewer
|
||||||
grim
|
grim
|
||||||
helvum
|
|
||||||
htop
|
htop
|
||||||
hwloc
|
hwloc
|
||||||
ipmiview
|
|
||||||
iperf3
|
iperf3
|
||||||
# ipscan
|
# ipscan
|
||||||
javaPackages.compiler.temurin-bin.jdk-25
|
|
||||||
javaPackages.compiler.temurin-bin.jdk-21
|
|
||||||
javaPackages.compiler.temurin-bin.jdk-17
|
|
||||||
jp2a
|
jp2a
|
||||||
jq
|
jq
|
||||||
kdePackages.kdenlive
|
kdePackages.kdenlive
|
||||||
@@ -85,8 +80,6 @@
|
|||||||
# signal in tray?
|
# signal in tray?
|
||||||
siji
|
siji
|
||||||
simple-mtpfs
|
simple-mtpfs
|
||||||
skaffold
|
|
||||||
slack
|
|
||||||
slurp
|
slurp
|
||||||
smartmontools
|
smartmontools
|
||||||
snyk
|
snyk
|
||||||
@@ -112,4 +105,13 @@
|
|||||||
zoom-us
|
zoom-us
|
||||||
zoxide
|
zoxide
|
||||||
];
|
];
|
||||||
|
programs = {
|
||||||
|
appimage = {
|
||||||
|
enable = true;
|
||||||
|
binfmt = true;
|
||||||
|
};
|
||||||
|
bat.enable = true;
|
||||||
|
direnv.enable = true;
|
||||||
|
kdeconnect.enable = true;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
# let
|
|
||||||
# randWallpaper = pkgs.runCommand "stylix-wallpaper" { } ''
|
|
||||||
# numWallpapers =
|
|
||||||
# $((1 + $RANDOM % 10))
|
|
||||||
|
|
||||||
# in
|
|
||||||
{
|
{
|
||||||
stylix = {
|
stylix = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -9,14 +9,17 @@
|
|||||||
./acme.nix
|
./acme.nix
|
||||||
./attic
|
./attic
|
||||||
./docker
|
./docker
|
||||||
|
./garage.nix
|
||||||
./gitea.nix
|
./gitea.nix
|
||||||
./firewall.nix
|
./firewall.nix
|
||||||
./haproxy
|
./haproxy
|
||||||
./hardware-changes.nix
|
./hardware-changes.nix
|
||||||
./hydra.nix
|
./hydra.nix
|
||||||
|
./mattermost.nix
|
||||||
./minio.nix
|
./minio.nix
|
||||||
./networking.nix
|
./networking.nix
|
||||||
./nextcloud.nix
|
./nextcloud.nix
|
||||||
|
./otel.nix
|
||||||
#./plex
|
#./plex
|
||||||
./postgresql.nix
|
./postgresql.nix
|
||||||
./samba.nix
|
./samba.nix
|
||||||
@@ -33,8 +36,7 @@
|
|||||||
loader.grub.device = "/dev/sda";
|
loader.grub.device = "/dev/sda";
|
||||||
useSystemdBoot = true;
|
useSystemdBoot = true;
|
||||||
kernelParams = [
|
kernelParams = [
|
||||||
"i915.force_probe=56a5"
|
"xe.force_probe=56a5"
|
||||||
"i915.enable_guc=2"
|
|
||||||
];
|
];
|
||||||
kernel.sysctl = {
|
kernel.sysctl = {
|
||||||
"vm.overcommit_memory" = lib.mkForce 1;
|
"vm.overcommit_memory" = lib.mkForce 1;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
vars = import ../vars.nix;
|
vars = import ../vars.nix;
|
||||||
|
shared_data_path = "${vars.primary_torr}/data";
|
||||||
arr_postgres_config =
|
arr_postgres_config =
|
||||||
container_type:
|
container_type:
|
||||||
let
|
let
|
||||||
@@ -62,7 +63,7 @@ in
|
|||||||
];
|
];
|
||||||
volumes = [
|
volumes = [
|
||||||
"${vars.primary_docker}/bazarr:/config"
|
"${vars.primary_docker}/bazarr:/config"
|
||||||
"${vars.primary_plex_storage}/data:/data"
|
"${shared_data_path}:/data"
|
||||||
"/var/run/postgresql:/var/run/postgresql"
|
"/var/run/postgresql:/var/run/postgresql"
|
||||||
];
|
];
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
@@ -110,7 +111,7 @@ in
|
|||||||
];
|
];
|
||||||
volumes = [
|
volumes = [
|
||||||
"${vars.primary_docker}/radarr:/config"
|
"${vars.primary_docker}/radarr:/config"
|
||||||
"${vars.primary_plex_storage}/data:/data"
|
"${shared_data_path}:/data"
|
||||||
"/var/run/postgresql:/var/run/postgresql"
|
"/var/run/postgresql:/var/run/postgresql"
|
||||||
];
|
];
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
@@ -134,7 +135,7 @@ in
|
|||||||
];
|
];
|
||||||
volumes = [
|
volumes = [
|
||||||
"${vars.primary_docker}/sonarr:/config"
|
"${vars.primary_docker}/sonarr:/config"
|
||||||
"${vars.primary_plex_storage}/data:/data"
|
"${shared_data_path}:/data"
|
||||||
"/var/run/postgresql:/var/run/postgresql"
|
"/var/run/postgresql:/var/run/postgresql"
|
||||||
];
|
];
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
@@ -158,7 +159,7 @@ in
|
|||||||
];
|
];
|
||||||
volumes = [
|
volumes = [
|
||||||
"${vars.primary_docker}/lidarr:/config"
|
"${vars.primary_docker}/lidarr:/config"
|
||||||
"${vars.primary_plex_storage}/data:/data"
|
"${shared_data_path}:/data"
|
||||||
"/var/run/postgresql:/var/run/postgresql"
|
"/var/run/postgresql:/var/run/postgresql"
|
||||||
];
|
];
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
@@ -176,7 +177,7 @@ in
|
|||||||
};
|
};
|
||||||
volumes = [
|
volumes = [
|
||||||
"${vars.primary_docker}/unpackerr:/config"
|
"${vars.primary_docker}/unpackerr:/config"
|
||||||
"${vars.primary_plex_storage}:/data"
|
"${shared_data_path}:/data"
|
||||||
"/var/run/postgresql:/var/run/postgresql"
|
"/var/run/postgresql:/var/run/postgresql"
|
||||||
];
|
];
|
||||||
extraOptions = [ "--network=arrnet" ];
|
extraOptions = [ "--network=arrnet" ];
|
||||||
@@ -194,7 +195,7 @@ in
|
|||||||
environmentFiles = [ config.sops.secrets."docker/notifiarr".path ];
|
environmentFiles = [ config.sops.secrets."docker/notifiarr".path ];
|
||||||
volumes = [
|
volumes = [
|
||||||
"${vars.primary_docker}/notifiarr:/config"
|
"${vars.primary_docker}/notifiarr:/config"
|
||||||
"${vars.primary_plex_storage}:/data"
|
"${shared_data_path}:/data"
|
||||||
"/var/run/postgresql:/var/run/postgresql"
|
"/var/run/postgresql:/var/run/postgresql"
|
||||||
];
|
];
|
||||||
extraOptions = [ "--network=arrnet" ];
|
extraOptions = [ "--network=arrnet" ];
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
{
|
{ ... }:
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ frontend ContentSwitching
|
|||||||
acl host_minio hdr(host) -i minio.alicehuston.xyz
|
acl host_minio hdr(host) -i minio.alicehuston.xyz
|
||||||
acl host_minio_console hdr(host) -i minio-console.alicehuston.xyz
|
acl host_minio_console hdr(host) -i minio-console.alicehuston.xyz
|
||||||
acl host_attic hdr(host) -i attic.nayeonie.com
|
acl host_attic hdr(host) -i attic.nayeonie.com
|
||||||
|
acl host_s3 hdr(host) -i s3.nayeonie.com
|
||||||
acl host_minio hdr(host) -i minio.nayeonie.com
|
acl host_minio hdr(host) -i minio.nayeonie.com
|
||||||
acl host_minio_console hdr(host) -i minio-console.nayeonie.com
|
acl host_minio_console hdr(host) -i minio-console.nayeonie.com
|
||||||
#acl host_nextcloud_vol hdr(host) -i nextcloud-vol.alicehuston.xyz
|
#acl host_nextcloud_vol hdr(host) -i nextcloud-vol.alicehuston.xyz
|
||||||
@@ -67,6 +68,7 @@ frontend ContentSwitching
|
|||||||
use_backend nextcloud_nodes if host_nextcloud
|
use_backend nextcloud_nodes if host_nextcloud
|
||||||
use_backend hydra_nodes if host_hydra
|
use_backend hydra_nodes if host_hydra
|
||||||
use_backend attic_nodes if host_attic
|
use_backend attic_nodes if host_attic
|
||||||
|
use_backend garage_nodes if host_s3
|
||||||
#use_backend nextcloud_vol_nodes if host_nextcloud_vol
|
#use_backend nextcloud_vol_nodes if host_nextcloud_vol
|
||||||
# use_backend collabora_nodes if host_collabora
|
# use_backend collabora_nodes if host_collabora
|
||||||
use_backend prometheus_nodes if host_prometheus
|
use_backend prometheus_nodes if host_prometheus
|
||||||
@@ -142,6 +144,10 @@ backend minio_console_nodes
|
|||||||
mode http
|
mode http
|
||||||
server server 192.168.76.2:8501
|
server server 192.168.76.2:8501
|
||||||
|
|
||||||
|
backend garage_nodes
|
||||||
|
mode http
|
||||||
|
server server 192.168.76.2:8502
|
||||||
|
|
||||||
# backend foundry_nodes
|
# backend foundry_nodes
|
||||||
# timeout tunnel 50s
|
# timeout tunnel 50s
|
||||||
# mode http
|
# mode http
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ let
|
|||||||
rlcraft = "rlcraft.alicehuston.xyz";
|
rlcraft = "rlcraft.alicehuston.xyz";
|
||||||
arcanum-institute = "arcanum.alicehuston.xyz";
|
arcanum-institute = "arcanum.alicehuston.xyz";
|
||||||
meits = "meits.alicehuston.xyz";
|
meits = "meits.alicehuston.xyz";
|
||||||
|
cobblemon-overclocked = "mco.alicehuston.xyz";
|
||||||
|
cobblemon-plus = "mcp.alicehuston.xyz";
|
||||||
# bcg-plus = "bcg.alicehuston.xyz";
|
# bcg-plus = "bcg.alicehuston.xyz";
|
||||||
pii = "pii.alicehuston.xyz";
|
pii = "pii.alicehuston.xyz";
|
||||||
};
|
};
|
||||||
@@ -79,69 +81,49 @@ in
|
|||||||
# log-driver = "local";
|
# log-driver = "local";
|
||||||
# environmentFiles = [ config.sops.secrets."docker/minecraft".path ];
|
# environmentFiles = [ config.sops.secrets."docker/minecraft".path ];
|
||||||
#};
|
#};
|
||||||
prominence-ii = {
|
cobblemon-overclocked = {
|
||||||
image = "itzg/minecraft-server:java25-graalvm";
|
image = "itzg/minecraft-server:java21";
|
||||||
volumes = [
|
volumes = [
|
||||||
"${minecraft_path}/prominence-ii/modpacks:/modpacks:ro"
|
"${minecraft_path}/cobblemon-overclocked/modpacks:/modpacks:ro"
|
||||||
"${minecraft_path}/prominence-ii/data:/data"
|
"${minecraft_path}/cobblemon-overclocked/data:/data"
|
||||||
];
|
];
|
||||||
hostname = "pii";
|
hostname = "cobblemon-overclocked";
|
||||||
environment = defaultEnv // {
|
environment = defaultEnv // {
|
||||||
VERSION = "1.20.1";
|
VERSION = "1.21.1";
|
||||||
CF_SLUG = "prominence-2-hasturian-era";
|
CF_SLUG = "modified-cobblemon-overclocked";
|
||||||
CF_FILENAME_MATCHER = "3.9.14hf";
|
CF_FILENAME_MATCHER = "1.11.2";
|
||||||
MEMORY = "8G";
|
|
||||||
USE_AIKAR_FLAGS = "false";
|
USE_AIKAR_FLAGS = "false";
|
||||||
USE_MEOWICE_FLAGS = "true";
|
USE_MEOWICE_FLAGS = "true";
|
||||||
USE_MEOWICE_GRAALVM_FLAGS = "true";
|
DIFFICULTY = "normal";
|
||||||
DIFFICULTY = "hard";
|
|
||||||
ENABLE_COMMAND_BLOCK = "true";
|
ENABLE_COMMAND_BLOCK = "true";
|
||||||
CF_FORCE_INCLUDE_FILES = ''
|
INIT_MEMORY = "4G";
|
||||||
emi
|
MAX_MEMORY = "16G";
|
||||||
'';
|
SEED = "-7146406535839057559";
|
||||||
};
|
};
|
||||||
extraOptions = defaultOptions;
|
extraOptions = defaultOptions;
|
||||||
log-driver = "local";
|
log-driver = "local";
|
||||||
environmentFiles = [ config.sops.secrets."docker/minecraft".path ];
|
environmentFiles = [ config.sops.secrets."docker/minecraft".path ];
|
||||||
};
|
};
|
||||||
stoneblock-4 = {
|
cobblemon-plus = {
|
||||||
image = "itzg/minecraft-server:java25-graalvm";
|
image = "itzg/minecraft-server:java21";
|
||||||
volumes = [
|
volumes = [
|
||||||
"${minecraft_path}/stoneblock-4/modpacks:/modpacks:ro"
|
"${minecraft_path}/cobblemon-plus/modpacks:/modpacks:ro"
|
||||||
"${minecraft_path}/stoneblock-4/data:/data"
|
"${minecraft_path}/cobblemon-plus/data:/data"
|
||||||
];
|
];
|
||||||
hostname = "stoneblock-4";
|
hostname = "cobblemon-plus";
|
||||||
environment = defaultEnv // {
|
environment = defaultEnv // {
|
||||||
VERSION = "1.21.1";
|
VERSION = "1.21.1";
|
||||||
CF_SLUG = "ftb-stoneblock-4";
|
CF_SLUG = "modified-cobblemon-plus";
|
||||||
CF_FILENAME_MATCHER = "1.6.0";
|
CF_FILENAME_MATCHER = "1.11.2";
|
||||||
MEMORY = "8G";
|
|
||||||
USE_AIKAR_FLAGS = "false";
|
USE_AIKAR_FLAGS = "false";
|
||||||
USE_MEOWICE_FLAGS = "true";
|
USE_MEOWICE_FLAGS = "true";
|
||||||
USE_MEOWICE_GRAALVM_FLAGS = "true";
|
DIFFICULTY = "peaceful";
|
||||||
DIFFICULTY = "hard";
|
|
||||||
ENABLE_COMMAND_BLOCK = "true";
|
|
||||||
};
|
|
||||||
extraOptions = defaultOptions;
|
|
||||||
log-driver = "local";
|
|
||||||
environmentFiles = [ config.sops.secrets."docker/minecraft".path ];
|
|
||||||
};
|
|
||||||
submerged-2 = {
|
|
||||||
image = "itzg/minecraft-server:java25-graalvm";
|
|
||||||
volumes = [
|
|
||||||
"${minecraft_path}/submerged-2/modpacks:/modpacks:ro"
|
|
||||||
"${minecraft_path}/submerged-2/data:/data"
|
|
||||||
];
|
|
||||||
hostname = "submerged-2";
|
|
||||||
environment = defaultEnv // {
|
|
||||||
VERSION = "1.21.1";
|
|
||||||
CF_SLUG = "submerged-2";
|
|
||||||
CF_FILENAME_MATCHER = "B6.1";
|
|
||||||
USE_AIKAR_FLAGS = "false";
|
|
||||||
USE_MEOWICE_FLAGS = "true";
|
|
||||||
USE_MEOWICE_GRAALVM_FLAGS = "true";
|
|
||||||
DIFFICULTY = "hard";
|
|
||||||
ENABLE_COMMAND_BLOCK = "true";
|
ENABLE_COMMAND_BLOCK = "true";
|
||||||
|
INIT_MEMORY = "4G";
|
||||||
|
MAX_MEMORY = "16G";
|
||||||
|
# exclude clientside mods that cause crashes when run in a headless environment
|
||||||
|
CF_EXCLUDE_MODS = "world-host";
|
||||||
|
CF_OVERRIDES_EXCLUSIONS = "mods/iris*.jar,mods/sodium*.jar,mods/world-host-*.jar";
|
||||||
};
|
};
|
||||||
extraOptions = defaultOptions;
|
extraOptions = defaultOptions;
|
||||||
log-driver = "local";
|
log-driver = "local";
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ in
|
|||||||
volumes = [ "${nextcloud_path}/nc_data:/var/www/html:ro" ];
|
volumes = [ "${nextcloud_path}/nc_data:/var/www/html:ro" ];
|
||||||
extraOptions = [
|
extraOptions = [
|
||||||
"--device=/dev/dri:/dev/dri"
|
"--device=/dev/dri:/dev/dri"
|
||||||
|
"--network=nextcloud_default"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
collabora-code = {
|
collabora-code = {
|
||||||
|
|||||||
@@ -48,6 +48,9 @@
|
|||||||
|
|
||||||
# torr
|
# torr
|
||||||
29432
|
29432
|
||||||
|
|
||||||
|
# mattermost
|
||||||
|
8065
|
||||||
];
|
];
|
||||||
|
|
||||||
allowedUDPPorts = [
|
allowedUDPPorts = [
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
vars = import ./vars.nix;
|
||||||
|
basePath = "${vars.primary_minio}/garage";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.garage = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.garage;
|
||||||
|
logLevel = "info";
|
||||||
|
settings = {
|
||||||
|
metadata_dir = "${basePath}/meta";
|
||||||
|
data_dir = "${basePath}/data";
|
||||||
|
db_engine = "sqlite";
|
||||||
|
replication_factor = 1;
|
||||||
|
|
||||||
|
rpc_bind_addr = "127.0.0.1:8504";
|
||||||
|
rpc_public_addr = "127.0.0.1:8504";
|
||||||
|
rpc_secret_file = config.sops.secrets."garage/rpc-secret".path;
|
||||||
|
|
||||||
|
s3_api = {
|
||||||
|
api_bind_addr = "127.0.0.1:8502";
|
||||||
|
s3_region = "us-east-1";
|
||||||
|
root_domain = ".s3.nayeonie.com";
|
||||||
|
};
|
||||||
|
|
||||||
|
admin = {
|
||||||
|
api_bind_addr = "127.0.0.1:8503";
|
||||||
|
admin_token_file = config.sops.secrets."garage/admin-token".path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${basePath}/meta 0750 garage garage -"
|
||||||
|
"d ${basePath}/data 0750 garage garage -"
|
||||||
|
];
|
||||||
|
|
||||||
|
sops.secrets = {
|
||||||
|
"garage/rpc-secret" = { };
|
||||||
|
"garage/admin-token" = { };
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
{ lib, pkgs, ... }:
|
{ lib, ... }:
|
||||||
{
|
{
|
||||||
|
|
||||||
boot = {
|
boot = {
|
||||||
zfs.requestEncryptionCredentials = lib.mkForce false;
|
|
||||||
postBootCommands = ''
|
|
||||||
${pkgs.zfs}/bin/zfs load-key -a
|
|
||||||
'';
|
|
||||||
initrd = {
|
initrd = {
|
||||||
services.lvm.enable = true;
|
services.lvm.enable = true;
|
||||||
luks.devices = {
|
luks.devices = {
|
||||||
@@ -16,6 +12,28 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
clevis = {
|
||||||
|
enable = true;
|
||||||
|
useTang = true;
|
||||||
|
devices = {
|
||||||
|
# Unlock LUKS root device via Tang
|
||||||
|
"nixos-pv".secretFile = ./nixos-pv.jwe;
|
||||||
|
# Unlock ZFS native-encrypted dataset via Tang
|
||||||
|
"ZFS-primary/nix".secretFile = ./nix-store.jwe;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Static networking needed in initrd so Tang is reachable before any disk mounts
|
||||||
|
systemd.network = {
|
||||||
|
enable = true;
|
||||||
|
networks."10-initrd-eno1" = {
|
||||||
|
matchConfig.Name = "eno1";
|
||||||
|
address = [ "192.168.76.2/24" ];
|
||||||
|
routes = [ { Gateway = "192.168.76.1"; } ];
|
||||||
|
dns = [ "192.168.76.1" ];
|
||||||
|
linkConfig.RequiredForOnline = "routable";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,10 +55,7 @@
|
|||||||
"dmask=0077"
|
"dmask=0077"
|
||||||
];
|
];
|
||||||
|
|
||||||
"/nix".depends = [
|
"/nix".depends = [ "/" ];
|
||||||
"/"
|
|
||||||
"/crypto"
|
|
||||||
];
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
let
|
let
|
||||||
hydra_notify_prometheus_port = "9199";
|
hydra_notify_prometheus_port = "9199";
|
||||||
hydra_queue_runner_prometheus_port = "9200";
|
hydra_queue_runner_prometheus_port = "9200";
|
||||||
|
postgres_exporter_port = 9187;
|
||||||
|
zfs_exporter_port = 9134;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
systemd.services.hydra-notify.serviceConfig.EnvironmentFile =
|
systemd.services.hydra-notify.serviceConfig.EnvironmentFile =
|
||||||
@@ -57,6 +59,7 @@ in
|
|||||||
minimumDiskFree = 50;
|
minimumDiskFree = 50;
|
||||||
minimumDiskFreeEvaluator = 100;
|
minimumDiskFreeEvaluator = 100;
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
|
allow_import_from_derivation = true
|
||||||
<git-input>
|
<git-input>
|
||||||
timeout = 3600
|
timeout = 3600
|
||||||
</git-input>
|
</git-input>
|
||||||
@@ -95,10 +98,23 @@ in
|
|||||||
enable = true;
|
enable = true;
|
||||||
webExternalUrl = "https://prom.alicehuston.xyz";
|
webExternalUrl = "https://prom.alicehuston.xyz";
|
||||||
port = 9001;
|
port = 9001;
|
||||||
exporters.node = {
|
exporters = {
|
||||||
enable = true;
|
node = {
|
||||||
enabledCollectors = [ "systemd" ];
|
enable = true;
|
||||||
port = 9002;
|
enabledCollectors = [ "systemd" ];
|
||||||
|
port = 9002;
|
||||||
|
};
|
||||||
|
postgres = {
|
||||||
|
enable = true;
|
||||||
|
listenAddress = "127.0.0.1";
|
||||||
|
port = postgres_exporter_port;
|
||||||
|
runAsLocalSuperUser = true;
|
||||||
|
};
|
||||||
|
zfs = {
|
||||||
|
enable = true;
|
||||||
|
listenAddress = "127.0.0.1";
|
||||||
|
port = zfs_exporter_port;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
scrapeConfigs = [
|
scrapeConfigs = [
|
||||||
{
|
{
|
||||||
@@ -118,6 +134,18 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
job_name = "postgres-local";
|
||||||
|
static_configs = [
|
||||||
|
{ targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.postgres.port}" ]; }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
job_name = "zfs-local";
|
||||||
|
static_configs = [
|
||||||
|
{ targets = [ "127.0.0.1:${toString config.services.prometheus.exporters.zfs.port}" ]; }
|
||||||
|
];
|
||||||
|
}
|
||||||
{
|
{
|
||||||
job_name = "hydra-external";
|
job_name = "hydra-external";
|
||||||
scheme = "https";
|
scheme = "https";
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
vars = import ./vars.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.mattermost = {
|
||||||
|
enable = true;
|
||||||
|
siteUrl = "https://mattermost.nayeonie.com"; # Set this to the URL you will be hosting the site on.
|
||||||
|
database = {
|
||||||
|
peerAuth = true; # This allows Mattermost to connect to the database without a password, which is more secure when both are on the same machine.
|
||||||
|
create = true;
|
||||||
|
driver = "postgres";
|
||||||
|
};
|
||||||
|
dataDir = "${vars.primary_mattermost}/mattermost";
|
||||||
|
host = "0.0.0.0";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
vars = import ./vars.nix;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services = {
|
||||||
|
ollama = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.ollama;
|
||||||
|
syncModels = true;
|
||||||
|
loadModels = [
|
||||||
|
"deepseek-r1:1.5b"
|
||||||
|
"deepseek-r1:32b"
|
||||||
|
"deepseek-r1:70b"
|
||||||
|
#"qwen3"
|
||||||
|
#"qwen3.5:latest"
|
||||||
|
"qwen3-coder-next"
|
||||||
|
"lennyerik/zeta"
|
||||||
|
"nomic-embed-text:latest"
|
||||||
|
"lfm2:24b"
|
||||||
|
"glm-4.7-flash"
|
||||||
|
"nemotron-cascade-2:30b"
|
||||||
|
"magistral"
|
||||||
|
"devstral-small-2"
|
||||||
|
"starcoder2:15b"
|
||||||
|
];
|
||||||
|
models = vars.primary_ollama;
|
||||||
|
environmentVariables = {
|
||||||
|
FLASH_ATTENTION = "1";
|
||||||
|
OLLAMA_KV_CACHE_TYPE = "q4_0";
|
||||||
|
# Ollama memory configuration
|
||||||
|
OLLAMA_MAX_LOADED_MODELS = "3";
|
||||||
|
OLLAMA_MAX_QUEUE = "512";
|
||||||
|
OLLAMA_NUM_PARALLEL = "1";
|
||||||
|
|
||||||
|
# ROCm memory optimization
|
||||||
|
#HIP_VISIBLE_DEVICES = "0";
|
||||||
|
#ROCR_VISIBLE_DEVICES = "0";
|
||||||
|
|
||||||
|
# context length for agents
|
||||||
|
OLLAMA_CONTEXT_LENGTH = "128000";
|
||||||
|
};
|
||||||
|
openFirewall = true;
|
||||||
|
host = "0.0.0.0"; # don't want to make this available via load-balancer yet, so making it available on the local network
|
||||||
|
};
|
||||||
|
open-webui = {
|
||||||
|
enable = true;
|
||||||
|
port = 21212;
|
||||||
|
openFirewall = true;
|
||||||
|
host = "0.0.0.0"; # don't want to make this available via load-balancer yet, so making it available on the local network
|
||||||
|
};
|
||||||
|
};
|
||||||
|
users.users.ollama = {
|
||||||
|
extraGroups = [
|
||||||
|
"render"
|
||||||
|
"video"
|
||||||
|
];
|
||||||
|
group = "ollama";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
users.groups.ollama = { };
|
||||||
|
systemd.services = {
|
||||||
|
ollama.serviceConfig = {
|
||||||
|
Nice = 19;
|
||||||
|
IOSchedulingPriority = 7;
|
||||||
|
};
|
||||||
|
ollama-model-loader.serviceConfig = {
|
||||||
|
Nice = 19;
|
||||||
|
CPUWeight = 50;
|
||||||
|
IOSchedulingClass = "idle";
|
||||||
|
IOSchedulingPriority = 7;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# node_exporter (port 9002) and Prometheus (port 9001) are already configured
|
||||||
|
# in hydra.nix — we just scrape the existing exporter here.
|
||||||
|
|
||||||
|
services.opentelemetry-collector = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
receivers = {
|
||||||
|
# Host-level system metrics
|
||||||
|
hostmetrics = {
|
||||||
|
collection_interval = "60s";
|
||||||
|
scrapers = {
|
||||||
|
cpu = { };
|
||||||
|
memory = { };
|
||||||
|
disk = { };
|
||||||
|
filesystem = { };
|
||||||
|
network = { };
|
||||||
|
load = { };
|
||||||
|
processes = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Scrape node_exporter for per-systemd-unit service state
|
||||||
|
prometheus = {
|
||||||
|
config = {
|
||||||
|
scrape_configs = [
|
||||||
|
{
|
||||||
|
job_name = "node-exporter";
|
||||||
|
scrape_interval = "60s";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ];
|
||||||
|
labels = {
|
||||||
|
host = "palatine-hill";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
job_name = "postgres-exporter";
|
||||||
|
scrape_interval = "60s";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "localhost:${toString config.services.prometheus.exporters.postgres.port}" ];
|
||||||
|
labels = {
|
||||||
|
host = "palatine-hill";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
job_name = "zfs-exporter";
|
||||||
|
scrape_interval = "60s";
|
||||||
|
static_configs = [
|
||||||
|
{
|
||||||
|
targets = [ "localhost:${toString config.services.prometheus.exporters.zfs.port}" ];
|
||||||
|
labels = {
|
||||||
|
host = "palatine-hill";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
processors = {
|
||||||
|
batch = { };
|
||||||
|
|
||||||
|
# Attach hostname and other system resource attributes
|
||||||
|
"resourcedetection/system" = {
|
||||||
|
detectors = [ "system" ];
|
||||||
|
system.hostname_sources = [ "os" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
exporters = {
|
||||||
|
"otlp/honeycomb" = {
|
||||||
|
endpoint = "api.honeycomb.io:443";
|
||||||
|
headers = {
|
||||||
|
# Expanded at runtime from the environment file
|
||||||
|
"x-honeycomb-team" = "\${HONEYCOMB_API_KEY}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
service = {
|
||||||
|
pipelines = {
|
||||||
|
metrics = {
|
||||||
|
receivers = [
|
||||||
|
"hostmetrics"
|
||||||
|
"prometheus"
|
||||||
|
];
|
||||||
|
processors = [
|
||||||
|
"resourcedetection/system"
|
||||||
|
"batch"
|
||||||
|
];
|
||||||
|
exporters = [ "otlp/honeycomb" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Inject the Honeycomb API key at runtime — never stored in the Nix store
|
||||||
|
systemd.services.opentelemetry-collector.serviceConfig.EnvironmentFile =
|
||||||
|
config.sops.secrets."honeycomb/api-key".path;
|
||||||
|
|
||||||
|
sops.secrets = {
|
||||||
|
"honeycomb/api-key".owner = "root";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -40,6 +40,7 @@ in
|
|||||||
ensureDatabases = [
|
ensureDatabases = [
|
||||||
"atticd"
|
"atticd"
|
||||||
"alice"
|
"alice"
|
||||||
|
"mattermost"
|
||||||
];
|
];
|
||||||
ensureUsers = [
|
ensureUsers = [
|
||||||
{
|
{
|
||||||
@@ -171,6 +172,7 @@ in
|
|||||||
"hydra-server"
|
"hydra-server"
|
||||||
"atticd"
|
"atticd"
|
||||||
"gitea"
|
"gitea"
|
||||||
|
"mattermost"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ server-validation:
|
|||||||
webhook: ENC[AES256_GCM,data:Lwqy4UhyFutpXjai7EJPKp8MDlI+ayDna4T8jluvC6qkeJ7o1UaaDCOsgLy4Fw7LC77tXhJtkcmep9w37JaiHp2CoDOfy2iAaq8o9CCSi/a0zqMJx+HdZYZNemvmpc6E/be0K+JDrFZLbjr3unSpCidQ3whccC6XyY013R12swN3bFZIu1gtzXCgUZ4U,iv:pVbrRwH3ziu4+R5BfimPV7N71QmyerJEc9M5K4eofOc=,tag:zNrCXrIioQWPEPVz/wMDpQ==,type:str]
|
webhook: ENC[AES256_GCM,data:Lwqy4UhyFutpXjai7EJPKp8MDlI+ayDna4T8jluvC6qkeJ7o1UaaDCOsgLy4Fw7LC77tXhJtkcmep9w37JaiHp2CoDOfy2iAaq8o9CCSi/a0zqMJx+HdZYZNemvmpc6E/be0K+JDrFZLbjr3unSpCidQ3whccC6XyY013R12swN3bFZIu1gtzXCgUZ4U,iv:pVbrRwH3ziu4+R5BfimPV7N71QmyerJEc9M5K4eofOc=,tag:zNrCXrIioQWPEPVz/wMDpQ==,type:str]
|
||||||
typhon:
|
typhon:
|
||||||
hashedPassword: ENC[AES256_GCM,data:gMyY8gxUn3HzycQRu2cminqRFWghqWcjzZzTxAQZ5PJqn604iSwDiVdr7icHB7drJfCAfsE7L4oKRJgxaIAE32043oOkb2T7DDH8y2jxMzqmZCfbvrfMI4wdfRTHGqzxb6X/aZ5ai2rr1Q==,iv:4EsTo/lQld0o9iktDX9gobMlPUCitx1i9wn8EL16sIs=,tag:FgVDRHk2glDwpC/mprrPqQ==,type:str]
|
hashedPassword: ENC[AES256_GCM,data:gMyY8gxUn3HzycQRu2cminqRFWghqWcjzZzTxAQZ5PJqn604iSwDiVdr7icHB7drJfCAfsE7L4oKRJgxaIAE32043oOkb2T7DDH8y2jxMzqmZCfbvrfMI4wdfRTHGqzxb6X/aZ5ai2rr1Q==,iv:4EsTo/lQld0o9iktDX9gobMlPUCitx1i9wn8EL16sIs=,tag:FgVDRHk2glDwpC/mprrPqQ==,type:str]
|
||||||
|
garage:
|
||||||
|
rpc-secret: ENC[AES256_GCM,data:Q2ZaAXcntD3yK6DynEpxab2TITByMZ7ECVrq1pb0ZU7hXOZnhaBmjdty/Os6len8l+GBl6+WaC0An6cFkhQTlQ==,iv:E8C4bnxMLXK9fky+KC7q8sHpmrEU5un0TEAwxVUBiLk=,tag:PiSiU+9NpyilH2aMs2Qc/Q==,type:str]
|
||||||
|
admin-token: ENC[AES256_GCM,data:Xjm8Xq99aDseR0jN50Uj3gLpeDaq2IGXzJCS0o1H0RgKX9LGdP8w508nWWE=,iv:+L9T3TEUSbIz+jo08ykjGHVhuz5ecmzrlhzD2iv48HE=,tag:7P2rY4F8cWFdG4Lm9n/etQ==,type:str]
|
||||||
|
honeycomb:
|
||||||
|
api-key: ENC[AES256_GCM,data:k+Z3tmF8pYwD6RokdZauQ/fMlhD5GbW1ekxzRnj0gEpQFlfGB8gQ6BPwbd7qk12ZhsCA4XdqmvsysAWJldYWrPo=,iv:dNAK/vbQYL7ir4UXhZMTWraZF1E6ps9EOF3skYe5wOk=,tag:5UJfCji/RmB5DIuR4179uw==,type:str]
|
||||||
sops:
|
sops:
|
||||||
age:
|
age:
|
||||||
- recipient: age1qw5k8h72k3fjg5gmlxx8q8gwlc2k6n6u08d8hdzpm2pk9r0fnfxsmw33nh
|
- recipient: age1qw5k8h72k3fjg5gmlxx8q8gwlc2k6n6u08d8hdzpm2pk9r0fnfxsmw33nh
|
||||||
@@ -53,8 +58,8 @@ sops:
|
|||||||
cXNZWmZqd0R0SmhINExscHBKWmxvblUKEFEQvt/zQFARba4S8vHz/1SoKdKg69At
|
cXNZWmZqd0R0SmhINExscHBKWmxvblUKEFEQvt/zQFARba4S8vHz/1SoKdKg69At
|
||||||
LZ58XQGOmlGbBhPr7EzYQ2XSY4flWbnnD174cmCR8DNFm15DsNA5fw==
|
LZ58XQGOmlGbBhPr7EzYQ2XSY4flWbnnD174cmCR8DNFm15DsNA5fw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2026-01-17T01:50:50Z"
|
lastmodified: "2026-05-03T16:28:04Z"
|
||||||
mac: ENC[AES256_GCM,data:8TGSqwEcfmrW1PjuzTVNyDTNs6s3oWbT0tI+rg7u2w5Dcw1EEU+SjJ6VpNY06AZHTjSD6E0O7NzUxybtMpslHUGitOGWwQCk+sbqRJuUseFe7bWFboEVoJpEoYGN5pnn52opMT+NeHGkXumaxjhDjCxfwn1RBHR7TgD4ZHEH6pE=,iv:szBUnn3HL/osWhmTwYmHrUghobWdBR60Lc6uUD/eGMY=,tag:6vgdJeJjL4ZYKc8WjixClg==,type:str]
|
mac: ENC[AES256_GCM,data:dJ00o+Ny6btbOn7Pt5dc4iLx6FHJiTTx7onZDhjxya7Ywg2qAwHTiNP2q2aP6348w5uenlEGrgnV0Dc8xyHfApNCkJwj4G6UnI17jxEGn3lc0ZFNzJJ7jO2CJcwHir0E2G4XdPjmbZUdB3aKmM34dI9EEUWWhNFXdps4X0dNQcM=,iv:vOU3kHq0axRBrkNfVicQ/8H77nF0DGIJlpoDuJmwRGQ=,tag:uvoFkmaaTM8zpr1g2FpCMA==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2024-11-28T18:56:39Z"
|
- created_at: "2024-11-28T18:56:39Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
@@ -69,4 +74,4 @@ sops:
|
|||||||
-----END PGP MESSAGE-----
|
-----END PGP MESSAGE-----
|
||||||
fp: 5EFFB75F7C9B74EAA5C4637547940175096C1330
|
fp: 5EFFB75F7C9B74EAA5C4637547940175096C1330
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.11.0
|
version: 3.12.2
|
||||||
|
|||||||
@@ -19,4 +19,6 @@ rec {
|
|||||||
primary_torr = "${zfs_primary}/torr";
|
primary_torr = "${zfs_primary}/torr";
|
||||||
primary_plex = "${zfs_primary}/plex";
|
primary_plex = "${zfs_primary}/plex";
|
||||||
primary_plex_storage = "${zfs_primary}/plex_storage";
|
primary_plex_storage = "${zfs_primary}/plex_storage";
|
||||||
|
primary_ollama = "${zfs_primary}/ollama";
|
||||||
|
primary_mattermost = "${zfs_primary}/mattermost";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,86 @@
|
|||||||
{
|
{
|
||||||
boot = {
|
boot = {
|
||||||
zfs.extraPools = [ "ZFS-primary" ];
|
zfs.extraPools = [ "ZFS-primary" ];
|
||||||
|
zfs.requestEncryptionCredentials = false;
|
||||||
filesystem = "zfs";
|
filesystem = "zfs";
|
||||||
extraModprobeConfig = ''
|
extraModprobeConfig = ''
|
||||||
options zfs zfs_arc_min=82463372083
|
options zfs zfs_arc_min=82463372083
|
||||||
options zfs zfs_arc_max=192414534860
|
options zfs zfs_arc_max=192414534860
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
initrd.systemd.services = {
|
||||||
|
zfs-import-zfs-primary = {
|
||||||
|
description = "Import ZFS-primary pool in initrd";
|
||||||
|
wantedBy = [ "initrd-root-fs.target" ];
|
||||||
|
wants = [ "systemd-udev-settle.service" ];
|
||||||
|
after = [ "systemd-udev-settle.service" ];
|
||||||
|
before = [
|
||||||
|
"sysroot.mount"
|
||||||
|
"initrd-root-fs.target"
|
||||||
|
];
|
||||||
|
unitConfig.DefaultDependencies = "no";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
};
|
||||||
|
path = with pkgs; [
|
||||||
|
coreutils
|
||||||
|
gawk
|
||||||
|
zfs
|
||||||
|
];
|
||||||
|
script = ''
|
||||||
|
ZFS_FORCE="-f"
|
||||||
|
msg=""
|
||||||
|
|
||||||
|
for o in $(cat /proc/cmdline); do
|
||||||
|
case "$o" in
|
||||||
|
zfs_force|zfs_force=1|zfs_force=y)
|
||||||
|
ZFS_FORCE="-f"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
pool_ready() {
|
||||||
|
pool="$1"
|
||||||
|
state="$(zpool import -d /dev/disk/by-id/ 2>/dev/null | awk '/pool: '"$pool"'/ { found = 1 }; /state:/ { if (found == 1) { print $2; exit } }; END { if (found == 0) { print "MISSING" } }')"
|
||||||
|
if [ "$state" = "ONLINE" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "Pool $pool in state $state, waiting"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_imported() {
|
||||||
|
pool="$1"
|
||||||
|
zpool list "$pool" >/dev/null 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
pool_import() {
|
||||||
|
pool="$1"
|
||||||
|
zpool import -d /dev/disk/by-id/ -N $ZFS_FORCE "$pool"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo -n 'importing root ZFS pool "ZFS-primary"...'
|
||||||
|
# Loop until import succeeds, because by-id devices may not be discovered yet.
|
||||||
|
if ! pool_imported "ZFS-primary"; then
|
||||||
|
trial=1
|
||||||
|
while [ "$trial" -le 60 ]; do
|
||||||
|
if pool_ready "ZFS-primary" >/dev/null && msg="$(pool_import "ZFS-primary" 2>&1)"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
echo -n .
|
||||||
|
trial=$((trial + 1))
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
if [ -n "$msg" ]; then
|
||||||
|
echo "$msg"
|
||||||
|
fi
|
||||||
|
pool_imported "ZFS-primary" || pool_import "ZFS-primary" # Try one last time, e.g. to import a degraded pool.
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
@@ -31,6 +106,7 @@
|
|||||||
"ZFS-primary/docker".useTemplate = [ "production" ];
|
"ZFS-primary/docker".useTemplate = [ "production" ];
|
||||||
"ZFS-primary/hydra".useTemplate = [ "nix-prod" ];
|
"ZFS-primary/hydra".useTemplate = [ "nix-prod" ];
|
||||||
"ZFS-primary/nextcloud".useTemplate = [ "production" ];
|
"ZFS-primary/nextcloud".useTemplate = [ "production" ];
|
||||||
|
"ZFS-primary/mattermost".useTemplate = [ "production" ];
|
||||||
# all docker containers should have a bind mount if they expect lasting zfs snapshots
|
# all docker containers should have a bind mount if they expect lasting zfs snapshots
|
||||||
"ZFS-primary/vardocker".useTemplate = [ "nix-prod" ];
|
"ZFS-primary/vardocker".useTemplate = [ "nix-prod" ];
|
||||||
"ZFS-primary/minio".useTemplate = [ "nix-prod" ];
|
"ZFS-primary/minio".useTemplate = [ "nix-prod" ];
|
||||||
@@ -81,69 +157,4 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# hack to make sure pool is imported before keys are loaded,
|
|
||||||
# and also keys are imported before things get mounted
|
|
||||||
# note to self: move zfs encryption over to luks lol
|
|
||||||
boot.initrd.postResumeCommands = ''
|
|
||||||
ZFS_FORCE="-f"
|
|
||||||
|
|
||||||
for o in $(cat /proc/cmdline); do
|
|
||||||
case $o in
|
|
||||||
zfs_force|zfs_force=1|zfs_force=y)
|
|
||||||
ZFS_FORCE="-f"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
poolReady() {
|
|
||||||
pool="$1"
|
|
||||||
state="$("zpool" import -d "/dev/disk/by-id/" 2>/dev/null | "awk" "/pool: $pool/ { found = 1 }; /state:/ { if (found == 1) { print \$2; exit } }; END { if (found == 0) { print \"MISSING\" } }")"
|
|
||||||
if [[ "$state" = "ONLINE" ]]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
echo "Pool $pool in state $state, waiting"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
poolImported() {
|
|
||||||
pool="$1"
|
|
||||||
"zpool" list "$pool" >/dev/null 2>/dev/null
|
|
||||||
}
|
|
||||||
poolImport() {
|
|
||||||
pool="$1"
|
|
||||||
"zpool" import -d "/dev/disk/by-id/" -N $ZFS_FORCE "$pool"
|
|
||||||
}
|
|
||||||
|
|
||||||
echo -n "importing root ZFS pool \"ZFS-primary\"..."
|
|
||||||
# Loop across the import until it succeeds, because the devices needed may not be discovered yet.
|
|
||||||
if ! poolImported "ZFS-primary"; then
|
|
||||||
for trial in `seq 1 60`; do
|
|
||||||
poolReady "ZFS-primary" > /dev/null && msg="$(poolImport "ZFS-primary" 2>&1)" && break
|
|
||||||
sleep 1
|
|
||||||
echo -n .
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
if [[ -n "$msg" ]]; then
|
|
||||||
echo "$msg";
|
|
||||||
fi
|
|
||||||
poolImported "ZFS-primary" || poolImport "ZFS-primary" # Try one last time, e.g. to import a degraded pool.
|
|
||||||
fi
|
|
||||||
|
|
||||||
# let root mount and everything, then manually unlock stuff
|
|
||||||
load_zfs_nix() {
|
|
||||||
local device="/dev/disk/by-uuid/8bfaa32b-09dd-45c8-831e-05e80be82f9e"
|
|
||||||
local mountPoint="/"
|
|
||||||
local options="x-initrd.mount,noatime,nodiratime"
|
|
||||||
local fsType="ext4"
|
|
||||||
|
|
||||||
echo "manually mounting key location, then unmounting"
|
|
||||||
udevadm settle
|
|
||||||
|
|
||||||
mountFS "$device" "$(escapeFstab "$mountPoint")" "$(escapeFstab "$options")" "$fsType"
|
|
||||||
|
|
||||||
zfs load-key -L "file://$targetRoot/crypto/keys/zfs-nix-store-key" "ZFS-primary/nix"
|
|
||||||
umount "$targetRoot/"
|
|
||||||
}
|
|
||||||
|
|
||||||
load_zfs_nix
|
|
||||||
'';
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,8 @@
|
|||||||
glances
|
glances
|
||||||
gpu-viewer
|
gpu-viewer
|
||||||
grim
|
grim
|
||||||
helvum
|
|
||||||
htop
|
htop
|
||||||
hwloc
|
hwloc
|
||||||
ipmiview
|
|
||||||
iperf3
|
iperf3
|
||||||
# ipscan
|
# ipscan
|
||||||
jp2a
|
jp2a
|
||||||
@@ -80,8 +78,6 @@
|
|||||||
# signal in tray?
|
# signal in tray?
|
||||||
siji
|
siji
|
||||||
simple-mtpfs
|
simple-mtpfs
|
||||||
skaffold
|
|
||||||
slack
|
|
||||||
slurp
|
slurp
|
||||||
smartmontools
|
smartmontools
|
||||||
snyk
|
snyk
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
# let
|
|
||||||
# randWallpaper = pkgs.runCommand "stylix-wallpaper" { } ''
|
|
||||||
# numWallpapers =
|
|
||||||
# $((1 + $RANDOM % 10))
|
|
||||||
|
|
||||||
# in
|
|
||||||
{
|
{
|
||||||
stylix = {
|
stylix = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -66,7 +66,6 @@
|
|||||||
cargo-update
|
cargo-update
|
||||||
diesel-cli
|
diesel-cli
|
||||||
tealdeer
|
tealdeer
|
||||||
helix
|
|
||||||
ripunzip
|
ripunzip
|
||||||
|
|
||||||
# nix specific packages
|
# nix specific packages
|
||||||
@@ -86,11 +85,12 @@
|
|||||||
|
|
||||||
# dependencies for nix-dotfiles/hydra-check-action
|
# dependencies for nix-dotfiles/hydra-check-action
|
||||||
nodejs_20
|
nodejs_20
|
||||||
nodePackages.prettier
|
prettier
|
||||||
treefmt
|
treefmt
|
||||||
|
|
||||||
gocryptfs
|
gocryptfs
|
||||||
awscli2
|
awscli2
|
||||||
|
claurst
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -164,8 +164,9 @@
|
|||||||
userDirs = {
|
userDirs = {
|
||||||
enable = true;
|
enable = true;
|
||||||
createDirectories = true;
|
createDirectories = true;
|
||||||
|
setSessionVariables = true;
|
||||||
extraConfig = {
|
extraConfig = {
|
||||||
XDG_SCREENSHOTS_DIR = "${config.xdg.userDirs.pictures}/Screenshots";
|
SCREENSHOTS = "${config.xdg.userDirs.pictures}/Screenshots";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
lfs.enable = true;
|
lfs.enable = true;
|
||||||
signing = {
|
signing = {
|
||||||
key = "5EFFB75F7C9B74EAA5C4637547940175096C1330";
|
key = "5EFFB75F7C9B74EAA5C4637547940175096C1330";
|
||||||
|
format = "openpgp";
|
||||||
signByDefault = true;
|
signByDefault = true;
|
||||||
};
|
};
|
||||||
settings = {
|
settings = {
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
color.ui = true;
|
color.ui = true;
|
||||||
init.defaultBranch = "main";
|
init.defaultBranch = "main";
|
||||||
format.signoff = true;
|
format.signoff = true;
|
||||||
|
format.commitMessage = "signed-off-by";
|
||||||
pack.windowMemory = "2g";
|
pack.windowMemory = "2g";
|
||||||
pack.packSizeLimit = "1g";
|
pack.packSizeLimit = "1g";
|
||||||
user.email = "aliceghuston@gmail.com";
|
user.email = "aliceghuston@gmail.com";
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ gestures {
|
|||||||
|
|
||||||
misc {
|
misc {
|
||||||
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
# See https://wiki.hyprland.org/Configuring/Variables/ for more
|
||||||
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
force_default_wallpaper = 1 # Set to 0 or 1 to disable the anime mascot wallpapers
|
||||||
}
|
}
|
||||||
|
|
||||||
# Example per-device config
|
# Example per-device config
|
||||||
@@ -137,7 +137,7 @@ device {
|
|||||||
# Example windowrule v2
|
# Example windowrule v2
|
||||||
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
|
||||||
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
|
||||||
windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
|
windowrule = suppress_event maximize, match:class .* # You'll probably like this.
|
||||||
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
# See https://wiki.hyprland.org/Configuring/Keywords/ for more
|
||||||
|
|||||||
+230
-48
@@ -1,51 +1,224 @@
|
|||||||
{ pkgs, outputs, ... }:
|
{ pkgs, ... }:
|
||||||
|
let
|
||||||
{
|
tex = pkgs.texlive.combine {
|
||||||
programs.emacs = {
|
inherit (pkgs.texlive)
|
||||||
enable = true;
|
scheme-medium
|
||||||
package = pkgs.emacs30-pgtk;
|
preprint
|
||||||
|
titlesec
|
||||||
|
enumitem
|
||||||
|
sourcesanspro
|
||||||
|
xifthen
|
||||||
|
ifmtarg
|
||||||
|
framed
|
||||||
|
paralist
|
||||||
|
fontawesome7
|
||||||
|
;
|
||||||
};
|
};
|
||||||
programs.vesktop = {
|
in
|
||||||
enable = true;
|
{
|
||||||
settings = {
|
programs = {
|
||||||
appBadge = false;
|
emacs = {
|
||||||
arRPC = true;
|
enable = true;
|
||||||
checkUpdates = false;
|
package = pkgs.emacs30-pgtk;
|
||||||
customTitleBar = false;
|
|
||||||
hardwareAcceleration = true;
|
|
||||||
};
|
};
|
||||||
vencord.useSystem = true;
|
vesktop = {
|
||||||
vencord.settings = {
|
enable = true;
|
||||||
autoUpdate = false;
|
settings = {
|
||||||
autoUpdateNotification = false;
|
appBadge = false;
|
||||||
notifyAboutUpdates = false;
|
arRPC = true;
|
||||||
plugins = {
|
checkUpdates = false;
|
||||||
AnonymiseFileNames.enabled = true;
|
customTitleBar = false;
|
||||||
BetterFolders.enabled = true;
|
hardwareAcceleration = true;
|
||||||
BetterGifAltText.enabled = true;
|
};
|
||||||
CallTimer.enabled = true;
|
vencord.useSystem = true;
|
||||||
ClearURLs.enabled = true;
|
vencord.settings = {
|
||||||
CopyFileContents.enabled = true;
|
autoUpdate = false;
|
||||||
CtrlEnterSend.enabled = true;
|
autoUpdateNotification = false;
|
||||||
CustomIdle = {
|
notifyAboutUpdates = false;
|
||||||
enabled = true;
|
plugins = {
|
||||||
remainInIdle = false;
|
AnonymiseFileNames.enabled = true;
|
||||||
|
BetterFolders.enabled = false;
|
||||||
|
BetterGifAltText.enabled = true;
|
||||||
|
CallTimer.enabled = true;
|
||||||
|
ClearURLs.enabled = true;
|
||||||
|
CopyFileContents.enabled = true;
|
||||||
|
CtrlEnterSend.enabled = true;
|
||||||
|
CustomIdle = {
|
||||||
|
enabled = true;
|
||||||
|
remainInIdle = false;
|
||||||
|
};
|
||||||
|
FriendsSince.enabled = true;
|
||||||
|
GameActivityToggle.enabled = true;
|
||||||
|
ImplicitRelationships.enabled = true;
|
||||||
|
MutualGroupDMs.enabled = true;
|
||||||
|
QuickMention.enabled = true;
|
||||||
|
QuickReply.enabled = true;
|
||||||
|
ReplaceGoogleSearch = {
|
||||||
|
enabled = true;
|
||||||
|
customEngineName = "DuckDuckGo";
|
||||||
|
};
|
||||||
|
ReviewDB.enabled = true;
|
||||||
|
ShowConnections.enabled = true;
|
||||||
};
|
};
|
||||||
FriendsSince.enabled = true;
|
};
|
||||||
GameActivityToggle.enabled = true;
|
};
|
||||||
ImplicitRelationships.enabled = true;
|
zed-editor = {
|
||||||
MutualGroupDMs.enabled = true;
|
enable = true;
|
||||||
QuickMention.enabled = true;
|
mutableUserSettings = false;
|
||||||
QuickReply.enabled = true;
|
extensions = [
|
||||||
ReplaceGoogleSearch = {
|
"nix"
|
||||||
enabled = true;
|
"toml"
|
||||||
customEngineName = "DuckDuckGo";
|
"rust"
|
||||||
|
"java"
|
||||||
|
"kotlin"
|
||||||
|
"git firefly"
|
||||||
|
"make"
|
||||||
|
"dockerfile"
|
||||||
|
"sql"
|
||||||
|
"latex"
|
||||||
|
"terraform"
|
||||||
|
"log"
|
||||||
|
"context7-mcp-server"
|
||||||
|
"github-mcp-server"
|
||||||
|
];
|
||||||
|
userSettings = {
|
||||||
|
context_servers = {
|
||||||
|
nixos = {
|
||||||
|
command = "nix";
|
||||||
|
args = [
|
||||||
|
"run"
|
||||||
|
"github:utensils/mcp-nixos"
|
||||||
|
"--"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
ReviewDB.enabled = true;
|
language_models = {
|
||||||
ShowConnections.enabled = true;
|
ollama = {
|
||||||
|
api_url = "http://192.168.76.2:11434";
|
||||||
|
context_window = 128000;
|
||||||
|
# global keep alive doesnt work
|
||||||
|
#keep_alive = "15m";
|
||||||
|
available_models = [
|
||||||
|
{
|
||||||
|
name = "deepseek-r1:1.5b";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "deepseek-r1:32b";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "deepseek-r1:70b";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "qwen3-coder-next";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "lennyerik/zeta";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "nomic-embed-text:latest";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "lfm2:24b";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "glm-4.7-flash";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "nemotron-cascade-2:30b";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "magistral";
|
||||||
|
max_tokens = 128000;
|
||||||
|
keep_alive = "15m";
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
colorize_brackets = true;
|
||||||
|
hard_tabs = false;
|
||||||
|
vim_mode = true;
|
||||||
|
minimap = {
|
||||||
|
show = "auto";
|
||||||
|
};
|
||||||
|
buffer_line_height = "comfortable";
|
||||||
|
auto_update = false;
|
||||||
|
autosave = "on_focus_change";
|
||||||
|
agent = {
|
||||||
|
default_model = {
|
||||||
|
provider = "ollama";
|
||||||
|
model = "glm-4.7-flash";
|
||||||
|
};
|
||||||
|
favorite_models = [ ];
|
||||||
|
model_parameters = [ ];
|
||||||
|
};
|
||||||
|
telemetry = {
|
||||||
|
diagnostics = false;
|
||||||
|
metrics = false;
|
||||||
|
};
|
||||||
|
journal = {
|
||||||
|
hour_format = "hour24";
|
||||||
|
};
|
||||||
|
edit_predictions = {
|
||||||
|
provider = "ollama";
|
||||||
|
ollama = {
|
||||||
|
#api_url = "http://192.168.76.2:11434/v1/completions";
|
||||||
|
api_url = "http://192.168.76.2:11434";
|
||||||
|
context_window = 128000;
|
||||||
|
model = "lennyerik/zeta";
|
||||||
|
prompt_format = "qwen";
|
||||||
|
max_requests = 64;
|
||||||
|
max_output_tokens = 256;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
texlab = {
|
||||||
|
build = {
|
||||||
|
onSave = true;
|
||||||
|
forwardSearchAfter = true;
|
||||||
|
};
|
||||||
|
#forwardSearch = {
|
||||||
|
# #executable = "zathura";
|
||||||
|
# args = [
|
||||||
|
# "--synctex-forward"
|
||||||
|
# "%l:1:%f"
|
||||||
|
# "-x"
|
||||||
|
# "zed %%{input}:%%{line}"
|
||||||
|
# "%p"
|
||||||
|
# ];
|
||||||
|
#};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
rbw = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
lockTimeout = 300;
|
||||||
|
pinentry = pkgs.pinentry-gnome3;
|
||||||
|
email = "snowinginwonderland@gmail.com";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.gnome-keyring.enable = true;
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
cmake
|
cmake
|
||||||
shellcheck
|
shellcheck
|
||||||
@@ -70,12 +243,14 @@
|
|||||||
nix-init
|
nix-init
|
||||||
|
|
||||||
# markdown
|
# markdown
|
||||||
nodePackages.markdownlint-cli
|
markdownlint-cli
|
||||||
|
|
||||||
|
# insert essential rust dependencies
|
||||||
|
|
||||||
# doom emacs dependencies
|
# doom emacs dependencies
|
||||||
yaml-language-server
|
yaml-language-server
|
||||||
nodePackages.typescript-language-server
|
typescript-language-server
|
||||||
nodePackages.bash-language-server
|
bash-language-server
|
||||||
pyright
|
pyright
|
||||||
cmake-language-server
|
cmake-language-server
|
||||||
multimarkdown
|
multimarkdown
|
||||||
@@ -91,18 +266,18 @@
|
|||||||
languagetool
|
languagetool
|
||||||
|
|
||||||
# latex
|
# latex
|
||||||
texlive.combined.scheme-medium
|
tex
|
||||||
|
poppler-utils
|
||||||
|
|
||||||
# dependencies for nix-dotfiles/hydra-check-action
|
# dependencies for nix-dotfiles/hydra-check-action
|
||||||
nodejs_20
|
nodejs_20
|
||||||
nodePackages.prettier
|
prettier
|
||||||
treefmt
|
treefmt
|
||||||
|
|
||||||
nextcloud-client
|
nextcloud-client
|
||||||
bitwarden-cli
|
bitwarden-cli
|
||||||
bitwarden-menu
|
rofi-rbw-wayland
|
||||||
wtype
|
wtype
|
||||||
zathura
|
|
||||||
obsidian
|
obsidian
|
||||||
libreoffice-qt-fresh
|
libreoffice-qt-fresh
|
||||||
wlr-randr
|
wlr-randr
|
||||||
@@ -112,5 +287,12 @@
|
|||||||
|
|
||||||
# arch zed deps
|
# arch zed deps
|
||||||
nixd
|
nixd
|
||||||
|
uv
|
||||||
|
|
||||||
|
pdf4qt
|
||||||
|
masterpdfeditor4
|
||||||
|
|
||||||
|
gitea-mcp-server
|
||||||
|
tea
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ alice:
|
|||||||
attic-nix-cache-admin: ENC[AES256_GCM,data:xHJGeU4EUn1HRy2nIValiJ6iLZnYmmT6Njv/cGMh15Q0hJXKNBSsi8f0mAfLI7EX+GaC299VKh2uTlU25jptrAvogLxNJIc+LZBLsSkyGE/ojqqevHMKmZ/6eciLZRQL5ey9TM3V9HHyDOhGaFgdfawtwg/vyvbV13lZBKpqneAX9T3gPRuKRjV4/Uc/5cUckiOF8bQ50xVFN8Cql9HgGDJEGWgg4XUTPu5eYspof2EN63pYvU7wg6HD2begeLDvqc2/i2DIcsc0wqc5DgkY/dH2YtcssBtU8AR9vKpl+HmH/wvt6dfaEyZ7hF7ITGwWnOO6H2ko3SjYRfHkFK3XDmm1YRRjfkptnw==,iv:BdVgNyZ1azl5tKfH+RTeXuNV/rYY6hPvrareKlIXSeQ=,tag:/ar87eAjMod4TmQXoerNBQ==,type:str]
|
attic-nix-cache-admin: ENC[AES256_GCM,data:xHJGeU4EUn1HRy2nIValiJ6iLZnYmmT6Njv/cGMh15Q0hJXKNBSsi8f0mAfLI7EX+GaC299VKh2uTlU25jptrAvogLxNJIc+LZBLsSkyGE/ojqqevHMKmZ/6eciLZRQL5ey9TM3V9HHyDOhGaFgdfawtwg/vyvbV13lZBKpqneAX9T3gPRuKRjV4/Uc/5cUckiOF8bQ50xVFN8Cql9HgGDJEGWgg4XUTPu5eYspof2EN63pYvU7wg6HD2begeLDvqc2/i2DIcsc0wqc5DgkY/dH2YtcssBtU8AR9vKpl+HmH/wvt6dfaEyZ7hF7ITGwWnOO6H2ko3SjYRfHkFK3XDmm1YRRjfkptnw==,iv:BdVgNyZ1azl5tKfH+RTeXuNV/rYY6hPvrareKlIXSeQ=,tag:/ar87eAjMod4TmQXoerNBQ==,type:str]
|
||||||
gitea-actions-token: ENC[AES256_GCM,data:QTEPMAh1RWWJ/O3yhkQkEBTdVL8XhIRGCDbiM0lLjfILKF4SpSJ2sA==,iv:mBaaB1JHb2KVc9n2pdeX4pSMvb7q5z3joMT7rR5Whgs=,tag:ef+58SI4AUeqUsk3RVDsRQ==,type:str]
|
gitea-actions-token: ENC[AES256_GCM,data:QTEPMAh1RWWJ/O3yhkQkEBTdVL8XhIRGCDbiM0lLjfILKF4SpSJ2sA==,iv:mBaaB1JHb2KVc9n2pdeX4pSMvb7q5z3joMT7rR5Whgs=,tag:ef+58SI4AUeqUsk3RVDsRQ==,type:str]
|
||||||
gitea-pr-token: ENC[AES256_GCM,data:ybTya4X2wd65pNFSGbQkg73lu66GNtSba4yf8J6tT8XkuOtfvtBS4g==,iv:39mJiAlw4kud4l06jOpxOCRumChE/5q8IBNsPHG1rMc=,tag:MEvHD2b9E3fVHLlz7haNyw==,type:str]
|
gitea-pr-token: ENC[AES256_GCM,data:ybTya4X2wd65pNFSGbQkg73lu66GNtSba4yf8J6tT8XkuOtfvtBS4g==,iv:39mJiAlw4kud4l06jOpxOCRumChE/5q8IBNsPHG1rMc=,tag:MEvHD2b9E3fVHLlz7haNyw==,type:str]
|
||||||
|
honeycomb-id: ENC[AES256_GCM,data:PndCclCbSMrgmlYdQ5a8//IB+hg9uB0ZwidIZFiKN6w=,iv:mxFcGPnY0eCliugvQT5HR9aGzJIvXZI6FTo8rphVQMM=,tag:3huIaIy7da0gx2G/BVJJLQ==,type:str]
|
||||||
|
honeycomb-secret: ENC[AES256_GCM,data:x2MZPgAJz3I1m+rjSVpINZdQVbu50XiwEtPGEX/kbJw=,iv:bPNNtXIES0pCLc4Nu/886nwoOVXaZgyTxndSpyWWU0E=,tag:igdd/NPCDpcvzSd9LO4hyw==,type:str]
|
||||||
sops:
|
sops:
|
||||||
age:
|
age:
|
||||||
- recipient: age1qw5k8h72k3fjg5gmlxx8q8gwlc2k6n6u08d8hdzpm2pk9r0fnfxsmw33nh
|
- recipient: age1qw5k8h72k3fjg5gmlxx8q8gwlc2k6n6u08d8hdzpm2pk9r0fnfxsmw33nh
|
||||||
@@ -39,8 +41,8 @@ sops:
|
|||||||
ZERFTlFyNjhOb3VCaW43ZXFHT1Vxc0UK7YV+BU7dCEOZxpqkQA394eDsnthvorj6
|
ZERFTlFyNjhOb3VCaW43ZXFHT1Vxc0UK7YV+BU7dCEOZxpqkQA394eDsnthvorj6
|
||||||
7bqrCdeU+6DU7DmFs6++BrNO2tx8vvOa1im+ZGrM/gZAJdv/7R2d6Q==
|
7bqrCdeU+6DU7DmFs6++BrNO2tx8vvOa1im+ZGrM/gZAJdv/7R2d6Q==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-04-07T23:43:57Z"
|
lastmodified: "2026-05-03T16:20:31Z"
|
||||||
mac: ENC[AES256_GCM,data:ygQzxSpGJqXwkOq7jGDeflA2FTSSxnre/PXm0LxmxzQQW5s7LeIVSI75fMqWir0WU3Pi/xroYGEWjpCG6JvxV5RiJycTONk8VE7c3jtw3AbrHSS0b1K5tJ+Sf+q3rHJFWWk/COrPk8IsRFNb+taqH4jnaH3AAVNo5u0C1CHKMes=,iv:FO2GVDXE8SjjA81/9cDwc+dX8kJ2oHt5kqkhNBuMb54=,tag:hgzRAmsh32SCvJEvKyV+vg==,type:str]
|
mac: ENC[AES256_GCM,data:/Ui0H0wgENYnzVB7V2aAbj4dIbE+sjRpPoso75xyKepmeeMp8nv8CJLKmLmtbp+rtX287teVw4hKxb/z8M6ZHIWmgt9Zgui8/+hw5hwuMmyjPeGqJQjFH8s4zcXkOKLDoFPA65gva5gaPsreqPwOSqgqYwmds5gOcxBI3Tqdh6E=,iv:ugtug8Vb7DRUp1eC2M6ooCoPFjbqZo8htHOV4AXIcSI=,tag:4sMJsh/r57Z4VFoOBmUmXw==,type:str]
|
||||||
pgp:
|
pgp:
|
||||||
- created_at: "2024-09-05T06:10:22Z"
|
- created_at: "2024-09-05T06:10:22Z"
|
||||||
enc: |-
|
enc: |-
|
||||||
@@ -55,4 +57,4 @@ sops:
|
|||||||
-----END PGP MESSAGE-----
|
-----END PGP MESSAGE-----
|
||||||
fp: 5EFFB75F7C9B74EAA5C4637547940175096C1330
|
fp: 5EFFB75F7C9B74EAA5C4637547940175096C1330
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.10.1
|
version: 3.12.2
|
||||||
|
|||||||
@@ -28,6 +28,8 @@
|
|||||||
"plugdev"
|
"plugdev"
|
||||||
"uaccess"
|
"uaccess"
|
||||||
"ydotool"
|
"ydotool"
|
||||||
|
"video"
|
||||||
|
"render"
|
||||||
]
|
]
|
||||||
++ groups;
|
++ groups;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user