Compare commits
97 Commits
f918ff5df2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7fd79c9911 | |||
| 41eacfec02 | |||
| 0a0748b920 | |||
| d6e0e09e87 | |||
| 61c3020a5e | |||
| 972b973f58 | |||
| 8c5a7b78c6 | |||
| 675204816a | |||
| 3bb82dbc6b | |||
| 0f6233c3ec | |||
| 43fa56bf35 | |||
| 50c930eeaf | |||
| 8dde15b8ef | |||
| 6100d8dc69 | |||
| a92f0fcb28 | |||
| bd4604cdcc | |||
| 31db372b43 | |||
| 360e776745 | |||
| 5a819f70bb | |||
| b2c055ffb2 | |||
| 6e0b34843b | |||
| e8485e3bb7 | |||
| e8cd970960 | |||
| 78b59cec4f | |||
| e6d40a9f7e | |||
| 7733a1be46 | |||
| a5df98bc5a | |||
| fb9b0dd2f5 | |||
| 0dc214069c | |||
| a6c4be9530 | |||
| 6e338e6d65 | |||
| 41f16fa0b8 | |||
| 1b05728817 | |||
| 520a417316 | |||
| 88ed5360ca | |||
| 392d40def3 | |||
| 5ef4d832fb | |||
| 49afc0c084 | |||
| b2c82ceaa8 | |||
| b9286d7243 | |||
| 22931e6747 | |||
| ac030018c6 | |||
| 7386d3a5ee | |||
| 2a5a9f2ee9 | |||
| 963a7c10fa | |||
| 283cf9d614 | |||
| 5b3b4ea2ed | |||
| 5a9d5de5c4 | |||
| a5e3f613c2 | |||
| 8b8fac2d89 | |||
| 31d79ba75b | |||
| 6faf148fde | |||
| e88f1c93c5 | |||
| 51375db1e4 | |||
| 9415a8ece2 | |||
| da85ee776d | |||
| e23dc7df5b | |||
| 163b9e4c22 | |||
| d521c3b013 | |||
| d123400ea9 | |||
| 9c64a8ec00 | |||
| 4907238726 | |||
| 37aad7d951 | |||
| ac34f029ed | |||
| 8d04add7dc | |||
| d7a07cebf5 | |||
| 2ba961bfa8 | |||
| 765e92f9c7 | |||
| 1bb202d017 | |||
| 98769f59d6 | |||
| 762037d17f | |||
| 32a22c783d | |||
| 8c29c18287 | |||
| 092a8b3658 | |||
| c7ff79d0c3 | |||
| ac51f50ef5 | |||
| c5347b6eba | |||
| d4525313bb | |||
| 92a27ac92b | |||
| fabfeea1c2 | |||
| 5ce0e0e1df | |||
| bd473d1ad2 | |||
| 064d227344 | |||
| dd8fee0ecb | |||
| a2b54be875 | |||
| ccf6154ba0 | |||
| bd5988dfbc | |||
| a57fc9107b | |||
| a7dce7cfb9 | |||
| b608e110c9 | |||
| 78dee346e9 | |||
| 66f26842c9 | |||
| 9c504e0278 | |||
| 4035d38ab2 | |||
| 53ef2f6293 | |||
| e5cd9bd98e | |||
| 0b51b44856 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@
|
|||||||
.tmp
|
.tmp
|
||||||
result
|
result
|
||||||
.aider*
|
.aider*
|
||||||
|
.claude
|
||||||
|
.direnv/
|
||||||
|
|||||||
23
.sops.yaml
23
.sops.yaml
@@ -2,10 +2,12 @@ keys:
|
|||||||
- &admin_ppetru age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
- &admin_ppetru age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
- &server_zippy age1gtyw202hd07hddac9886as2cs8pm07e4exlnrgfm72lync75ng9qc5fjac
|
- &server_zippy age1gtyw202hd07hddac9886as2cs8pm07e4exlnrgfm72lync75ng9qc5fjac
|
||||||
- &server_chilly age16yqffw4yl5jqvsr7tyd883vn98zw0attuv9g5snc329juff6dy3qw2w5wp
|
- &server_chilly age16yqffw4yl5jqvsr7tyd883vn98zw0attuv9g5snc329juff6dy3qw2w5wp
|
||||||
- &server_sparky age1zxf8263nk04zf4pu5x2czh6g4trv4e2xydypyjschyekr6udqcsqmrgv68
|
- &server_sparky age14aml5s3sxksa8qthnt6apl3pu6egxyn0cz7pdzzvp2yl6wncad0q56udyj
|
||||||
|
- &server_stinky age1me78u46409q9ez6fj0qanrfffc5e9kuq7n7uuvlljfwwc2mdaezqmyzxhx
|
||||||
|
- &server_beefy age1cs8uqj243lspyp042ueu5aes4t3azgyuaxl9au70ggrl2meulq4sgqpc7y
|
||||||
- &server_alo_cloud_1 age1w5w4wfvtul3sge9mt205zvrkjaeh3qs9gsxhmq7df2g4dztnvv6qylup8z
|
- &server_alo_cloud_1 age1w5w4wfvtul3sge9mt205zvrkjaeh3qs9gsxhmq7df2g4dztnvv6qylup8z
|
||||||
- &server_c1 age1wwufz86tm3auxn6pn27c47s8rvu7en58rk00nghtaxsdpw0gya6qj6qxdt
|
- &server_c1 age1wwufz86tm3auxn6pn27c47s8rvu7en58rk00nghtaxsdpw0gya6qj6qxdt
|
||||||
- &server_c2 age1c2kc034n7tqztarcu7n5ldnjmy9sr3jgwrsaddsj0hwfus9mdp3sctts4m
|
- &server_c2 age1jy7pe4530s8w904wtvrmpxvteztqy5ewdt92a7y3lq87sg9jce5qxxuydt
|
||||||
- &server_c3 age1zjgqu3zks5kvlw6hvy6ytyygq7n25lu0uj2435zlf30smpxuy4hshpmfer
|
- &server_c3 age1zjgqu3zks5kvlw6hvy6ytyygq7n25lu0uj2435zlf30smpxuy4hshpmfer
|
||||||
creation_rules:
|
creation_rules:
|
||||||
- path_regex: secrets/common\.yaml
|
- path_regex: secrets/common\.yaml
|
||||||
@@ -15,6 +17,8 @@ creation_rules:
|
|||||||
- *server_zippy
|
- *server_zippy
|
||||||
- *server_chilly
|
- *server_chilly
|
||||||
- *server_sparky
|
- *server_sparky
|
||||||
|
- *server_stinky
|
||||||
|
- *server_beefy
|
||||||
- *server_alo_cloud_1
|
- *server_alo_cloud_1
|
||||||
- *server_c1
|
- *server_c1
|
||||||
- *server_c2
|
- *server_c2
|
||||||
@@ -34,6 +38,21 @@ creation_rules:
|
|||||||
- age:
|
- age:
|
||||||
- *admin_ppetru
|
- *admin_ppetru
|
||||||
- *server_sparky
|
- *server_sparky
|
||||||
|
- path_regex: secrets/stinky\.yaml
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *admin_ppetru
|
||||||
|
- *server_stinky
|
||||||
|
- path_regex: secrets/beefy\.yaml
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *admin_ppetru
|
||||||
|
- *server_beefy
|
||||||
|
- path_regex: secrets/wifi\.yaml
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *admin_ppetru
|
||||||
|
- *server_stinky
|
||||||
- path_regex: secrets/alo-cloud-1\.yaml
|
- path_regex: secrets/alo-cloud-1\.yaml
|
||||||
key_groups:
|
key_groups:
|
||||||
- age:
|
- age:
|
||||||
|
|||||||
100
CLAUDE.md
100
CLAUDE.md
@@ -6,47 +6,67 @@ NixOS cluster configuration using flakes. Homelab infrastructure with Nomad/Cons
|
|||||||
|
|
||||||
```
|
```
|
||||||
├── common/
|
├── common/
|
||||||
│ ├── global/ # Applied to all hosts (backup, sops, users, etc.)
|
│ ├── global/ # Applied to all hosts (backup, sops, users, etc.)
|
||||||
│ ├── compute-node.nix # Nomad client + Consul agent + NFS client
|
│ ├── minimal-node.nix # Base (ssh, user, boot, impermanence)
|
||||||
│ ├── cluster-node.nix # Nomad server + Consul server (for quorum members)
|
│ ├── cluster-member.nix # Consul agent + storage mounts (NFS/CIFS)
|
||||||
│ ├── nfs-services-server.nix # NFS server + btrfs replication (zippy)
|
│ ├── nomad-worker.nix # Nomad client (runs jobs) + Docker + NFS deps
|
||||||
│ └── nfs-services-standby.nix # NFS standby + receive replication (c1, c2)
|
│ ├── nomad-server.nix # Enables Consul + Nomad server mode
|
||||||
├── hosts/
|
│ ├── cluster-tools.nix # Just CLI tools (nomad, wander, damon)
|
||||||
│ ├── c1/, c2/, c3/ # Cattle nodes (compute, quorum members)
|
│ ├── workstation-node.nix # Dev tools (wget, deploy-rs, docker, nix-ld)
|
||||||
│ ├── zippy/ # Primary storage + NFS server + stateful workloads
|
│ ├── desktop-node.nix # Hyprland + GUI environment
|
||||||
│ ├── fractal/ # (Proxmox, will become NixOS storage node)
|
│ ├── nfs-services-server.nix # NFS server + btrfs replication
|
||||||
│ ├── sunny/ # (Standalone ethereum node, not in cluster)
|
│ └── nfs-services-standby.nix # NFS standby + receive replication
|
||||||
│ └── chilly/ # (Home Assistant VM, not in cluster)
|
├── hosts/ # Host configs - check imports for roles
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── CLUSTER_REVAMP.md # Master plan for architecture changes
|
│ ├── CLUSTER_REVAMP.md # Master plan for architecture changes
|
||||||
│ ├── MIGRATION_TODO.md # Tracking checklist for migration
|
│ ├── MIGRATION_TODO.md # Tracking checklist for migration
|
||||||
│ └── NFS_FAILOVER.md # NFS failover procedures
|
│ ├── NFS_FAILOVER.md # NFS failover procedures
|
||||||
|
│ └── AUTH_SETUP.md # Authentication (Pocket ID + Traefik OIDC)
|
||||||
└── services/ # Nomad job specs (.hcl files)
|
└── services/ # Nomad job specs (.hcl files)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Current Architecture (transitioning)
|
## Current Architecture
|
||||||
|
|
||||||
**OLD**: GlusterFS on c1/c2/c3 at `/data/compute` (being phased out)
|
|
||||||
**NEW**: NFS from zippy at `/data/services` (current target)
|
|
||||||
|
|
||||||
### Storage Mounts
|
### Storage Mounts
|
||||||
- `/data/services` - NFS from `data-services.service.consul` (zippy primary, c1 standby)
|
- `/data/services` - NFS from `data-services.service.consul` (check nfs-services-server.nix for primary)
|
||||||
- `/data/media` - CIFS from fractal (existing, unchanged)
|
- `/data/media` - CIFS from fractal
|
||||||
- `/data/shared` - CIFS from fractal (existing, unchanged)
|
- `/data/shared` - CIFS from fractal
|
||||||
|
|
||||||
### Hosts
|
### Cluster Roles (check hosts/*/default.nix for each host's imports)
|
||||||
- **c1, c2, c3**: Cattle nodes, run most workloads, Nomad/Consul quorum
|
- **Quorum**: hosts importing `nomad-server.nix` (3 expected for consensus)
|
||||||
- **zippy**: Primary NFS server, runs databases (affinity), replicates to c1 every 5min
|
- **Workers**: hosts importing `nomad-worker.nix` (run Nomad jobs)
|
||||||
- **fractal**: Storage node (Proxmox/ZFS), will join quorum after GlusterFS removed
|
- **NFS server**: host importing `nfs-services-server.nix` (affinity for direct disk access like DBs)
|
||||||
- **sunny**: Standalone ethereum staking node
|
- **Standby**: hosts importing `nfs-services-standby.nix` (receive replication)
|
||||||
- **chilly**: Home Assistant VM
|
|
||||||
|
## Config Architecture
|
||||||
|
|
||||||
|
**Modular role-based configs** (compose as needed):
|
||||||
|
- `minimal-node.nix` - Base for all systems (SSH, user, boot, impermanence)
|
||||||
|
- `cluster-member.nix` - Consul agent + shared storage mounts (no Nomad)
|
||||||
|
- `nomad-worker.nix` - Nomad client to run jobs (requires cluster-member)
|
||||||
|
- `nomad-server.nix` - Enables Consul + Nomad server mode (for quorum members)
|
||||||
|
- `cluster-tools.nix` - Just CLI tools (no services)
|
||||||
|
|
||||||
|
**Machine type configs** (via flake profile):
|
||||||
|
- `workstation-node.nix` - Dev tools (deploy-rs, docker, nix-ld, emulation)
|
||||||
|
- `desktop-node.nix` - Extends workstation + Hyprland/GUI
|
||||||
|
|
||||||
|
**Composition patterns**:
|
||||||
|
- Quorum member: `cluster-member + nomad-worker + nomad-server`
|
||||||
|
- Worker only: `cluster-member + nomad-worker`
|
||||||
|
- CLI only: `cluster-member + cluster-tools` (Consul agent, no Nomad service)
|
||||||
|
- NFS primary: `cluster-member + nomad-worker + nfs-services-server`
|
||||||
|
- Standalone: `minimal-node` only (no cluster membership)
|
||||||
|
|
||||||
|
**Key insight**: Profiles (workstation/desktop) don't imply cluster roles. Check imports for actual roles.
|
||||||
|
|
||||||
## Key Patterns
|
## Key Patterns
|
||||||
|
|
||||||
**NFS Server/Standby**:
|
**NFS Server/Standby**:
|
||||||
- Primary (zippy): imports `nfs-services-server.nix`, sets `standbys = ["c1"]`
|
- Primary: imports `nfs-services-server.nix`, sets `standbys = [...]`
|
||||||
- Standby (c1): imports `nfs-services-standby.nix`, sets `replicationKeys = [...]`
|
- Standby: imports `nfs-services-standby.nix`, sets `replicationKeys = [...]`
|
||||||
- Replication: btrfs send/receive every 5min, incremental with fallback to full
|
- Replication: btrfs send/receive every 5min, incremental with fallback to full
|
||||||
|
- Check host configs for current primary/standby assignments
|
||||||
|
|
||||||
**Backups**:
|
**Backups**:
|
||||||
- Kopia client on all nodes → Kopia server on fractal
|
- Kopia client on all nodes → Kopia server on fractal
|
||||||
@@ -57,28 +77,26 @@ NixOS cluster configuration using flakes. Homelab infrastructure with Nomad/Cons
|
|||||||
- SOPS for secrets, files in `secrets/`
|
- SOPS for secrets, files in `secrets/`
|
||||||
- Keys managed per-host
|
- Keys managed per-host
|
||||||
|
|
||||||
|
**Authentication**:
|
||||||
|
- Pocket ID (OIDC provider) at `pocket-id.v.paler.net`
|
||||||
|
- Traefik uses `traefik-oidc-auth` plugin for SSO
|
||||||
|
- Services add `middlewares=oidc-auth@file` tag to protect
|
||||||
|
- See `docs/AUTH_SETUP.md` for details
|
||||||
|
|
||||||
## Migration Status
|
## Migration Status
|
||||||
|
|
||||||
**Phase**: 4 in progress (20/35 services migrated)
|
**Phase 3 & 4**: COMPLETE! GlusterFS removed, all services on NFS
|
||||||
**Current**: Migrating services from GlusterFS → NFS
|
**Next**: Convert fractal to NixOS (deferred)
|
||||||
**Next**: Finish migrating remaining services, update host volumes, remove GlusterFS
|
|
||||||
**Later**: Convert fractal to NixOS (deferred)
|
|
||||||
|
|
||||||
See `docs/MIGRATION_TODO.md` for detailed checklist.
|
See `docs/MIGRATION_TODO.md` for detailed checklist.
|
||||||
|
|
||||||
**IMPORTANT**: When working on migration tasks:
|
|
||||||
1. Always update `docs/MIGRATION_TODO.md` after completing each service migration
|
|
||||||
2. Update both the individual service checklist AND the summary counts at the bottom
|
|
||||||
3. Pattern: `/data/compute/appdata/foo` → `/data/services/foo` (NOT `/data/services/appdata/foo`!)
|
|
||||||
4. Migration workflow per service: stop → copy data → edit config → start → update MIGRATION_TODO.md
|
|
||||||
|
|
||||||
## Common Tasks
|
## Common Tasks
|
||||||
|
|
||||||
**Deploy a host**: `deploy -s '.#hostname'`
|
**Deploy a host**: `deploy -s '.#hostname'`
|
||||||
**Deploy all**: `deploy`
|
**Deploy all**: `deploy`
|
||||||
**Check replication**: `ssh zippy journalctl -u replicate-services-to-c1.service -f`
|
**Check replication**: Check NFS primary host, then `ssh <primary> journalctl -u replicate-services-to-*.service -f`
|
||||||
**NFS failover**: See `docs/NFS_FAILOVER.md`
|
**NFS failover**: See `docs/NFS_FAILOVER.md`
|
||||||
**Nomad jobs**: `services/*.hcl` - update paths: `/data/compute/appdata/foo` → `/data/services/foo` (NOT `/data/services/appdata/foo`!)
|
**Nomad jobs**: `services/*.hcl` - service data stored at `/data/services/<service-name>`
|
||||||
|
|
||||||
## Troubleshooting Hints
|
## Troubleshooting Hints
|
||||||
|
|
||||||
@@ -90,8 +108,8 @@ See `docs/MIGRATION_TODO.md` for detailed checklist.
|
|||||||
## Important Files
|
## Important Files
|
||||||
|
|
||||||
- `common/global/backup.nix` - Kopia backup configuration
|
- `common/global/backup.nix` - Kopia backup configuration
|
||||||
- `hosts/zippy/default.nix` - NFS server config, replication targets
|
- `common/nfs-services-server.nix` - NFS server role (check hosts for which imports this)
|
||||||
- `hosts/c1/default.nix` - NFS standby config, authorized replication keys
|
- `common/nfs-services-standby.nix` - NFS standby role (check hosts for which imports this)
|
||||||
- `flake.nix` - Host definitions, nixpkgs inputs
|
- `flake.nix` - Host definitions, nixpkgs inputs
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ Each layer extends the previous one, inheriting all configurations. Hosts select
|
|||||||
|
|
||||||
### Special Node Types
|
### Special Node Types
|
||||||
|
|
||||||
- **cloud-node**: Minimal + Consul only (cloud VPS deployments)
|
|
||||||
- **compute-node**: Cluster + Nomad worker (container orchestration)
|
- **compute-node**: Cluster + Nomad worker (container orchestration)
|
||||||
|
|
||||||
## Directory Structure
|
## Directory Structure
|
||||||
@@ -40,9 +39,7 @@ Each layer extends the previous one, inheriting all configurations. Hosts select
|
|||||||
│ ├── server-node.nix # Server layer: bare metal services (future)
|
│ ├── server-node.nix # Server layer: bare metal services (future)
|
||||||
│ ├── workstation-node.nix # Workstation layer: dev tools
|
│ ├── workstation-node.nix # Workstation layer: dev tools
|
||||||
│ ├── desktop-node.nix # Desktop layer: GUI environment
|
│ ├── desktop-node.nix # Desktop layer: GUI environment
|
||||||
│ ├── cloud-node.nix # Cloud VPS profile
|
|
||||||
│ ├── compute-node.nix # Nomad worker profile
|
│ ├── compute-node.nix # Nomad worker profile
|
||||||
│ ├── base-node.nix # [DEPRECATED] Alias for cluster-node
|
|
||||||
│ └── [feature modules] # Individual feature configs
|
│ └── [feature modules] # Individual feature configs
|
||||||
├── hosts/
|
├── hosts/
|
||||||
│ ├── c1/ # Compute node 1
|
│ ├── c1/ # Compute node 1
|
||||||
@@ -102,7 +99,7 @@ This ensures system and user configurations stay synchronized.
|
|||||||
| Host | Profile | Role | Hardware |
|
| Host | Profile | Role | Hardware |
|
||||||
|------|---------|------|----------|
|
|------|---------|------|----------|
|
||||||
| **c1, c2, c3** | compute-node | Nomad workers | Bare metal servers |
|
| **c1, c2, c3** | compute-node | Nomad workers | Bare metal servers |
|
||||||
| **alo-cloud-1** | cloud-node | Reverse proxy | Cloud VPS |
|
| **alo-cloud-1** | minimal | Reverse proxy (Traefik) | Cloud VPS |
|
||||||
| **chilly** | server | Home Assistant in a VM | Bare metal server |
|
| **chilly** | server | Home Assistant in a VM | Bare metal server |
|
||||||
| **zippy** | workstation | Development machine, server | Bare metal server |
|
| **zippy** | workstation | Development machine, server | Bare metal server |
|
||||||
| **sparky** | desktop | Desktop environment | Bare metal desktop |
|
| **sparky** | desktop | Desktop environment | Bare metal desktop |
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# DEPRECATED: Use cluster-node.nix for cluster nodes or minimal-node.nix for minimal systems
|
|
||||||
# This file is kept for backward compatibility with existing configurations
|
|
||||||
imports = [
|
|
||||||
./cluster-node.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -19,6 +19,8 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
cache = {
|
cache = {
|
||||||
hostName = config.networking.hostName;
|
hostName = config.networking.hostName;
|
||||||
|
# NOTE: These paths are hardcoded to /persist (not using config.custom.impermanence.persistPath)
|
||||||
|
# This is acceptable since this service is only enabled on btrfs-based hosts
|
||||||
dataPath = "/persist/ncps/data";
|
dataPath = "/persist/ncps/data";
|
||||||
tempPath = "/persist/ncps/tmp";
|
tempPath = "/persist/ncps/tmp";
|
||||||
databaseURL = "sqlite:/persist/ncps/db/db.sqlite";
|
databaseURL = "sqlite:/persist/ncps/db/db.sqlite";
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
let
|
||||||
# this line prevents hanging on network split
|
# this line prevents hanging on network split
|
||||||
automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.mount-timeout=5s";
|
automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.mount-timeout=5s,nobrl";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
environment.systemPackages = [ pkgs.cifs-utils ];
|
environment.systemPackages = [ pkgs.cifs-utils ];
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# Cloud node: Minimal system with Consul for cloud deployments
|
|
||||||
imports = [
|
|
||||||
./minimal-node.nix
|
|
||||||
./consul.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
24
common/cluster-member.nix
Normal file
24
common/cluster-member.nix
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{ pkgs, lib, config, ... }:
|
||||||
|
{
|
||||||
|
# Cluster node configuration
|
||||||
|
# Extends minimal-node with cluster-specific services (Consul, GlusterFS, CIFS, NFS)
|
||||||
|
# Used by: compute nodes (c1, c2, c3)
|
||||||
|
imports = [
|
||||||
|
./minimal-node.nix
|
||||||
|
./unattended-encryption.nix
|
||||||
|
./cifs-client.nix
|
||||||
|
./consul.nix
|
||||||
|
./nfs-services-client.nix # New: NFS client for /data/services
|
||||||
|
];
|
||||||
|
|
||||||
|
options.networking.cluster.primaryInterface = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "eno1";
|
||||||
|
description = "Primary network interface for cluster communication (Consul, NFS, etc.)";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
# Wait for primary interface to be routable before considering network online
|
||||||
|
systemd.network.wait-online.extraArgs = [ "--interface=${config.networking.cluster.primaryInterface}:routable" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# Cluster node configuration
|
|
||||||
# Extends minimal-node with cluster-specific services (Consul, GlusterFS, CIFS, NFS)
|
|
||||||
# Used by: compute nodes (c1, c2, c3)
|
|
||||||
imports = [
|
|
||||||
./minimal-node.nix
|
|
||||||
./unattended-encryption.nix
|
|
||||||
./cifs-client.nix
|
|
||||||
./consul.nix
|
|
||||||
./glusterfs-client.nix # Keep during migration, will be removed in Phase 3
|
|
||||||
./nfs-services-client.nix # New: NFS client for /data/services
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# Compute node: Cluster node with Nomad and GlusterFS server
|
|
||||||
# Used by: c1, c2, c3
|
|
||||||
imports = [
|
|
||||||
./cluster-node.nix
|
|
||||||
./glusterfs.nix
|
|
||||||
./nomad.nix
|
|
||||||
];
|
|
||||||
}
|
|
||||||
@@ -1,44 +1,47 @@
|
|||||||
{ pkgs, config, ... }:
|
{ pkgs, config, lib, ... }:
|
||||||
let
|
let
|
||||||
servers = [
|
servers = [
|
||||||
"c1"
|
"c1"
|
||||||
"c2"
|
"c2"
|
||||||
"c3"
|
"c3"
|
||||||
];
|
];
|
||||||
server_enabled = builtins.elem config.networking.hostName servers;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.consul = {
|
options.clusterRole.consulServer = lib.mkEnableOption "Consul server mode";
|
||||||
enable = true;
|
|
||||||
webUi = true;
|
config = {
|
||||||
interface.advertise = "eno1";
|
services.consul = {
|
||||||
extraConfig = {
|
enable = true;
|
||||||
client_addr = "0.0.0.0";
|
webUi = true;
|
||||||
datacenter = "alo";
|
interface.advertise = config.networking.cluster.primaryInterface;
|
||||||
server = server_enabled;
|
extraConfig = {
|
||||||
bootstrap_expect = if server_enabled then (builtins.length servers + 2) / 2 else null;
|
client_addr = "0.0.0.0";
|
||||||
retry_join = builtins.filter (elem: elem != config.networking.hostName) servers;
|
datacenter = "alo";
|
||||||
|
server = config.clusterRole.consulServer;
|
||||||
|
bootstrap_expect = if config.clusterRole.consulServer then (builtins.length servers + 2) / 2 else null;
|
||||||
|
retry_join = builtins.filter (elem: elem != config.networking.hostName) servers;
|
||||||
telemetry = {
|
telemetry = {
|
||||||
prometheus_retention_time = "24h";
|
prometheus_retention_time = "24h";
|
||||||
disable_hostname = true;
|
disable_hostname = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.persistence."/persist".directories = [ "/var/lib/consul" ];
|
environment.persistence.${config.custom.impermanence.persistPath}.directories = [ "/var/lib/consul" ];
|
||||||
|
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
8600
|
8600
|
||||||
8500
|
8500
|
||||||
8301
|
8301
|
||||||
8302
|
8302
|
||||||
8300
|
8300
|
||||||
];
|
];
|
||||||
allowedUDPPorts = [
|
allowedUDPPorts = [
|
||||||
8600
|
8600
|
||||||
8301
|
8301
|
||||||
8302
|
8302
|
||||||
];
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, lib, ... }:
|
||||||
{
|
{
|
||||||
# Desktop profile: Graphical desktop with Hyprland
|
# Desktop profile: Graphical desktop with Hyprland
|
||||||
# Extends workstation-node with desktop environment
|
# Extends workstation-node with desktop environment
|
||||||
@@ -6,6 +6,9 @@
|
|||||||
./workstation-node.nix
|
./workstation-node.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# omarchy-nix enables NetworkManager, but we use useDHCP globally
|
||||||
|
networking.networkmanager.enable = lib.mkForce false;
|
||||||
|
|
||||||
# Enable Hyprland (Wayland compositor)
|
# Enable Hyprland (Wayland compositor)
|
||||||
programs.hyprland = {
|
programs.hyprland = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -27,12 +30,6 @@
|
|||||||
pulse.enable = true;
|
pulse.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# XDG portal for screen sharing, file pickers, etc.
|
|
||||||
xdg.portal = {
|
|
||||||
enable = true;
|
|
||||||
extraPortals = [ pkgs.xdg-desktop-portal-hyprland ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
fonts.packages = with pkgs; [
|
fonts.packages = with pkgs; [
|
||||||
noto-fonts
|
noto-fonts
|
||||||
@@ -43,23 +40,12 @@
|
|||||||
fira-code-symbols
|
fira-code-symbols
|
||||||
];
|
];
|
||||||
|
|
||||||
# Enable greetd with tuigreet for login
|
|
||||||
services.greetd = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
default_session = {
|
|
||||||
command = "${pkgs.greetd.tuigreet}/bin/tuigreet --time --remember --remember-session --sessions ${pkgs.writeText "sessions" ''
|
|
||||||
Hyprland:Hyprland
|
|
||||||
Console:fish
|
|
||||||
''}";
|
|
||||||
user = "greeter";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Environment variables for Wayland
|
# Environment variables for Wayland
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
NIXOS_OZONE_WL = "1"; # Hint electron apps to use Wayland
|
NIXOS_OZONE_WL = "1"; # Hint electron apps to use Wayland
|
||||||
WLR_NO_HARDWARE_CURSORS = "1"; # Fix cursor rendering on some hardware
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
prusa-slicer
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
checkpoint-sync-url = "https://beaconstate.info";
|
checkpoint-sync-url = "https://beaconstate.info";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
environment.persistence."/persist".directories = [
|
environment.persistence.${config.custom.impermanence.persistPath}.directories = [
|
||||||
"/var/lib/private/lighthouse-mainnet"
|
"/var/lib/private/lighthouse-mainnet"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ let
|
|||||||
btrfs = "${btrfsPkg}/bin/btrfs";
|
btrfs = "${btrfsPkg}/bin/btrfs";
|
||||||
snapshotBackup = pkgs.writeScript "kopia-snapshot-backup" (builtins.readFile ./kopia-snapshot-backup.sh);
|
snapshotBackup = pkgs.writeScript "kopia-snapshot-backup" (builtins.readFile ./kopia-snapshot-backup.sh);
|
||||||
backupScript = pkgs.writeShellScript "backup-persist" ''
|
backupScript = pkgs.writeShellScript "backup-persist" ''
|
||||||
target_path="/persist"
|
target_path="${config.custom.impermanence.persistPath}"
|
||||||
snapshot_path="$target_path/kopia-backup-snapshot"
|
|
||||||
KOPIA_CHECK_FOR_UPDATES=false
|
KOPIA_CHECK_FOR_UPDATES=false
|
||||||
|
|
||||||
${kopia} repository connect server \
|
${kopia} repository connect server \
|
||||||
@@ -16,18 +15,29 @@ let
|
|||||||
-p "$(cat ${config.sops.secrets.kopia.path})" \
|
-p "$(cat ${config.sops.secrets.kopia.path})" \
|
||||||
|| exit 1
|
|| exit 1
|
||||||
|
|
||||||
[ -e "$snapshot_path" ] && ${btrfs} subvolume delete "$snapshot_path"
|
# Check if target_path is on btrfs filesystem
|
||||||
|
fs_type=$(stat -f -c %T "$target_path")
|
||||||
|
|
||||||
${btrfs} subvolume snapshot -r "$target_path" "$snapshot_path"
|
if [ "$fs_type" = "btrfs" ]; then
|
||||||
|
# On btrfs: use snapshot for consistency
|
||||||
|
snapshot_path="$target_path/kopia-backup-snapshot"
|
||||||
|
[ -e "$snapshot_path" ] && ${btrfs} subvolume delete "$snapshot_path"
|
||||||
|
${btrfs} subvolume snapshot -r "$target_path" "$snapshot_path"
|
||||||
|
|
||||||
# --no-send-snapshot-path due to https://github.com/kopia/kopia/issues/4402
|
# --no-send-snapshot-path due to https://github.com/kopia/kopia/issues/4402
|
||||||
# Exclude btrfs replication snapshots (they appear as empty dirs in the snapshot anyway)
|
# Exclude btrfs replication snapshots (they appear as empty dirs in the snapshot anyway)
|
||||||
${kopia} snapshot create --no-send-snapshot-report --override-source "$target_path" \
|
${kopia} snapshot create --no-send-snapshot-report --override-source "$target_path" \
|
||||||
--ignore "services@*" \
|
--ignore "services@*" \
|
||||||
--ignore "services-standby/services@*" \
|
--ignore "services-standby/services@*" \
|
||||||
-- "$snapshot_path"
|
-- "$snapshot_path"
|
||||||
|
|
||||||
|
${btrfs} subvolume delete "$snapshot_path"
|
||||||
|
else
|
||||||
|
# On non-btrfs (e.g., ext4): backup directly without snapshot
|
||||||
|
${kopia} snapshot create --no-send-snapshot-report --override-source "$target_path" \
|
||||||
|
-- "$target_path"
|
||||||
|
fi
|
||||||
|
|
||||||
${btrfs} subvolume delete "$snapshot_path"
|
|
||||||
${kopia} repository disconnect
|
${kopia} repository disconnect
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
@@ -41,7 +51,7 @@ in
|
|||||||
services."backup-persist" = {
|
services."backup-persist" = {
|
||||||
description = "Backup persistent data with Kopia";
|
description = "Backup persistent data with Kopia";
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
type = "oneshot";
|
Type = "oneshot";
|
||||||
User = "root";
|
User = "root";
|
||||||
ExecStart = "${backupScript}";
|
ExecStart = "${backupScript}";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
./console.nix
|
./console.nix
|
||||||
./cpufreq.nix
|
./cpufreq.nix
|
||||||
./flakes.nix
|
./flakes.nix
|
||||||
|
./impermanence-options.nix
|
||||||
./kernel.nix
|
./kernel.nix
|
||||||
./locale.nix
|
./locale.nix
|
||||||
./network.nix
|
./network.nix
|
||||||
|
|||||||
14
common/global/impermanence-options.nix
Normal file
14
common/global/impermanence-options.nix
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Define impermanence options that need to be available to all modules
|
||||||
|
# The actual impermanence implementation is in common/impermanence.nix or common/impermanence-tmpfs.nix
|
||||||
|
|
||||||
|
options.custom.impermanence.persistPath = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "/persist";
|
||||||
|
description = "Path where persistent data is stored (e.g., /persist for btrfs, /nix/persist for tmpfs)";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{ lib, config, ... }:
|
||||||
{
|
{
|
||||||
networking = {
|
networking = {
|
||||||
useDHCP = true;
|
useDHCP = true;
|
||||||
@@ -9,7 +10,7 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.persistence."/persist" = {
|
environment.persistence.${config.custom.impermanence.persistPath} = {
|
||||||
directories = [ "/var/db/dhcpcd" ];
|
directories = [ "/var/db/dhcpcd" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
sops = {
|
sops = {
|
||||||
# sometimes the impermanence bind mount is stopped when sops needs these
|
# sometimes the impermanence bind mount is stopped when sops needs these
|
||||||
age.sshKeyPaths = [
|
age.sshKeyPaths = [
|
||||||
"/persist/etc/ssh/ssh_host_ed25519_key"
|
"${config.custom.impermanence.persistPath}/etc/ssh/ssh_host_ed25519_key"
|
||||||
"/persist/etc/ssh/ssh_host_rsa_key"
|
|
||||||
];
|
];
|
||||||
defaultSopsFile = ./../../secrets/common.yaml;
|
defaultSopsFile = ./../../secrets/common.yaml;
|
||||||
secrets = {
|
secrets = {
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ in
|
|||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.tailscaleAutoconnect.enable = true;
|
services.tailscaleAutoconnect.enable = true;
|
||||||
services.tailscale.package = pkgs.unstable.tailscale;
|
services.tailscale.package = pkgs.unstable.tailscale;
|
||||||
environment.persistence."/persist".directories = [ "/var/lib/tailscale" ];
|
environment.persistence.${config.custom.impermanence.persistPath}.directories = [ "/var/lib/tailscale" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
environment.systemPackages = [ pkgs.glusterfs ];
|
|
||||||
|
|
||||||
fileSystems."/data/compute" = {
|
|
||||||
device = "192.168.1.71:/compute";
|
|
||||||
fsType = "glusterfs";
|
|
||||||
options = [
|
|
||||||
"backup-volfile-servers=192.168.1.72:192.168.1.73"
|
|
||||||
"_netdev"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
services.glusterfs = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.persistence."/persist".directories = [ "/var/lib/glusterd" ];
|
|
||||||
|
|
||||||
# TODO: each volume needs its own port starting at 49152
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
24007
|
|
||||||
24008
|
|
||||||
24009
|
|
||||||
49152
|
|
||||||
49153
|
|
||||||
49154
|
|
||||||
49155
|
|
||||||
];
|
|
||||||
}
|
|
||||||
30
common/impermanence-common.nix
Normal file
30
common/impermanence-common.nix
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Common impermanence configuration shared by both btrfs and tmpfs variants
|
||||||
|
# This module should be imported by impermanence.nix or impermanence-tmpfs.nix
|
||||||
|
# The option custom.impermanence.persistPath is defined in common/global/impermanence-options.nix
|
||||||
|
|
||||||
|
environment.persistence.${config.custom.impermanence.persistPath} = {
|
||||||
|
directories = [
|
||||||
|
"/var/lib/nixos"
|
||||||
|
"/home"
|
||||||
|
];
|
||||||
|
files = [
|
||||||
|
"/etc/machine-id"
|
||||||
|
"/etc/ssh/ssh_host_ed25519_key"
|
||||||
|
"/etc/ssh/ssh_host_ed25519_key.pub"
|
||||||
|
"/etc/ssh/ssh_host_rsa_key"
|
||||||
|
"/etc/ssh/ssh_host_rsa_key.pub"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.mutableUsers = false;
|
||||||
|
|
||||||
|
security.sudo.extraConfig = ''
|
||||||
|
Defaults lecture = never
|
||||||
|
'';
|
||||||
|
}
|
||||||
30
common/impermanence-tmpfs.nix
Normal file
30
common/impermanence-tmpfs.nix
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Impermanence configuration for tmpfs root filesystem
|
||||||
|
# Used for systems with tmpfs root (e.g., Raspberry Pi with SD card)
|
||||||
|
# Root is in-memory and wiped on every boot
|
||||||
|
# Persistent data is stored in /nix/persist (directory on the /nix partition)
|
||||||
|
|
||||||
|
# Import common impermanence configuration
|
||||||
|
imports = [ ./impermanence-common.nix ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
# Use /nix/persist for tmpfs-based impermanence
|
||||||
|
custom.impermanence.persistPath = "/nix/persist";
|
||||||
|
|
||||||
|
# tmpfs root filesystem
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "none";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [
|
||||||
|
"defaults"
|
||||||
|
"size=2G"
|
||||||
|
"mode=755"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
inputs,
|
|
||||||
lib,
|
lib,
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
@@ -9,28 +8,22 @@ let
|
|||||||
cfg = config.custom.impermanence;
|
cfg = config.custom.impermanence;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
# Import common impermanence configuration
|
||||||
|
imports = [ ./impermanence-common.nix ];
|
||||||
|
|
||||||
options.custom.impermanence = {
|
options.custom.impermanence = {
|
||||||
enable = lib.mkOption {
|
enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = true;
|
default = true;
|
||||||
description = "Enable impermanent root fs";
|
description = "Enable impermanent root fs with btrfs subvolume rollback";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
environment.persistence = {
|
# Use /persist for btrfs-based impermanence
|
||||||
"/persist" = {
|
custom.impermanence.persistPath = "/persist";
|
||||||
directories = [ "/var/lib/nixos" ];
|
|
||||||
files = [
|
|
||||||
"/etc/machine-id"
|
|
||||||
"/etc/ssh/ssh_host_ed25519_key"
|
|
||||||
"/etc/ssh/ssh_host_ed25519_key.pub"
|
|
||||||
"/etc/ssh/ssh_host_rsa_key"
|
|
||||||
"/etc/ssh/ssh_host_rsa_key.pub"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
# Btrfs-specific filesystem options
|
||||||
fileSystems."/".options = [
|
fileSystems."/".options = [
|
||||||
"compress=zstd"
|
"compress=zstd"
|
||||||
"noatime"
|
"noatime"
|
||||||
@@ -50,17 +43,7 @@ in
|
|||||||
];
|
];
|
||||||
fileSystems."/var/log".neededForBoot = true;
|
fileSystems."/var/log".neededForBoot = true;
|
||||||
|
|
||||||
users.mutableUsers = false;
|
# Btrfs subvolume rollback at each boot
|
||||||
|
|
||||||
# rollback results in sudo lectures after each reboot
|
|
||||||
security.sudo.extraConfig = ''
|
|
||||||
Defaults lecture = never
|
|
||||||
'';
|
|
||||||
|
|
||||||
# needed for allowOther in the home-manager impermanence config
|
|
||||||
programs.fuse.userAllowOther = true;
|
|
||||||
|
|
||||||
# reset / at each boot
|
|
||||||
# Note `lib.mkBefore` is used instead of `lib.mkAfter` here.
|
# Note `lib.mkBefore` is used instead of `lib.mkAfter` here.
|
||||||
boot.initrd.postDeviceCommands = pkgs.lib.mkBefore ''
|
boot.initrd.postDeviceCommands = pkgs.lib.mkBefore ''
|
||||||
mkdir /mnt
|
mkdir /mnt
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
# Note: unattended-encryption is NOT included by default - add it explicitly where needed
|
# Note: unattended-encryption is NOT included by default - add it explicitly where needed
|
||||||
imports = [
|
imports = [
|
||||||
./impermanence.nix
|
./impermanence.nix
|
||||||
|
./resource-limits.nix
|
||||||
./sshd.nix
|
./sshd.nix
|
||||||
./user-ppetru.nix
|
./user-ppetru.nix
|
||||||
./systemd-boot.nix
|
./systemd-boot.nix
|
||||||
|
|||||||
@@ -9,12 +9,17 @@
|
|||||||
# The mount is established at boot time and persists - no auto-unmount.
|
# The mount is established at boot time and persists - no auto-unmount.
|
||||||
# This prevents issues with Docker bind mounts seeing empty automount stubs.
|
# This prevents issues with Docker bind mounts seeing empty automount stubs.
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
./wait-for-dns-ready.nix
|
||||||
|
];
|
||||||
|
|
||||||
fileSystems."/data/services" = {
|
fileSystems."/data/services" = {
|
||||||
device = "data-services.service.consul:/persist/services";
|
device = "data-services.service.consul:/persist/services";
|
||||||
fsType = "nfs";
|
fsType = "nfs";
|
||||||
options = [
|
options = [
|
||||||
"nofail" # Don't block boot if mount fails
|
"nofail" # Don't block boot if mount fails
|
||||||
"x-systemd.mount-timeout=30s" # Timeout for mount attempts
|
"x-systemd.mount-timeout=30s" # Timeout for mount attempts
|
||||||
|
"x-systemd.after=wait-for-dns-ready.service" # Wait for DNS to actually work
|
||||||
"_netdev" # Network filesystem (wait for network)
|
"_netdev" # Network filesystem (wait for network)
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ in
|
|||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
# Persist root SSH directory for replication key
|
# Persist root SSH directory for replication key
|
||||||
environment.persistence."/persist" = {
|
environment.persistence.${config.custom.impermanence.persistPath} = {
|
||||||
directories = [
|
directories = [
|
||||||
"/root/.ssh"
|
"/root/.ssh"
|
||||||
];
|
];
|
||||||
@@ -103,11 +103,14 @@ in
|
|||||||
] ++ (lib.forEach cfg.standbys (standby: {
|
] ++ (lib.forEach cfg.standbys (standby: {
|
||||||
"replicate-services-to-${standby}" = {
|
"replicate-services-to-${standby}" = {
|
||||||
description = "Replicate /persist/services to ${standby}";
|
description = "Replicate /persist/services to ${standby}";
|
||||||
path = [ pkgs.btrfs-progs pkgs.openssh pkgs.coreutils pkgs.findutils pkgs.gnugrep ];
|
path = [ pkgs.btrfs-progs pkgs.openssh pkgs.coreutils pkgs.findutils pkgs.gnugrep pkgs.curl ];
|
||||||
|
|
||||||
script = ''
|
script = ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
START_TIME=$(date +%s)
|
||||||
|
REPLICATION_SUCCESS=0
|
||||||
|
|
||||||
SSH_KEY="/persist/root/.ssh/btrfs-replication"
|
SSH_KEY="/persist/root/.ssh/btrfs-replication"
|
||||||
if [ ! -f "$SSH_KEY" ]; then
|
if [ ! -f "$SSH_KEY" ]; then
|
||||||
echo "ERROR: SSH key not found at $SSH_KEY"
|
echo "ERROR: SSH key not found at $SSH_KEY"
|
||||||
@@ -130,15 +133,19 @@ in
|
|||||||
echo "Attempting incremental send from $(basename $PREV_LOCAL) to ${standby}"
|
echo "Attempting incremental send from $(basename $PREV_LOCAL) to ${standby}"
|
||||||
|
|
||||||
# Try incremental send, if it fails (e.g., parent missing on receiver), fall back to full
|
# Try incremental send, if it fails (e.g., parent missing on receiver), fall back to full
|
||||||
if btrfs send -p "$PREV_LOCAL" "$SNAPSHOT_PATH" | \
|
# Use -c to help with broken Received UUID chains
|
||||||
|
if btrfs send -p "$PREV_LOCAL" -c "$PREV_LOCAL" "$SNAPSHOT_PATH" | \
|
||||||
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new root@${standby} \
|
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new root@${standby} \
|
||||||
"btrfs receive /persist/services-standby"; then
|
"btrfs receive /persist/services-standby"; then
|
||||||
echo "Incremental send completed successfully"
|
echo "Incremental send completed successfully"
|
||||||
|
REPLICATION_SUCCESS=1
|
||||||
else
|
else
|
||||||
echo "Incremental send failed (likely missing parent on receiver), falling back to full send"
|
echo "Incremental send failed (likely missing parent on receiver), falling back to full send"
|
||||||
|
# Plain full send without clone source (receiver may have no snapshots)
|
||||||
btrfs send "$SNAPSHOT_PATH" | \
|
btrfs send "$SNAPSHOT_PATH" | \
|
||||||
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new root@${standby} \
|
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new root@${standby} \
|
||||||
"btrfs receive /persist/services-standby"
|
"btrfs receive /persist/services-standby"
|
||||||
|
REPLICATION_SUCCESS=1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# First snapshot, do full send
|
# First snapshot, do full send
|
||||||
@@ -146,10 +153,28 @@ in
|
|||||||
btrfs send "$SNAPSHOT_PATH" | \
|
btrfs send "$SNAPSHOT_PATH" | \
|
||||||
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new root@${standby} \
|
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=accept-new root@${standby} \
|
||||||
"btrfs receive /persist/services-standby"
|
"btrfs receive /persist/services-standby"
|
||||||
|
REPLICATION_SUCCESS=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Cleanup old snapshots on sender (keep last 24 hours = 288 snapshots at 5min intervals)
|
# Cleanup old snapshots on sender (keep last 10 snapshots, sorted by name/timestamp)
|
||||||
find /persist -maxdepth 1 -name 'services@*' -mmin +1440 -exec btrfs subvolume delete {} \;
|
ls -1d /persist/services@* 2>/dev/null | sort | head -n -10 | xargs -r btrfs subvolume delete
|
||||||
|
|
||||||
|
# Calculate metrics
|
||||||
|
END_TIME=$(date +%s)
|
||||||
|
DURATION=$((END_TIME - START_TIME))
|
||||||
|
SNAPSHOT_COUNT=$(ls -1d /persist/services@* 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
# Push metrics to Prometheus pushgateway
|
||||||
|
cat <<METRICS | curl -s --data-binary @- http://pushgateway.service.consul:9091/metrics/job/nfs_replication/instance/${standby} || true
|
||||||
|
# TYPE nfs_replication_last_success_timestamp gauge
|
||||||
|
nfs_replication_last_success_timestamp $END_TIME
|
||||||
|
# TYPE nfs_replication_duration_seconds gauge
|
||||||
|
nfs_replication_duration_seconds $DURATION
|
||||||
|
# TYPE nfs_replication_snapshot_count gauge
|
||||||
|
nfs_replication_snapshot_count $SNAPSHOT_COUNT
|
||||||
|
# TYPE nfs_replication_success gauge
|
||||||
|
nfs_replication_success $REPLICATION_SUCCESS
|
||||||
|
METRICS
|
||||||
'';
|
'';
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
|||||||
@@ -39,17 +39,28 @@ in
|
|||||||
noCheck = true;
|
noCheck = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Cleanup old snapshots on standby (keep last 48 hours for safety)
|
# Cleanup old snapshots on standby (keep last 10 snapshots)
|
||||||
systemd.services.cleanup-services-standby-snapshots = {
|
systemd.services.cleanup-services-standby-snapshots = {
|
||||||
description = "Cleanup old btrfs snapshots in services-standby";
|
description = "Cleanup old btrfs snapshots in services-standby";
|
||||||
path = [ pkgs.btrfs-progs pkgs.findutils ];
|
path = [ pkgs.btrfs-progs pkgs.findutils pkgs.coreutils pkgs.curl ];
|
||||||
|
|
||||||
script = ''
|
script = ''
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
# Keep last 48 hours of snapshots (576 snapshots at 5min intervals)
|
|
||||||
find /persist/services-standby -maxdepth 1 -name 'services@*' -mmin +2880 -exec btrfs subvolume delete {} \; || true
|
|
||||||
'';
|
|
||||||
|
|
||||||
|
# Cleanup old snapshots on standby (keep last 10 snapshots, sorted by name/timestamp)
|
||||||
|
ls -1d /persist/services-standby/services@* 2>/dev/null | sort | head -n -10 | xargs -r btrfs subvolume delete || true
|
||||||
|
|
||||||
|
# Calculate metrics
|
||||||
|
CLEANUP_TIME=$(date +%s)
|
||||||
|
SNAPSHOT_COUNT=$(ls -1d /persist/services-standby/services@* 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
# Push metrics to Prometheus pushgateway
|
||||||
|
cat <<METRICS | curl -s --data-binary @- http://pushgateway.service.consul:9091/metrics/job/nfs_standby_cleanup/instance/$(hostname) || true
|
||||||
|
# TYPE nfs_standby_snapshot_count gauge
|
||||||
|
nfs_standby_snapshot_count $SNAPSHOT_COUNT
|
||||||
|
# TYPE nfs_standby_cleanup_last_run_timestamp gauge
|
||||||
|
nfs_standby_cleanup_last_run_timestamp $CLEANUP_TIME
|
||||||
|
METRICS
|
||||||
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
User = "root";
|
User = "root";
|
||||||
@@ -60,7 +71,7 @@ in
|
|||||||
description = "Timer for cleaning up old snapshots on standby";
|
description = "Timer for cleaning up old snapshots on standby";
|
||||||
wantedBy = [ "timers.target" ];
|
wantedBy = [ "timers.target" ];
|
||||||
timerConfig = {
|
timerConfig = {
|
||||||
OnCalendar = "daily";
|
OnCalendar = "hourly";
|
||||||
Persistent = true;
|
Persistent = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
9
common/nomad-server.nix
Normal file
9
common/nomad-server.nix
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# Enable server mode for both Consul and Nomad
|
||||||
|
# Used by: c1, c2, c3 (quorum members)
|
||||||
|
clusterRole = {
|
||||||
|
consulServer = true;
|
||||||
|
nomadServer = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
9
common/nomad-worker.nix
Normal file
9
common/nomad-worker.nix
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# Enable Nomad client to run workloads
|
||||||
|
# Includes: Nomad client, Docker plugin, host volumes, NFS mount dependencies
|
||||||
|
# Used by: c1, c2, c3, zippy (all nodes that run Nomad jobs)
|
||||||
|
imports = [
|
||||||
|
./nomad.nix
|
||||||
|
];
|
||||||
|
}
|
||||||
299
common/nomad.nix
299
common/nomad.nix
@@ -1,174 +1,177 @@
|
|||||||
# inspiration: https://github.com/astro/skyflake/blob/main/nixos-modules/nomad.nix
|
# inspiration: https://github.com/astro/skyflake/blob/main/nixos-modules/nomad.nix
|
||||||
{ pkgs, config, ... }:
|
{ pkgs, config, lib, ... }:
|
||||||
let
|
let
|
||||||
servers = [
|
servers = [
|
||||||
"c1"
|
"c1"
|
||||||
"c2"
|
"c2"
|
||||||
"c3"
|
"c3"
|
||||||
];
|
];
|
||||||
server_enabled = builtins.elem config.networking.hostName servers;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
services.nomad = {
|
options.clusterRole.nomadServer = lib.mkEnableOption "Nomad server mode";
|
||||||
enable = true;
|
|
||||||
# true breaks at least CSI volumes
|
|
||||||
# TODO: consider fixing
|
|
||||||
dropPrivileges = false;
|
|
||||||
|
|
||||||
settings = {
|
config = {
|
||||||
datacenter = "alo";
|
services.nomad = {
|
||||||
|
enable = true;
|
||||||
|
# true breaks at least CSI volumes
|
||||||
|
# TODO: consider fixing
|
||||||
|
dropPrivileges = false;
|
||||||
|
|
||||||
client = {
|
settings = {
|
||||||
enabled = true;
|
datacenter = "alo";
|
||||||
server_join.retry_join = servers;
|
|
||||||
host_network.tailscale = {
|
client = {
|
||||||
interface = "tailscale0";
|
enabled = true;
|
||||||
cidr = "100.64.0.0/10";
|
server_join.retry_join = servers;
|
||||||
|
host_network.tailscale = {
|
||||||
|
interface = "tailscale0";
|
||||||
|
cidr = "100.64.0.0/10";
|
||||||
|
};
|
||||||
|
host_volume = {
|
||||||
|
services = {
|
||||||
|
path = "/data/services";
|
||||||
|
read_only = false;
|
||||||
|
};
|
||||||
|
nix-store = {
|
||||||
|
path = "/nix/store";
|
||||||
|
read_only = true;
|
||||||
|
};
|
||||||
|
sw = {
|
||||||
|
path = "/run/current-system/sw";
|
||||||
|
read_only = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
host_volume = {
|
|
||||||
services = {
|
server = {
|
||||||
path = "/data/services";
|
enabled = config.clusterRole.nomadServer;
|
||||||
read_only = false;
|
bootstrap_expect = (builtins.length servers + 2) / 2;
|
||||||
};
|
server_join.retry_join = servers;
|
||||||
nix-store = {
|
};
|
||||||
path = "/nix/store";
|
|
||||||
read_only = true;
|
telemetry = {
|
||||||
};
|
collection_interval = "1s";
|
||||||
sw = {
|
disable_hostname = true;
|
||||||
path = "/run/current-system/sw";
|
prometheus_metrics = true;
|
||||||
read_only = true;
|
publish_allocation_metrics = true;
|
||||||
};
|
publish_node_metrics = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
server = {
|
extraSettingsPaths = [ "/etc/nomad-alo.json" ];
|
||||||
enabled = server_enabled;
|
};
|
||||||
bootstrap_expect = (builtins.length servers + 2) / 2;
|
|
||||||
server_join.retry_join = servers;
|
|
||||||
};
|
|
||||||
|
|
||||||
telemetry = {
|
# NFS mount dependency configuration for Nomad:
|
||||||
collection_interval = "1s";
|
#
|
||||||
disable_hostname = true;
|
# Problem: Docker bind mounts need the real NFS mount, not an empty stub.
|
||||||
prometheus_metrics = true;
|
# If Nomad starts before NFS is mounted, containers get empty directories.
|
||||||
publish_allocation_metrics = true;
|
#
|
||||||
publish_node_metrics = true;
|
# Solution: Use soft dependencies (wants/after) with health-checking recovery.
|
||||||
|
# - wants: Nomad wants the mount, but won't be killed if it goes away
|
||||||
|
# - after: Nomad waits for mount to be attempted before starting
|
||||||
|
# - ExecStartPre with findmnt: Blocks Nomad start until mount is actually active
|
||||||
|
#
|
||||||
|
# This prevents Docker race conditions while allowing:
|
||||||
|
# - Boot to proceed if NFS unavailable (Nomad fails to start, systemd retries)
|
||||||
|
# - Nomad to keep running if NFS temporarily fails (containers may error)
|
||||||
|
# - Recovery service to auto-restart Nomad when NFS comes back or becomes stale
|
||||||
|
#
|
||||||
|
# Note: Mount uses Consul DNS which resolves at mount time. If NFS server
|
||||||
|
# moves to different IP, mount becomes stale and needs remount.
|
||||||
|
# The recovery service handles this by detecting stale mounts and restarting Nomad.
|
||||||
|
systemd.services.nomad = {
|
||||||
|
wants = [ "network-online.target" "data-services.mount" ];
|
||||||
|
after = [ "data-services.mount" ];
|
||||||
|
serviceConfig.ExecStartPre = "${pkgs.util-linux}/bin/findmnt --mountpoint /data/services";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Recovery service: automatically restart Nomad when NFS mount needs attention
|
||||||
|
# This handles scenarios where:
|
||||||
|
# - NFS server was down during boot (mount failed, Nomad hit start-limit)
|
||||||
|
# - NFS server failed over to different host with new IP (mount went stale)
|
||||||
|
# - Network outage temporarily broke the mount
|
||||||
|
#
|
||||||
|
# The timer runs every 30s and checks:
|
||||||
|
# 1. Is mount healthy (exists and accessible)?
|
||||||
|
# 2. If mount is stale/inaccessible → restart Nomad (triggers remount)
|
||||||
|
# 3. If mount is healthy but Nomad failed → restart Nomad (normal recovery)
|
||||||
|
systemd.services.nomad-mount-watcher = {
|
||||||
|
description = "Restart Nomad when NFS mount needs attention";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = pkgs.writeShellScript "nomad-mount-watcher" ''
|
||||||
|
# Check if mount point exists
|
||||||
|
if ! ${pkgs.util-linux}/bin/findmnt --mountpoint /data/services >/dev/null 2>&1; then
|
||||||
|
exit 0 # Mount not present, nothing to do
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if mount is actually accessible (not stale)
|
||||||
|
# Use timeout to avoid hanging on stale NFS mounts
|
||||||
|
if ! ${pkgs.coreutils}/bin/timeout 5s ${pkgs.coreutils}/bin/stat /data/services >/dev/null 2>&1; then
|
||||||
|
echo "NFS mount is stale or inaccessible. Restarting Nomad to trigger remount..."
|
||||||
|
${pkgs.systemd}/bin/systemctl restart nomad.service
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mount is healthy - check if Nomad needs recovery
|
||||||
|
if ${pkgs.systemd}/bin/systemctl is-failed nomad.service >/dev/null 2>&1; then
|
||||||
|
echo "NFS mount is healthy but Nomad is failed. Restarting Nomad..."
|
||||||
|
${pkgs.systemd}/bin/systemctl restart nomad.service
|
||||||
|
fi
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
extraSettingsPaths = [ "/etc/nomad-alo.json" ];
|
systemd.timers.nomad-mount-watcher = {
|
||||||
};
|
description = "Timer for Nomad mount watcher";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
# NFS mount dependency configuration for Nomad:
|
timerConfig = {
|
||||||
#
|
OnBootSec = "1min"; # First run 1min after boot
|
||||||
# Problem: Docker bind mounts need the real NFS mount, not an empty stub.
|
OnUnitActiveSec = "30s"; # Then every 30s
|
||||||
# If Nomad starts before NFS is mounted, containers get empty directories.
|
Unit = "nomad-mount-watcher.service";
|
||||||
#
|
};
|
||||||
# Solution: Use soft dependencies (wants/after) with health-checking recovery.
|
|
||||||
# - wants: Nomad wants the mount, but won't be killed if it goes away
|
|
||||||
# - after: Nomad waits for mount to be attempted before starting
|
|
||||||
# - ExecStartPre with findmnt: Blocks Nomad start until mount is actually active
|
|
||||||
#
|
|
||||||
# This prevents Docker race conditions while allowing:
|
|
||||||
# - Boot to proceed if NFS unavailable (Nomad fails to start, systemd retries)
|
|
||||||
# - Nomad to keep running if NFS temporarily fails (containers may error)
|
|
||||||
# - Recovery service to auto-restart Nomad when NFS comes back or becomes stale
|
|
||||||
#
|
|
||||||
# Note: Mount uses Consul DNS which resolves at mount time. If NFS server
|
|
||||||
# moves to different IP, mount becomes stale and needs remount.
|
|
||||||
# The recovery service handles this by detecting stale mounts and restarting Nomad.
|
|
||||||
systemd.services.nomad = {
|
|
||||||
wants = [ "network-online.target" "data-services.mount" ];
|
|
||||||
after = [ "data-services.mount" ];
|
|
||||||
serviceConfig.ExecStartPre = "${pkgs.util-linux}/bin/findmnt --mountpoint /data/services";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Recovery service: automatically restart Nomad when NFS mount needs attention
|
|
||||||
# This handles scenarios where:
|
|
||||||
# - NFS server was down during boot (mount failed, Nomad hit start-limit)
|
|
||||||
# - NFS server failed over to different host with new IP (mount went stale)
|
|
||||||
# - Network outage temporarily broke the mount
|
|
||||||
#
|
|
||||||
# The timer runs every 30s and checks:
|
|
||||||
# 1. Is mount healthy (exists and accessible)?
|
|
||||||
# 2. If mount is stale/inaccessible → restart Nomad (triggers remount)
|
|
||||||
# 3. If mount is healthy but Nomad failed → restart Nomad (normal recovery)
|
|
||||||
systemd.services.nomad-mount-watcher = {
|
|
||||||
description = "Restart Nomad when NFS mount needs attention";
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
ExecStart = pkgs.writeShellScript "nomad-mount-watcher" ''
|
|
||||||
# Check if mount point exists
|
|
||||||
if ! ${pkgs.util-linux}/bin/findmnt --mountpoint /data/services >/dev/null 2>&1; then
|
|
||||||
exit 0 # Mount not present, nothing to do
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if mount is actually accessible (not stale)
|
|
||||||
# Use timeout to avoid hanging on stale NFS mounts
|
|
||||||
if ! ${pkgs.coreutils}/bin/timeout 5s ${pkgs.coreutils}/bin/stat /data/services >/dev/null 2>&1; then
|
|
||||||
echo "NFS mount is stale or inaccessible. Restarting Nomad to trigger remount..."
|
|
||||||
${pkgs.systemd}/bin/systemctl restart nomad.service
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Mount is healthy - check if Nomad needs recovery
|
|
||||||
if ${pkgs.systemd}/bin/systemctl is-failed nomad.service >/dev/null 2>&1; then
|
|
||||||
echo "NFS mount is healthy but Nomad is failed. Restarting Nomad..."
|
|
||||||
${pkgs.systemd}/bin/systemctl restart nomad.service
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.nomad-mount-watcher = {
|
|
||||||
description = "Timer for Nomad mount watcher";
|
|
||||||
wantedBy = [ "timers.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnBootSec = "1min"; # First run 1min after boot
|
|
||||||
OnUnitActiveSec = "30s"; # Then every 30s
|
|
||||||
Unit = "nomad-mount-watcher.service";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.etc."nomad-alo.json".text = builtins.toJSON {
|
|
||||||
plugin.docker.config = {
|
|
||||||
allow_privileged = true;
|
|
||||||
# for keepalived, though only really needing "NET_ADMIN","NET_BROADCAST","NET_RAW" on top of default
|
|
||||||
# TODO: trim this down
|
|
||||||
allow_caps = [ "all" ];
|
|
||||||
volumes.enabled = true;
|
|
||||||
extra_labels = [
|
|
||||||
"job_name"
|
|
||||||
"task_group_name"
|
|
||||||
"task_name"
|
|
||||||
"node_name"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
plugin.raw_exec.config.enabled = true;
|
environment.etc."nomad-alo.json".text = builtins.toJSON {
|
||||||
};
|
plugin.docker.config = {
|
||||||
|
allow_privileged = true;
|
||||||
|
# for keepalived, though only really needing "NET_ADMIN","NET_BROADCAST","NET_RAW" on top of default
|
||||||
|
# TODO: trim this down
|
||||||
|
allow_caps = [ "all" ];
|
||||||
|
volumes.enabled = true;
|
||||||
|
extra_labels = [
|
||||||
|
"job_name"
|
||||||
|
"task_group_name"
|
||||||
|
"task_name"
|
||||||
|
"node_name"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
environment.persistence."/persist".directories = [
|
plugin.raw_exec.config.enabled = true;
|
||||||
"/var/lib/docker"
|
};
|
||||||
"/var/lib/nomad"
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.persistence.${config.custom.impermanence.persistPath}.directories = [
|
||||||
nomad
|
"/var/lib/docker"
|
||||||
wander
|
"/var/lib/nomad"
|
||||||
damon
|
];
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall = {
|
environment.systemPackages = with pkgs; [
|
||||||
allowedTCPPorts =
|
nomad
|
||||||
if server_enabled then
|
wander
|
||||||
[
|
damon
|
||||||
4646
|
];
|
||||||
4647
|
|
||||||
4648
|
networking.firewall = {
|
||||||
]
|
allowedTCPPorts =
|
||||||
else
|
if config.clusterRole.nomadServer then
|
||||||
[ 4646 ];
|
[
|
||||||
allowedUDPPorts = if server_enabled then [ 4648 ] else [ ];
|
4646
|
||||||
|
4647
|
||||||
|
4648
|
||||||
|
]
|
||||||
|
else
|
||||||
|
[ 4646 ];
|
||||||
|
allowedUDPPorts = if config.clusterRole.nomadServer then [ 4648 ] else [ ];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
44
common/resource-limits.nix
Normal file
44
common/resource-limits.nix
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{ ... }:
|
||||||
|
{
|
||||||
|
# Resource limits for user sessions to prevent system wedging
|
||||||
|
#
|
||||||
|
# Modern systemd/cgroups v2 approach to resource control (replaces ulimits).
|
||||||
|
# Limits apply to all user sessions (SSH, GUI, etc.) but NOT to system services.
|
||||||
|
#
|
||||||
|
# Rationale:
|
||||||
|
# - Prevents runaway user processes (nix builds, compiles, etc.) from consuming
|
||||||
|
# all resources and making the system unresponsive
|
||||||
|
# - System services (Nomad jobs, Consul, NFS, etc.) run outside user.slice and
|
||||||
|
# are unaffected by these limits
|
||||||
|
# - Ensures SSH access remains responsive even under heavy load
|
||||||
|
#
|
||||||
|
# CPU: Uses CPUWeight (not CPUQuota) so user sessions can use 100% when idle,
|
||||||
|
# but system services get priority (1.25x) during contention
|
||||||
|
# Memory: Soft limit at 90% (triggers pressure/reclaim), hard limit at 95%
|
||||||
|
# Gives 5% warning buffer before OOM kills
|
||||||
|
|
||||||
|
systemd.slices.user = {
|
||||||
|
sliceConfig = {
|
||||||
|
# CPU weight: 80 vs default 100 for system services
|
||||||
|
# When idle: user sessions use all available CPU
|
||||||
|
# Under contention: system services get 1.25x CPU share
|
||||||
|
CPUWeight = "80";
|
||||||
|
|
||||||
|
# Memory soft limit: triggers reclaim and memory pressure
|
||||||
|
# User will notice slowdown but processes keep running
|
||||||
|
MemoryHigh = "90%";
|
||||||
|
|
||||||
|
# Memory hard limit: OOM killer targets user.slice
|
||||||
|
# 5% buffer between MemoryHigh and MemoryMax provides warning
|
||||||
|
MemoryMax = "95%";
|
||||||
|
|
||||||
|
# Limit number of tasks (processes/threads)
|
||||||
|
# Prevents fork bombs while still allowing nix builds
|
||||||
|
TasksMax = "4096";
|
||||||
|
|
||||||
|
# Lower I/O priority slightly
|
||||||
|
# System services get preference during I/O contention
|
||||||
|
IOWeight = "90";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{ pkgs, ... }:
|
|
||||||
{
|
|
||||||
# Server profile: Cluster-enabled system for server deployments
|
|
||||||
# Extends cluster-node with server-specific configurations
|
|
||||||
# Future: Add bare NixOS services here (mysql, postgres, etc.) when migrating from Nomad
|
|
||||||
imports = [
|
|
||||||
./cluster-node.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# Server-specific configurations can be added here
|
|
||||||
# Example (for future use):
|
|
||||||
# services.mysql.enable = lib.mkDefault false;
|
|
||||||
# services.postgresql.enable = lib.mkDefault false;
|
|
||||||
}
|
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
allowSFTP = true;
|
allowSFTP = true;
|
||||||
settings = {
|
settings = {
|
||||||
PasswordAuthentication = false;
|
|
||||||
KbdInteractiveAuthentication = false;
|
|
||||||
PermitRootLogin = "prohibit-password"; # Allow root login with SSH keys only
|
PermitRootLogin = "prohibit-password"; # Allow root login with SSH keys only
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
{ pkgs, lib, ... }:
|
||||||
{
|
{
|
||||||
boot.loader.systemd-boot = {
|
boot.loader.systemd-boot = {
|
||||||
enable = true;
|
enable = true;
|
||||||
configurationLimit = 5;
|
configurationLimit = 5;
|
||||||
|
memtest86.enable = lib.mkIf (pkgs.system == "x86_64-linux") true;
|
||||||
};
|
};
|
||||||
boot.loader.efi.canTouchEfiVariables = true;
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
openssh.authorizedKeys.keys = [
|
openssh.authorizedKeys.keys = [
|
||||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCdZ9dHN+DamoyRAIS8v7Ph85KyJ9zYdgwoqkp7F+smEJEdDKboHE5LA49IDQk4cgkR5xNEMtxANpJm+AXNAhQOPVl/w57vI/Z+TBtSvDoj8LuAvKjmmrPfok2iyD2IIlbctcw8ypn1revZwDb1rBFefpbbZdr5h+75tVqqmNebzxk6UQsfL++lU8HscWwYKzxrrom5aJL6wxNTfy7/Htkt4FHzoKAc5gcB2KM/q0s6NvZzX9WtdHHwAR1kib2EekssjDM9VLecX75Xhtbp+LrHOJKRnxbIanXos4UZUzaJctdNTcOYzEVLvV0BCYaktbI+uVvJcC0qo28bXbHdS3rTGRu8CsykFneJXnrrRIJw7mYWhJSTV9bf+6j/lnFNAurbiYmd4SzaTgbGjj2j38Gr/CTsyv8Rho7P3QUWbRRZnn4a7eVPtjGagqwIwS59YDxRcOy2Wdsw35ry/N2G802V7Cr3hUqeaAIev2adtn4FaG72C8enacYUeACPEhi7TYdsDzuuyt31W7AQa5Te4Uda20rTa0Y9N5Lw85uGB2ebbdYWlO2CqI/m+xNYcPkKqL7zZILz782jDw1sxWd/RUbEgJNrWjsKZ7ybiEMmhpw5vLiMGOeqQWIT6cBCNjocmW0ocU+FBLhhioyrvuZOyacoEZLoklatsL0DMkvvkbT0Ew== petru@paler.net"
|
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCdZ9dHN+DamoyRAIS8v7Ph85KyJ9zYdgwoqkp7F+smEJEdDKboHE5LA49IDQk4cgkR5xNEMtxANpJm+AXNAhQOPVl/w57vI/Z+TBtSvDoj8LuAvKjmmrPfok2iyD2IIlbctcw8ypn1revZwDb1rBFefpbbZdr5h+75tVqqmNebzxk6UQsfL++lU8HscWwYKzxrrom5aJL6wxNTfy7/Htkt4FHzoKAc5gcB2KM/q0s6NvZzX9WtdHHwAR1kib2EekssjDM9VLecX75Xhtbp+LrHOJKRnxbIanXos4UZUzaJctdNTcOYzEVLvV0BCYaktbI+uVvJcC0qo28bXbHdS3rTGRu8CsykFneJXnrrRIJw7mYWhJSTV9bf+6j/lnFNAurbiYmd4SzaTgbGjj2j38Gr/CTsyv8Rho7P3QUWbRRZnn4a7eVPtjGagqwIwS59YDxRcOy2Wdsw35ry/N2G802V7Cr3hUqeaAIev2adtn4FaG72C8enacYUeACPEhi7TYdsDzuuyt31W7AQa5Te4Uda20rTa0Y9N5Lw85uGB2ebbdYWlO2CqI/m+xNYcPkKqL7zZILz782jDw1sxWd/RUbEgJNrWjsKZ7ybiEMmhpw5vLiMGOeqQWIT6cBCNjocmW0ocU+FBLhhioyrvuZOyacoEZLoklatsL0DMkvvkbT0Ew== petru@paler.net"
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH+QbeQG/gTPJ2sIMPgZ3ZPEirVo5qX/carbZMKt50YN petru@happy"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH+QbeQG/gTPJ2sIMPgZ3ZPEirVo5qX/carbZMKt50YN petru@happy"
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINIwBGVVoiKh/5/j9Z0ITvResWy+ZuB1afFUkkP/VZ9O ppetru@sparky"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOOQ2EcJ+T+7BItZl89oDYhq7ZW4B9KuQVCy2DuQaPKR ppetru@sparky"
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFRYVOfrqk2nFSyiu7TzU23ql8D6TfXICFpMIEvPbNsc JuiceSSH"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFRYVOfrqk2nFSyiu7TzU23ql8D6TfXICFpMIEvPbNsc JuiceSSH"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINBIqK6+aPIbmviJPWP8PI/k8GmaC7RO8v2ENnsK8sJx ppetru@beefy"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
55
common/wait-for-dns-ready.nix
Normal file
55
common/wait-for-dns-ready.nix
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
# Service to wait for DNS resolution to be actually functional
|
||||||
|
# This is needed because network-online.target and wait-online.service
|
||||||
|
# don't guarantee DNS works - they only check that interfaces are configured.
|
||||||
|
#
|
||||||
|
# Problem: NFS mounts using Consul DNS names (data-services.service.consul)
|
||||||
|
# fail at boot because DNS resolution isn't ready even though network is "online"
|
||||||
|
#
|
||||||
|
# Solution: Actively test DNS resolution before considering network truly ready
|
||||||
|
|
||||||
|
systemd.services.wait-for-dns-ready = {
|
||||||
|
description = "Wait for DNS resolution to be functional";
|
||||||
|
after = [
|
||||||
|
"systemd-networkd-wait-online.service"
|
||||||
|
"systemd-resolved.service"
|
||||||
|
"network-online.target"
|
||||||
|
];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = pkgs.writeShellScript "wait-for-dns-ready" ''
|
||||||
|
# Test DNS resolution by attempting to resolve data-services.service.consul
|
||||||
|
# This ensures the full DNS path works: interface → gateway → Consul DNS
|
||||||
|
|
||||||
|
echo "Waiting for DNS resolution to be ready..."
|
||||||
|
|
||||||
|
for i in {1..30}; do
|
||||||
|
# Use getent which respects /etc/nsswitch.conf and systemd-resolved
|
||||||
|
if ${pkgs.glibc.bin}/bin/getent hosts data-services.service.consul >/dev/null 2>&1; then
|
||||||
|
echo "DNS ready: data-services.service.consul resolved successfully"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Also test a public DNS name to distinguish between general DNS failure
|
||||||
|
# vs Consul-specific issues (helpful for debugging)
|
||||||
|
if ! ${pkgs.glibc.bin}/bin/getent hosts www.google.com >/dev/null 2>&1; then
|
||||||
|
echo "Attempt $i/30: General DNS not working yet, waiting..."
|
||||||
|
else
|
||||||
|
echo "Attempt $i/30: General DNS works but Consul DNS not ready yet, waiting..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Warning: DNS not fully ready after 30 seconds"
|
||||||
|
echo "NFS mounts with 'nofail' option will handle this gracefully"
|
||||||
|
exit 0 # Don't block boot - let nofail mounts handle DNS failures
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
35
common/wifi.nix
Normal file
35
common/wifi.nix
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
sops.secrets.wifi-password-pi = {
|
||||||
|
sopsFile = ./../secrets/wifi.yaml;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.wireless = {
|
||||||
|
enable = true;
|
||||||
|
secretsFile = config.sops.secrets.wifi-password-pi.path;
|
||||||
|
networks = {
|
||||||
|
"pi" = {
|
||||||
|
pskRaw = "ext:pi";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# Only enable on wireless interface, not ethernet
|
||||||
|
interfaces = [ "wlan0" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Prefer wifi over ethernet, but keep ethernet as fallback
|
||||||
|
networking.dhcpcd.extraConfig = ''
|
||||||
|
# Prefer wlan0 over ethernet interfaces
|
||||||
|
interface wlan0
|
||||||
|
metric 100
|
||||||
|
|
||||||
|
interface eth0
|
||||||
|
metric 200
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Persist wireless configuration across reboots (for impermanence)
|
||||||
|
environment.persistence.${config.custom.impermanence.persistPath} = {
|
||||||
|
files = [
|
||||||
|
"/etc/wpa_supplicant.conf"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
{ pkgs, inputs, ... }:
|
{ pkgs, inputs, ... }:
|
||||||
{
|
{
|
||||||
# Workstation profile: Development workstation configuration
|
# Workstation profile: Development workstation configuration
|
||||||
# Extends server-node with development tools and emulation
|
# Adds development tools and emulation on top of minimal-node
|
||||||
imports = [
|
imports = [
|
||||||
./server-node.nix
|
./minimal-node.nix
|
||||||
./unattended-encryption.nix
|
./unattended-encryption.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
55
docs/AUTH_SETUP.md
Normal file
55
docs/AUTH_SETUP.md
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Authentication Setup
|
||||||
|
|
||||||
|
SSO for homelab services using OIDC.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
**Pocket ID** (`pocket-id.v.paler.net`) - Lightweight OIDC provider, data in `/data/services/pocket-id`
|
||||||
|
|
||||||
|
**Traefik** - Uses `traefik-oidc-auth` plugin (v0.16.0) to protect services
|
||||||
|
- Plugin downloaded from GitHub at startup, cached in `/data/services/traefik/plugins-storage`
|
||||||
|
- Middleware config in `/data/services/traefik/rules/middlewares.yml`
|
||||||
|
- Protected services add tag: `traefik.http.routers.<name>.middlewares=oidc-auth@file`
|
||||||
|
|
||||||
|
## Flow
|
||||||
|
|
||||||
|
1. User hits protected service → Traefik intercepts
|
||||||
|
2. Redirects to Pocket ID for login
|
||||||
|
3. Pocket ID returns OIDC token
|
||||||
|
4. Traefik validates and forwards with `X-Oidc-Username` header
|
||||||
|
|
||||||
|
## Protected Services
|
||||||
|
|
||||||
|
Use `oidc-auth@file` middleware (grep codebase for full list):
|
||||||
|
- Wikis (TiddlyWiki instances)
|
||||||
|
- Media stack (Radarr, Sonarr, Plex, etc.)
|
||||||
|
- Infrastructure (Traefik dashboard, Loki, Jupyter, Unifi)
|
||||||
|
|
||||||
|
## Key Files
|
||||||
|
|
||||||
|
- `services/pocket-id.hcl` - OIDC provider
|
||||||
|
- `services/traefik.hcl` - Plugin declaration
|
||||||
|
- `/data/services/traefik/rules/middlewares.yml` - Middleware definitions (oidc-auth, simple-auth fallback)
|
||||||
|
|
||||||
|
## Cold Start Notes
|
||||||
|
|
||||||
|
- Traefik needs internet to download plugin on first start
|
||||||
|
- Pocket ID needs `/data/services` NFS mounted
|
||||||
|
- Pocket ID down = all protected services inaccessible
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Infinite redirects**: Check `TRUST_PROXY=true` on Pocket ID
|
||||||
|
|
||||||
|
**Plugin not loading**: Clear cache in `/data/services/traefik/plugins-storage/`, restart Traefik
|
||||||
|
|
||||||
|
**401 after login**: Verify client ID/secret in middlewares.yml matches Pocket ID client config
|
||||||
|
|
||||||
|
## Migration History
|
||||||
|
|
||||||
|
- Previous: Authentik with forwardAuth (removed Nov 2024)
|
||||||
|
- Current: Pocket ID + traefik-oidc-auth (simpler, lighter)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Manage users/clients via Pocket ID UI. Basic auth fallback available via `simple-auth` middleware.*
|
||||||
288
docs/DIFF_CONFIGS.md
Normal file
288
docs/DIFF_CONFIGS.md
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
# Configuration Diff Tool
|
||||||
|
|
||||||
|
Tool to compare all NixOS host configurations between current working tree and HEAD commit.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Before committing changes (especially refactors), verify that you haven't accidentally broken existing host configurations. This tool:
|
||||||
|
- Builds all host configurations in current state (with uncommitted changes)
|
||||||
|
- Builds all host configurations at HEAD (last commit)
|
||||||
|
- Uses `nvd` to show readable diffs for each host
|
||||||
|
- Highlights which hosts changed and which didn't
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
The script requires `nvd` to be in PATH. Use either:
|
||||||
|
|
||||||
|
**Option 1: direnv (recommended)**
|
||||||
|
```bash
|
||||||
|
# Allow direnv in the repository (one-time setup)
|
||||||
|
direnv allow
|
||||||
|
|
||||||
|
# direnv will automatically load the dev shell when you cd into the directory
|
||||||
|
cd /home/ppetru/projects/alo-cluster
|
||||||
|
# nvd is now in PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: nix develop**
|
||||||
|
```bash
|
||||||
|
# Enter dev shell manually
|
||||||
|
nix develop
|
||||||
|
|
||||||
|
# Now run the script
|
||||||
|
./scripts/diff-configs.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Compare all hosts (summary)
|
||||||
|
./scripts/diff-configs.sh
|
||||||
|
|
||||||
|
# Compare with detailed path listing
|
||||||
|
./scripts/diff-configs.sh -v c1
|
||||||
|
|
||||||
|
# Compare with content diffs of changed files (deep mode)
|
||||||
|
./scripts/diff-configs.sh --deep c1
|
||||||
|
|
||||||
|
# Compare only x86_64 hosts (avoid slow ARM cross-compilation)
|
||||||
|
./scripts/diff-configs.sh c1 c2 c3 zippy chilly sparky
|
||||||
|
|
||||||
|
# Verbose mode with multiple hosts
|
||||||
|
./scripts/diff-configs.sh --verbose c1 c2 c3
|
||||||
|
|
||||||
|
# Via flake app
|
||||||
|
nix run .#diff-configs
|
||||||
|
|
||||||
|
# Show help
|
||||||
|
./scripts/diff-configs.sh --help
|
||||||
|
```
|
||||||
|
|
||||||
|
### Typical Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Make changes to configurations
|
||||||
|
vim common/impermanence.nix
|
||||||
|
|
||||||
|
# 2. Stage changes (required for flake to see them)
|
||||||
|
git add common/impermanence.nix
|
||||||
|
|
||||||
|
# 3. Check what would change if you committed now
|
||||||
|
# For quick feedback, compare only x86_64 hosts first:
|
||||||
|
./scripts/diff-configs.sh c1 c2 c3 zippy chilly sparky
|
||||||
|
|
||||||
|
# 4. Review output, make adjustments if needed
|
||||||
|
|
||||||
|
# 5. If changes look good and affect ARM hosts, check those too:
|
||||||
|
./scripts/diff-configs.sh stinky alo-cloud-1
|
||||||
|
|
||||||
|
# 6. Commit when satisfied
|
||||||
|
git commit -m "Refactor impermanence config"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output Explanation
|
||||||
|
|
||||||
|
### No Changes
|
||||||
|
```
|
||||||
|
━━━ c1 ━━━
|
||||||
|
Building current... done
|
||||||
|
Building HEAD... done
|
||||||
|
✓ No changes
|
||||||
|
```
|
||||||
|
This host's configuration is identical between current and HEAD.
|
||||||
|
|
||||||
|
### Changes Detected
|
||||||
|
```
|
||||||
|
━━━ stinky ━━━
|
||||||
|
Building current... done
|
||||||
|
Building HEAD... done
|
||||||
|
⚠ Configuration changed
|
||||||
|
|
||||||
|
<<< /nix/store/abc-nixos-system-stinky-25.05 (HEAD)
|
||||||
|
>>> /nix/store/xyz-nixos-system-stinky-25.05 (current)
|
||||||
|
|
||||||
|
Version changes:
|
||||||
|
[C] octoprint: 1.9.3 -> 1.10.0
|
||||||
|
[A+] libcamera: ∅ -> 0.1.0
|
||||||
|
Closure size: 1500 -> 1520 (5 paths added, 2 paths removed, +3, +15.2 MB)
|
||||||
|
```
|
||||||
|
|
||||||
|
Legend:
|
||||||
|
- `[C]` - Changed package version
|
||||||
|
- `[A+]` - Added package
|
||||||
|
- `[R-]` - Removed package
|
||||||
|
- `[U.]` - Updated (same version, rebuilt)
|
||||||
|
|
||||||
|
### Verbose Mode (--verbose)
|
||||||
|
|
||||||
|
With `-v` or `--verbose`, also shows the actual store paths that changed:
|
||||||
|
|
||||||
|
```
|
||||||
|
━━━ c1 ━━━
|
||||||
|
Building current... done
|
||||||
|
Building HEAD... done
|
||||||
|
⚠ Configuration changed
|
||||||
|
|
||||||
|
[nvd summary as above]
|
||||||
|
|
||||||
|
Changed store paths:
|
||||||
|
Removed (17 paths):
|
||||||
|
- config.fish
|
||||||
|
- system-units
|
||||||
|
- home-manager-generation
|
||||||
|
- etc-fuse.conf
|
||||||
|
... and 13 more
|
||||||
|
|
||||||
|
Added (17 paths):
|
||||||
|
- config.fish
|
||||||
|
- system-units
|
||||||
|
- home-manager-generation
|
||||||
|
- etc-fuse.conf
|
||||||
|
... and 13 more
|
||||||
|
```
|
||||||
|
|
||||||
|
This is useful when nvd shows "No version changes" but paths still changed (e.g., refactors that rebuild config files).
|
||||||
|
|
||||||
|
### Deep Mode (--deep)
|
||||||
|
|
||||||
|
With `-d` or `--deep`, shows actual content diffs of changed files within store paths (implies verbose):
|
||||||
|
|
||||||
|
```
|
||||||
|
━━━ c1 ━━━
|
||||||
|
Building current... done
|
||||||
|
Building HEAD... done
|
||||||
|
⚠ Configuration changed
|
||||||
|
|
||||||
|
[nvd summary and path listing as above]
|
||||||
|
|
||||||
|
Content diffs of changed files:
|
||||||
|
|
||||||
|
▸ etc-fuse.conf
|
||||||
|
@@ -1,2 +1,2 @@
|
||||||
|
-user_allow_other
|
||||||
|
+#user_allow_other
|
||||||
|
mount_max = 1000
|
||||||
|
|
||||||
|
▸ nixos-system-c1-25.05
|
||||||
|
activate:
|
||||||
|
@@ -108,7 +108,7 @@
|
||||||
|
echo "setting up /etc..."
|
||||||
|
-/nix/store/...-perl/bin/perl /nix/store/...-setup-etc.pl /nix/store/abc-etc/etc
|
||||||
|
+/nix/store/...-perl/bin/perl /nix/store/...-setup-etc.pl /nix/store/xyz-etc/etc
|
||||||
|
|
||||||
|
▸ unit-dbus.service
|
||||||
|
dbus.service:
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
[Service]
|
||||||
|
+Environment="LD_LIBRARY_PATH=/nix/store/.../systemd/lib"
|
||||||
|
Environment="LOCALE_ARCHIVE=..."
|
||||||
|
```
|
||||||
|
|
||||||
|
**What it shows**:
|
||||||
|
- Matches changed paths by basename (e.g., both have "config.fish")
|
||||||
|
- Diffs important files: activate scripts, etc/*, *.conf, *.fish, *.service, *.nix
|
||||||
|
- Shows unified diff format (lines added/removed)
|
||||||
|
- Limits to first 50 lines per file
|
||||||
|
|
||||||
|
**When to use**:
|
||||||
|
- When you need to know **what exactly changed** in config files
|
||||||
|
- Debugging unexpected configuration changes
|
||||||
|
- Reviewing refactors that don't change package versions
|
||||||
|
- Understanding why a host rebuilt despite "No version changes"
|
||||||
|
|
||||||
|
### Build Failures
|
||||||
|
```
|
||||||
|
━━━ broken-host ━━━
|
||||||
|
Building current... FAILED
|
||||||
|
Error: attribute 'foo' missing
|
||||||
|
```
|
||||||
|
If a host fails to build, the error is shown and the script continues with other hosts.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **Discovers hosts**: Queries `deploy.nodes` from flake to get all configured hosts
|
||||||
|
2. **Creates worktree**: Uses `git worktree` to check out HEAD in a temporary directory
|
||||||
|
3. **Builds configurations**: Builds `config.system.build.toplevel` for each host in both locations
|
||||||
|
4. **Compares with nvd**: Runs `nvd diff` to show package-level changes
|
||||||
|
5. **Cleans up**: Removes temporary worktree automatically
|
||||||
|
|
||||||
|
## Important Notes
|
||||||
|
|
||||||
|
### Git Staging Required
|
||||||
|
|
||||||
|
Flakes only evaluate files that are tracked by git. To make changes visible:
|
||||||
|
```bash
|
||||||
|
# Stage new files
|
||||||
|
git add new-file.nix
|
||||||
|
|
||||||
|
# Stage changes to existing files
|
||||||
|
git add modified-file.nix
|
||||||
|
|
||||||
|
# Or stage everything
|
||||||
|
git add .
|
||||||
|
```
|
||||||
|
|
||||||
|
Unstaged changes to tracked files **are** visible (flake uses working tree content).
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
- First run may be slow (building all configurations)
|
||||||
|
- Subsequent runs benefit from Nix evaluation cache
|
||||||
|
- Typical runtime: 1-5 minutes depending on changes
|
||||||
|
- **ARM cross-compilation is slow**: Use host filtering to avoid building ARM hosts when not needed
|
||||||
|
- Example: `./scripts/diff-configs.sh c1 c2 c3` (x86_64 only, fast)
|
||||||
|
- vs `./scripts/diff-configs.sh` (includes stinky/alo-cloud-1, slow)
|
||||||
|
|
||||||
|
### When to Use
|
||||||
|
|
||||||
|
**Good use cases**:
|
||||||
|
- Refactoring shared modules (like impermanence)
|
||||||
|
- Updating common configurations
|
||||||
|
- Before committing significant changes
|
||||||
|
- Verifying deploy target consistency
|
||||||
|
|
||||||
|
**Not needed for**:
|
||||||
|
- Adding a single new host
|
||||||
|
- Trivial one-host changes
|
||||||
|
- Documentation updates
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "Not in a git repository"
|
||||||
|
```bash
|
||||||
|
cd /home/ppetru/projects/alo-cluster
|
||||||
|
./scripts/diff-configs.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### "No changes detected"
|
||||||
|
All changes are already committed. Stage some changes first:
|
||||||
|
```bash
|
||||||
|
git add .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build failures for all hosts
|
||||||
|
Check flake syntax:
|
||||||
|
```bash
|
||||||
|
nix flake check
|
||||||
|
```
|
||||||
|
|
||||||
|
### nvd not found
|
||||||
|
Install nvd:
|
||||||
|
```bash
|
||||||
|
nix profile install nixpkgs#nvd
|
||||||
|
```
|
||||||
|
(Already included in workstation-node.nix packages)
|
||||||
|
|
||||||
|
## Related Tools
|
||||||
|
|
||||||
|
- `nvd` - Package diff tool (used internally)
|
||||||
|
- `nix diff-closures` - Low-level closure diff
|
||||||
|
- `nix store diff-closures` - Alternative diff command
|
||||||
|
- `deploy-rs` - Actual deployment tool
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- `common/global/show-changelog.nix` - Shows changes during system activation
|
||||||
|
- `docs/RASPBERRY_PI_SD_IMAGE.md` - SD image building process
|
||||||
@@ -37,17 +37,17 @@ See [CLUSTER_REVAMP.md](./CLUSTER_REVAMP.md) for detailed procedures.
|
|||||||
## Phase 3: Migrate from GlusterFS to NFS
|
## Phase 3: Migrate from GlusterFS to NFS
|
||||||
- [x] Update all nodes to mount NFS at `/data/services`
|
- [x] Update all nodes to mount NFS at `/data/services`
|
||||||
- [x] Deploy updated configs (NFS client on all nodes)
|
- [x] Deploy updated configs (NFS client on all nodes)
|
||||||
- [ ] Stop all Nomad jobs temporarily
|
- [x] Stop all Nomad jobs temporarily
|
||||||
- [ ] Copy data from GlusterFS to zippy NFS
|
- [x] Copy data from GlusterFS to zippy NFS
|
||||||
- [ ] Copy `/data/compute/appdata/*` → `/persist/services/appdata/`
|
- [x] Copy `/data/compute/appdata/*` → `/persist/services/appdata/`
|
||||||
- [ ] Copy `/data/compute/config/*` → `/persist/services/config/`
|
- [x] Copy `/data/compute/config/*` → `/persist/services/config/`
|
||||||
- [ ] Copy `/data/sync/wordpress` → `/persist/services/appdata/wordpress`
|
- [x] Copy `/data/sync/wordpress` → `/persist/services/appdata/wordpress`
|
||||||
- [ ] Verify data integrity
|
- [x] Verify data integrity
|
||||||
- [ ] Verify NFS mounts working on all nodes
|
- [x] Verify NFS mounts working on all nodes
|
||||||
- [ ] Stop GlusterFS volume
|
- [x] Stop GlusterFS volume
|
||||||
- [ ] Delete GlusterFS volume
|
- [x] Delete GlusterFS volume
|
||||||
- [ ] Remove GlusterFS from NixOS configs
|
- [x] Remove GlusterFS from NixOS configs
|
||||||
- [ ] Remove syncthing wordpress sync configuration
|
- [x] Remove syncthing wordpress sync configuration (no longer used)
|
||||||
|
|
||||||
## Phase 4: Update and redeploy Nomad jobs
|
## Phase 4: Update and redeploy Nomad jobs
|
||||||
|
|
||||||
@@ -125,8 +125,8 @@ See [CLUSTER_REVAMP.md](./CLUSTER_REVAMP.md) for detailed procedures.
|
|||||||
- [ ] Verify backups include `/persist/services` data
|
- [ ] Verify backups include `/persist/services` data
|
||||||
- [ ] Verify backups exclude replication snapshots
|
- [ ] Verify backups exclude replication snapshots
|
||||||
- [ ] Update documentation (README.md, architecture diagrams)
|
- [ ] Update documentation (README.md, architecture diagrams)
|
||||||
- [ ] Clean up old GlusterFS data (only after everything verified!)
|
- [x] Clean up old GlusterFS data (only after everything verified!)
|
||||||
- [ ] Remove old glusterfs directories from all nodes
|
- [x] Remove old glusterfs directories from all nodes
|
||||||
|
|
||||||
## Post-Migration Checklist
|
## Post-Migration Checklist
|
||||||
- [ ] All 5 servers in quorum (consul members)
|
- [ ] All 5 servers in quorum (consul members)
|
||||||
@@ -143,8 +143,8 @@ See [CLUSTER_REVAMP.md](./CLUSTER_REVAMP.md) for detailed procedures.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last updated**: 2025-10-23 22:30
|
**Last updated**: 2025-10-25
|
||||||
**Current phase**: Phase 4 complete! All services migrated to NFS
|
**Current phase**: Phase 3 & 4 complete! GlusterFS removed, all services on NFS
|
||||||
**Note**: Phase 1 (fractal NixOS conversion) deferred until after GlusterFS migration is complete
|
**Note**: Phase 1 (fractal NixOS conversion) deferred until after GlusterFS migration is complete
|
||||||
|
|
||||||
## Migration Summary
|
## Migration Summary
|
||||||
|
|||||||
98
docs/RASPBERRY_PI_SD_IMAGE.md
Normal file
98
docs/RASPBERRY_PI_SD_IMAGE.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
# Raspberry Pi SD Image Building and Deployment
|
||||||
|
|
||||||
|
Guide for building and deploying NixOS SD card images for Raspberry Pi hosts (e.g., stinky).
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Raspberry Pi hosts use a different deployment strategy than regular NixOS hosts:
|
||||||
|
- **First deployment**: Build and flash an SD card image
|
||||||
|
- **Subsequent updates**: Use `deploy-rs` like other hosts
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Storage Layout
|
||||||
|
|
||||||
|
**Partition structure** (automatically created by NixOS):
|
||||||
|
- `/boot/firmware` - FAT32 partition (label: `FIRMWARE`)
|
||||||
|
- Contains Raspberry Pi firmware, U-Boot bootloader, device trees
|
||||||
|
- `/` - tmpfs (in-memory, ephemeral root)
|
||||||
|
- 2GB RAM disk, wiped on every boot
|
||||||
|
- `/nix` - ext4 partition (label: `NIXOS_SD`)
|
||||||
|
- Nix store and persistent data
|
||||||
|
- Contains `/nix/persist` directory for impermanence
|
||||||
|
|
||||||
|
### Impermanence with tmpfs
|
||||||
|
|
||||||
|
Unlike btrfs-based hosts that use `/persist`, Pi hosts use `/nix/persist`:
|
||||||
|
- Root filesystem is tmpfs (no disk writes, auto-wiped)
|
||||||
|
- Single ext4 partition mounted at `/nix`
|
||||||
|
- Persistent data stored in `/nix/persist/` (directory, not separate mount)
|
||||||
|
- Better for SD card longevity (fewer writes)
|
||||||
|
|
||||||
|
**Persisted paths**:
|
||||||
|
- `/nix/persist/var/lib/nixos` - System state
|
||||||
|
- `/nix/persist/home/ppetru` - User home directory
|
||||||
|
- `/nix/persist/etc` - SSH host keys, machine-id
|
||||||
|
- Service-specific: `/nix/persist/var/lib/octoprint`, etc.
|
||||||
|
|
||||||
|
## Building the SD Image
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- ARM64 emulation enabled on build machine:
|
||||||
|
```nix
|
||||||
|
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
|
||||||
|
```
|
||||||
|
(Already configured in `workstation-node.nix`)
|
||||||
|
|
||||||
|
### Build Command
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build SD image for stinky
|
||||||
|
nix build .#packages.aarch64-linux.stinky-sdImage
|
||||||
|
|
||||||
|
# Result location
|
||||||
|
ls -lh result/sd-image/
|
||||||
|
# nixos-sd-image-stinky-25.05-*.img.zst (compressed with zstd)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build location**: Defined in `flake.nix`:
|
||||||
|
```nix
|
||||||
|
packages.aarch64-linux.stinky-sdImage =
|
||||||
|
self.nixosConfigurations.stinky.config.system.build.sdImage;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Flashing the SD Card
|
||||||
|
|
||||||
|
### Find SD Card Device
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Before inserting SD card
|
||||||
|
lsblk
|
||||||
|
|
||||||
|
# Insert SD card, then check again
|
||||||
|
lsblk
|
||||||
|
|
||||||
|
# Look for new device, typically:
|
||||||
|
# - /dev/sdX (USB SD card readers)
|
||||||
|
# - /dev/mmcblk0 (built-in SD card slots)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Warning**: Double-check the device! Wrong device = data loss.
|
||||||
|
|
||||||
|
### Flash Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Decompress and flash in one command
|
||||||
|
zstd -d -c result/sd-image/*.img.zst | sudo dd of=/dev/sdX bs=4M status=progress conv=fsync
|
||||||
|
|
||||||
|
# Or decompress first, then flash
|
||||||
|
unzstd result/sd-image/*.img.zst
|
||||||
|
sudo dd if=result/sd-image/*.img of=/dev/sdX bs=4M status=progress conv=fsync
|
||||||
|
```
|
||||||
|
|
||||||
|
### Eject SD Card
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo eject /dev/sdX
|
||||||
|
```
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
* remote docker images used, can't come up if internet is down
|
* remote docker images used, can't come up if internet is down
|
||||||
* local docker images pulled from gitea, can't come up if gitea isn't up (yet)
|
* local docker images pulled from gitea, can't come up if gitea isn't up (yet)
|
||||||
|
* traefik-oidc-auth plugin downloaded from GitHub at startup (cached in /data/services/traefik/plugins-storage)
|
||||||
* renovate system of some kind
|
* renovate system of some kind
|
||||||
|
* vector (or other log ingestion) everywhere, consider moving it off docker if possible
|
||||||
|
* monitor backup-persist success/fail
|
||||||
|
|
||||||
|
|||||||
656
flake.lock
generated
656
flake.lock
generated
@@ -1,5 +1,58 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"aquamarine": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753216019,
|
||||||
|
"narHash": "sha256-zik7WISrR1ks2l6T1MZqZHb/OqroHdJnSnAehkE0kCk=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "aquamarine",
|
||||||
|
"rev": "be166e11d86ba4186db93e10c54a141058bdce49",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "aquamarine",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"base16-schemes": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696158499,
|
||||||
|
"narHash": "sha256-5yIHgDTPjoX/3oDEfLSQ0eJZdFL1SaCfb9d6M0RmOTM=",
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-schemes",
|
||||||
|
"rev": "a9112eaae86d9dd8ee6bb9445b664fba2f94037a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "tinted-theming",
|
||||||
|
"repo": "base16-schemes",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"browser-previews": {
|
"browser-previews": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
@@ -9,11 +62,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761247699,
|
"lastModified": 1763766218,
|
||||||
"narHash": "sha256-yMQCRsD6F6eyt0ckCbAHH3W59mav7rbn9hwfUWd+rHU=",
|
"narHash": "sha256-CM694zS6IeO/tFvUW7zhlb8t67+6L9QfvCDgQy0nVyQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "browser-previews",
|
"repo": "browser-previews",
|
||||||
"rev": "5fc2e2d88f87b46b72767fd6fc2d4af7d983f2c7",
|
"rev": "04f8550aa62ccda42a6eb839a4ccf6cdcf3d953d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -31,11 +84,11 @@
|
|||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756719547,
|
"lastModified": 1762286984,
|
||||||
"narHash": "sha256-N9gBKUmjwRKPxAafXEk1EGadfk2qDZPBQp4vXWPHINQ=",
|
"narHash": "sha256-9I2H9x5We6Pl+DBYHjR1s3UT8wgwcpAH03kn9CqtdQc=",
|
||||||
"owner": "serokell",
|
"owner": "serokell",
|
||||||
"repo": "deploy-rs",
|
"repo": "deploy-rs",
|
||||||
"rev": "125ae9e3ecf62fb2c0fd4f2d894eb971f1ecaed2",
|
"rev": "9c870f63e28ec1e83305f7f6cb73c941e699f74f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -52,11 +105,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1741473158,
|
"lastModified": 1762521437,
|
||||||
"narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=",
|
"narHash": "sha256-RXN+lcx4DEn3ZS+LqEJSUu/HH+dwGvy0syN7hTo/Chg=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "devshell",
|
"repo": "devshell",
|
||||||
"rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0",
|
"rev": "07bacc9531f5f4df6657c0a02a806443685f384a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -72,11 +125,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760701190,
|
"lastModified": 1764110879,
|
||||||
"narHash": "sha256-y7UhnWlER8r776JsySqsbTUh2Txf7K30smfHlqdaIQw=",
|
"narHash": "sha256-xanUzIb0tf3kJ+PoOFmXEXV1jM3PjkDT/TQ5DYeNYRc=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "disko",
|
"repo": "disko",
|
||||||
"rev": "3a9450b26e69dcb6f8de6e2b07b3fc1c288d85f5",
|
"rev": "aecba248f9a7d68c5d1ed15de2d1c8a4c994a3c5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -88,7 +141,6 @@
|
|||||||
"ethereum-nix": {
|
"ethereum-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"devshell": "devshell",
|
"devshell": "devshell",
|
||||||
"flake-compat": "flake-compat_2",
|
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-utils": "flake-utils_2",
|
||||||
"foundry-nix": "foundry-nix",
|
"foundry-nix": "foundry-nix",
|
||||||
@@ -100,11 +152,11 @@
|
|||||||
"treefmt-nix": "treefmt-nix"
|
"treefmt-nix": "treefmt-nix"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761217923,
|
"lastModified": 1764174664,
|
||||||
"narHash": "sha256-usNQQSwmaHdHiRttmH4no/CVTUyEP+sIoAkkRMgdu0g=",
|
"narHash": "sha256-CYAjcXbI6RzQ3cWKiW/u3ZiJCeVX9PQd2J0+V8zX7c8=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "ethereum.nix",
|
"repo": "ethereum.nix",
|
||||||
"rev": "8c3827adc7e1ea75b43ad3d7c4f9ab9acc3b6273",
|
"rev": "e3a1e2d86a6bc1ef25bdb395d9c770b471d53e7f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -130,16 +182,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat_2": {
|
"flake-compat_2": {
|
||||||
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1746162366,
|
"lastModified": 1747046372,
|
||||||
"narHash": "sha256-5SSSZ/oQkwfcAz/o/6TlejlVGqeK08wyREBQ5qFFPhM=",
|
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
||||||
"owner": "nix-community",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "0f158086a2ecdbb138cd0429410e44994f1b7e4b",
|
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -149,11 +202,11 @@
|
|||||||
"nixpkgs-lib": "nixpkgs-lib"
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760813311,
|
"lastModified": 1762980239,
|
||||||
"narHash": "sha256-lbHQ7FXGzt6/IygWvJ1lCq+Txcut3xYYd6VIpF1ojkg=",
|
"narHash": "sha256-8oNVE8TrD19ulHinjaqONf9QWCKK+w4url56cdStMpM=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "4e627ac2e1b8f1de7f5090064242de9a259dbbc8",
|
"rev": "52a2caecc898d0b46b2b905f058ccc5081f842da",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -170,11 +223,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760948891,
|
"lastModified": 1763759067,
|
||||||
"narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=",
|
"narHash": "sha256-LlLt2Jo/gMNYAwOgdRQBrsRoOz7BPRkzvNaI/fzXi2Q=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04",
|
"rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -255,11 +308,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759569036,
|
"lastModified": 1762247499,
|
||||||
"narHash": "sha256-FuxbXLDArxD1NeRR8zNnsb8Xww5/+qdMwzN1m8Kow/M=",
|
"narHash": "sha256-dPBqjoBcP3yczY7EUQP6BXf58wauRl+lZVZ/fabgq3E=",
|
||||||
"owner": "shazow",
|
"owner": "shazow",
|
||||||
"repo": "foundry.nix",
|
"repo": "foundry.nix",
|
||||||
"rev": "47ba6d3b02bf3faaa857d3572df82ff186d5279a",
|
"rev": "ae6473c7190edea0e505f433293688014b556b29",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -269,6 +322,29 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"gitignore": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"pre-commit-hooks",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1709087332,
|
||||||
|
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "gitignore.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -276,11 +352,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758463745,
|
"lastModified": 1763992789,
|
||||||
"narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=",
|
"narHash": "sha256-WHkdBlw6oyxXIra/vQPYLtqY+3G8dUVZM8bEXk0t8x4=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3",
|
"rev": "44831a7eaba4360fb81f2acc5ea6de5fde90aaa3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -290,6 +366,287 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hyprcursor": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprlang": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753964049,
|
||||||
|
"narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprcursor",
|
||||||
|
"rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprcursor",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprgraphics": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754305013,
|
||||||
|
"narHash": "sha256-u+M2f0Xf1lVHzIPQ7DsNCDkM1NYxykOSsRr4t3TbSM4=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprgraphics",
|
||||||
|
"rev": "4c1d63a0f22135db123fc789f174b89544c6ec2d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprgraphics",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland": {
|
||||||
|
"inputs": {
|
||||||
|
"aquamarine": "aquamarine",
|
||||||
|
"hyprcursor": "hyprcursor",
|
||||||
|
"hyprgraphics": "hyprgraphics",
|
||||||
|
"hyprland-protocols": "hyprland-protocols",
|
||||||
|
"hyprland-qtutils": "hyprland-qtutils",
|
||||||
|
"hyprlang": "hyprlang",
|
||||||
|
"hyprutils": "hyprutils",
|
||||||
|
"hyprwayland-scanner": "hyprwayland-scanner",
|
||||||
|
"nixpkgs": "nixpkgs_2",
|
||||||
|
"pre-commit-hooks": "pre-commit-hooks",
|
||||||
|
"systems": "systems_6",
|
||||||
|
"xdph": "xdph"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1755184403,
|
||||||
|
"narHash": "sha256-VI+ZPD/uIFjzYW8IcyvBgvwyDIvUe4/xh/kOHTbITX8=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "Hyprland",
|
||||||
|
"rev": "60d769a89908c29e19100059985db15a7b6bab6a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "Hyprland",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-protocols": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1749046714,
|
||||||
|
"narHash": "sha256-kymV5FMnddYGI+UjwIw8ceDjdeg7ToDVjbHCvUlhn14=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-protocols",
|
||||||
|
"rev": "613878cb6f459c5e323aaafe1e6f388ac8a36330",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-protocols",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-qt-support": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprlang": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprland-qtutils",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprland-qtutils",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprland-qtutils",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1749154592,
|
||||||
|
"narHash": "sha256-DO7z5CeT/ddSGDEnK9mAXm1qlGL47L3VAHLlLXoCjhE=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-qt-support",
|
||||||
|
"rev": "4c8053c3c888138a30c3a6c45c2e45f5484f2074",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-qt-support",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprland-qtutils": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprland-qt-support": "hyprland-qt-support",
|
||||||
|
"hyprlang": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"hyprutils": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprland-qtutils",
|
||||||
|
"hyprlang",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753819801,
|
||||||
|
"narHash": "sha256-tHe6XeNeVeKapkNM3tcjW4RuD+tB2iwwoogWJOtsqTI=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-qtutils",
|
||||||
|
"rev": "b308a818b9dcaa7ab8ccab891c1b84ebde2152bc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprland-qtutils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprlang": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprutils": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753622892,
|
||||||
|
"narHash": "sha256-0K+A+gmOI8IklSg5It1nyRNv0kCNL51duwnhUO/B8JA=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprlang",
|
||||||
|
"rev": "23f0debd2003f17bd65f851cd3f930cff8a8c809",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprlang",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprutils": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754481650,
|
||||||
|
"narHash": "sha256-6u6HdEFJh5gY6VfyMQbhP7zDdVcqOrCDTkbiHJmAtMI=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprutils",
|
||||||
|
"rev": "df6b8820c4a0835d83d0c7c7be86fbc555f1f7fd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprutils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hyprwayland-scanner": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1751897909,
|
||||||
|
"narHash": "sha256-FnhBENxihITZldThvbO7883PdXC/2dzW4eiNvtoV5Ao=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprwayland-scanner",
|
||||||
|
"rev": "fcca0c61f988a9d092cbb33e906775014c61579d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "hyprwayland-scanner",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"impermanence": {
|
"impermanence": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1737831083,
|
"lastModified": 1737831083,
|
||||||
@@ -333,6 +690,25 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nix-colors": {
|
||||||
|
"inputs": {
|
||||||
|
"base16-schemes": "base16-schemes",
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1707825078,
|
||||||
|
"narHash": "sha256-hTfge2J2W+42SZ7VHXkf4kjU+qzFqPeC9k66jAUBMHk=",
|
||||||
|
"owner": "misterio77",
|
||||||
|
"repo": "nix-colors",
|
||||||
|
"rev": "b01f024090d2c4fc3152cd0cf12027a7b8453ba1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "misterio77",
|
||||||
|
"repo": "nix-colors",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nix-index-database": {
|
"nix-index-database": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -340,11 +716,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760846226,
|
"lastModified": 1763870992,
|
||||||
"narHash": "sha256-xmU8kAsRprJiTGBTaGrwmjBP3AMA9ltlrxHKFuy5JWc=",
|
"narHash": "sha256-NPyc76Wxmv/vAsXJ8F+/8fXECHYcv2YGSqdiSHp/F/A=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nix-index-database",
|
"repo": "nix-index-database",
|
||||||
"rev": "5024e1901239a76b7bf94a4cd27f3507e639d49e",
|
"rev": "d7423982c7a26586aa237d130b14c8b302c7a367",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -353,13 +729,29 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixos-hardware": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1764328224,
|
||||||
|
"narHash": "sha256-hFyF1XQd+XrRx7WZCrGJp544dykexD8Q5SrJJZpEQYg=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixos-hardware",
|
||||||
|
"rev": "d62603a997438e19182af69d3ce7be07565ecad4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nixos-hardware",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761016216,
|
"lastModified": 1763948260,
|
||||||
"narHash": "sha256-G/iC4t/9j/52i/nm+0/4ybBmAF4hzR8CNHC75qEhjHo=",
|
"narHash": "sha256-dY9qLD0H0zOUgU3vWacPY6Qc421BeQAfm8kBuBtPVE0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "481cf557888e05d3128a76f14c76397b7d7cc869",
|
"rev": "1c8ba8d3f7634acac4a2094eef7c32ad9106532c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -371,11 +763,26 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-lib": {
|
"nixpkgs-lib": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754788789,
|
"lastModified": 1761765539,
|
||||||
"narHash": "sha256-x2rJ+Ovzq0sCMpgfgGaaqgBSwY+LST+WbZ6TytnT9Rk=",
|
"narHash": "sha256-b0yj6kfvO8ApcSE+QmA6mUfu8IYG6/uU28OFn4PaC8M=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixpkgs.lib",
|
"repo": "nixpkgs.lib",
|
||||||
"rev": "a73b9c743612e4244d865a2fdee11865283c04e6",
|
"rev": "719359f4562934ae99f5443f20aa06c2ffff91fc",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1697935651,
|
||||||
|
"narHash": "sha256-qOfWjQ2JQSQL15KLh6D7xQhx0qgZlYZTYlcEiRuAMMw=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "e1e11fdbb01113d85c7f41cada9d2847660e3902",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -386,11 +793,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760872779,
|
"lastModified": 1763191728,
|
||||||
"narHash": "sha256-c5C907Raf9eY8f1NUXYeju9aUDlm227s/V0OptEbypA=",
|
"narHash": "sha256-esRhOS0APE6k40Hs/jjReXg+rx+J5LkWw7cuWFKlwYA=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "63bdb5d90fa2fa11c42f9716ad1e23565613b07c",
|
"rev": "1d4c88323ac36805d09657d13a5273aea1b34f0c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -402,11 +809,27 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-unstable_2": {
|
"nixpkgs-unstable_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761114652,
|
"lastModified": 1764242076,
|
||||||
"narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=",
|
"narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c",
|
"rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754725699,
|
||||||
|
"narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -426,11 +849,11 @@
|
|||||||
"systems": "systems_5"
|
"systems": "systems_5"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1761222236,
|
"lastModified": 1764238240,
|
||||||
"narHash": "sha256-Um296vYIWjSjm4btukpjyVPLIz5ovQgoAtEYXFb/Jr4=",
|
"narHash": "sha256-7Znm3koZ4sF+O41Y7rJqf651BPEbjIUYF3r9H23GRGw=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixvim",
|
"repo": "nixvim",
|
||||||
"rev": "39443b9f5737b6f8ee0b654eb47d3a64daac1bd0",
|
"rev": "f1e07ba53abd0fb4872a365cba45562144ad6130",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -449,11 +872,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760652422,
|
"lastModified": 1761730856,
|
||||||
"narHash": "sha256-C88Pgz38QIl9JxQceexqL2G7sw9vodHWx1Uaq+NRJrw=",
|
"narHash": "sha256-t1i5p/vSWwueZSC0Z2BImxx3BjoUDNKyC2mk24krcMY=",
|
||||||
"owner": "NuschtOS",
|
"owner": "NuschtOS",
|
||||||
"repo": "search",
|
"repo": "search",
|
||||||
"rev": "3ebeebe8b6a49dfb11f771f761e0310f7c48d726",
|
"rev": "e29de6db0cb3182e9aee75a3b1fd1919d995d85b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -462,6 +885,55 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"omarchy-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"home-manager": [
|
||||||
|
"home-manager"
|
||||||
|
],
|
||||||
|
"hyprland": "hyprland",
|
||||||
|
"nix-colors": "nix-colors",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1762999930,
|
||||||
|
"narHash": "sha256-uKyxLwiN6sD6EmRSno66y1a8oqISr1XiWxbWHoMJT7I=",
|
||||||
|
"owner": "henrysipp",
|
||||||
|
"repo": "omarchy-nix",
|
||||||
|
"rev": "308e0f85a0deb820c01cfbe1b4faee1daab4da12",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "henrysipp",
|
||||||
|
"repo": "omarchy-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pre-commit-hooks": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat_2",
|
||||||
|
"gitignore": "gitignore",
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1754416808,
|
||||||
|
"narHash": "sha256-c6yg0EQ9xVESx6HGDOCMcyRSjaTpNJP10ef+6fRcofA=",
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"rev": "9c52372878df6911f9afc1e2a1391f55e4dfc864",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "cachix",
|
||||||
|
"repo": "git-hooks.nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"browser-previews": "browser-previews",
|
"browser-previews": "browser-previews",
|
||||||
@@ -471,9 +943,11 @@
|
|||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"impermanence": "impermanence",
|
"impermanence": "impermanence",
|
||||||
"nix-index-database": "nix-index-database",
|
"nix-index-database": "nix-index-database",
|
||||||
|
"nixos-hardware": "nixos-hardware",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"nixpkgs-unstable": "nixpkgs-unstable_2",
|
"nixpkgs-unstable": "nixpkgs-unstable_2",
|
||||||
"nixvim": "nixvim",
|
"nixvim": "nixvim",
|
||||||
|
"omarchy-nix": "omarchy-nix",
|
||||||
"sops-nix": "sops-nix"
|
"sops-nix": "sops-nix"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -484,11 +958,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760998189,
|
"lastModified": 1764021963,
|
||||||
"narHash": "sha256-ee2e1/AeGL5X8oy/HXsZQvZnae6XfEVdstGopKucYLY=",
|
"narHash": "sha256-1m84V2ROwNEbqeS9t37/mkry23GBhfMt8qb6aHHmjuc=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "5a7d18b5c55642df5c432aadb757140edfeb70b3",
|
"rev": "c482a1c1bbe030be6688ed7dc84f7213f304f1ec",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -572,6 +1046,21 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_6": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689347949,
|
||||||
|
"narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-linux",
|
||||||
|
"rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-linux",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -580,11 +1069,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1760889407,
|
"lastModified": 1762938485,
|
||||||
"narHash": "sha256-ppIp04fmz+BaTpJs1nIOmPADg02asfQFrFbhb3SmxsE=",
|
"narHash": "sha256-AlEObg0syDl+Spi4LsZIBrjw+snSVU4T8MOeuZJUJjM=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "3f258dead9fed51f53862366d3a6bc1b622ee7cb",
|
"rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -610,6 +1099,53 @@
|
|||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"xdph": {
|
||||||
|
"inputs": {
|
||||||
|
"hyprland-protocols": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprland-protocols"
|
||||||
|
],
|
||||||
|
"hyprlang": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprlang"
|
||||||
|
],
|
||||||
|
"hyprutils": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprutils"
|
||||||
|
],
|
||||||
|
"hyprwayland-scanner": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"hyprwayland-scanner"
|
||||||
|
],
|
||||||
|
"nixpkgs": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": [
|
||||||
|
"omarchy-nix",
|
||||||
|
"hyprland",
|
||||||
|
"systems"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1753633878,
|
||||||
|
"narHash": "sha256-js2sLRtsOUA/aT10OCDaTjO80yplqwOIaLUqEe0nMx0=",
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
|
"rev": "371b96bd11ad2006ed4f21229dbd1be69bed3e8a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hyprwm",
|
||||||
|
"repo": "xdg-desktop-portal-hyprland",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
132
flake.nix
132
flake.nix
@@ -33,6 +33,12 @@
|
|||||||
url = "github:nix-community/browser-previews";
|
url = "github:nix-community/browser-previews";
|
||||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||||
};
|
};
|
||||||
|
omarchy-nix = {
|
||||||
|
url = "github:henrysipp/omarchy-nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.home-manager.follows = "home-manager";
|
||||||
|
};
|
||||||
|
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
@@ -47,6 +53,8 @@
|
|||||||
impermanence,
|
impermanence,
|
||||||
sops-nix,
|
sops-nix,
|
||||||
browser-previews,
|
browser-previews,
|
||||||
|
omarchy-nix,
|
||||||
|
nixos-hardware,
|
||||||
...
|
...
|
||||||
}@inputs:
|
}@inputs:
|
||||||
let
|
let
|
||||||
@@ -66,13 +74,8 @@
|
|||||||
mkHost =
|
mkHost =
|
||||||
system: profile: modules:
|
system: profile: modules:
|
||||||
let
|
let
|
||||||
# Auto-import profile-specific module based on profile parameter
|
# Profile parameter is only used by home-manager for user environment
|
||||||
profileModule =
|
# NixOS system configuration is handled via explicit imports in host configs
|
||||||
if profile == "server" then ./common/server-node.nix
|
|
||||||
else if profile == "workstation" then ./common/workstation-node.nix
|
|
||||||
else if profile == "desktop" then ./common/desktop-node.nix
|
|
||||||
else if profile == "cloud" then ./common/cloud-node.nix
|
|
||||||
else null;
|
|
||||||
in
|
in
|
||||||
nixpkgs.lib.nixosSystem {
|
nixpkgs.lib.nixosSystem {
|
||||||
system = system;
|
system = system;
|
||||||
@@ -88,24 +91,40 @@
|
|||||||
sops-nix.nixosModules.sops
|
sops-nix.nixosModules.sops
|
||||||
impermanence.nixosModules.impermanence
|
impermanence.nixosModules.impermanence
|
||||||
home-manager.nixosModules.home-manager
|
home-manager.nixosModules.home-manager
|
||||||
{
|
(
|
||||||
home-manager = {
|
{ lib, ... }:
|
||||||
useGlobalPkgs = true;
|
lib.mkMerge [
|
||||||
useUserPackages = true;
|
{
|
||||||
users.ppetru = {
|
home-manager = {
|
||||||
imports = [
|
useGlobalPkgs = true;
|
||||||
(inputs.impermanence + "/home-manager.nix")
|
useUserPackages = true;
|
||||||
inputs.nix-index-database.homeModules.nix-index
|
users.ppetru = {
|
||||||
inputs.nixvim.homeModules.nixvim
|
imports = [
|
||||||
./home
|
inputs.nix-index-database.homeModules.nix-index
|
||||||
];
|
inputs.nixvim.homeModules.nixvim
|
||||||
};
|
./home
|
||||||
extraSpecialArgs = {
|
] ++ lib.optionals (profile == "desktop") [
|
||||||
inherit profile;
|
omarchy-nix.homeManagerModules.default
|
||||||
};
|
];
|
||||||
};
|
};
|
||||||
}
|
extraSpecialArgs = {
|
||||||
] ++ nixpkgs.lib.optional (profileModule != null) profileModule ++ modules;
|
inherit profile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(lib.optionalAttrs (profile == "desktop") {
|
||||||
|
omarchy = {
|
||||||
|
full_name = "Petru Paler";
|
||||||
|
email_address = "petru@paler.net";
|
||||||
|
theme = "tokyo-night";
|
||||||
|
monitors = [ "DP-1,preferred,auto,1.5" ];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]
|
||||||
|
)
|
||||||
|
] ++ nixpkgs.lib.optionals (profile == "desktop") [
|
||||||
|
omarchy-nix.nixosModules.default
|
||||||
|
] ++ modules;
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
inherit inputs self;
|
inherit inputs self;
|
||||||
};
|
};
|
||||||
@@ -136,16 +155,18 @@
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
nixosConfigurations = {
|
nixosConfigurations = {
|
||||||
c1 = mkHost "x86_64-linux" "server" [ ./hosts/c1 ];
|
c1 = mkHost "x86_64-linux" "minimal" [ ./hosts/c1 ];
|
||||||
c2 = mkHost "x86_64-linux" "server" [ ./hosts/c2 ];
|
c2 = mkHost "x86_64-linux" "minimal" [ ./hosts/c2 ];
|
||||||
c3 = mkHost "x86_64-linux" "server" [ ./hosts/c3 ];
|
c3 = mkHost "x86_64-linux" "minimal" [ ./hosts/c3 ];
|
||||||
alo-cloud-1 = mkHost "aarch64-linux" "cloud" [ ./hosts/alo-cloud-1 ];
|
alo-cloud-1 = mkHost "aarch64-linux" "cloud" [ ./hosts/alo-cloud-1 ];
|
||||||
zippy = mkHost "x86_64-linux" "workstation" [
|
zippy = mkHost "x86_64-linux" "minimal" [ ./hosts/zippy ];
|
||||||
ethereum-nix.nixosModules.default
|
|
||||||
./hosts/zippy
|
|
||||||
];
|
|
||||||
chilly = mkHost "x86_64-linux" "workstation" [ ./hosts/chilly ];
|
chilly = mkHost "x86_64-linux" "workstation" [ ./hosts/chilly ];
|
||||||
sparky = mkHost "x86_64-linux" "desktop" [ ./hosts/sparky ];
|
sparky = mkHost "x86_64-linux" "minimal" [ ./hosts/sparky ];
|
||||||
|
beefy = mkHost "x86_64-linux" "desktop" [ ./hosts/beefy ];
|
||||||
|
stinky = mkHost "aarch64-linux" "minimal" [
|
||||||
|
nixos-hardware.nixosModules.raspberry-pi-4
|
||||||
|
./hosts/stinky
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
deploy = {
|
deploy = {
|
||||||
@@ -207,9 +228,54 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
beefy = {
|
||||||
|
hostname = "beefy";
|
||||||
|
profiles = {
|
||||||
|
system = {
|
||||||
|
user = "root";
|
||||||
|
path = (deployPkgsFor "x86_64-linux").deploy-rs.lib.activate.nixos self.nixosConfigurations.beefy;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
stinky = {
|
||||||
|
hostname = "stinky";
|
||||||
|
profiles = {
|
||||||
|
system = {
|
||||||
|
user = "root";
|
||||||
|
path = (deployPkgsFor "aarch64-linux").deploy-rs.lib.activate.nixos self.nixosConfigurations.stinky;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# SD card image for stinky (Raspberry Pi 4)
|
||||||
|
packages.aarch64-linux.stinky-sdImage = self.nixosConfigurations.stinky.config.system.build.sdImage;
|
||||||
|
|
||||||
|
# Apps - utility scripts
|
||||||
|
apps.x86_64-linux.diff-configs = {
|
||||||
|
type = "app";
|
||||||
|
program = "${(pkgsFor "x86_64-linux").writeShellScriptBin "diff-configs" (builtins.readFile ./scripts/diff-configs.sh)}/bin/diff-configs";
|
||||||
|
};
|
||||||
|
|
||||||
|
apps.aarch64-linux.diff-configs = {
|
||||||
|
type = "app";
|
||||||
|
program = "${(pkgsFor "aarch64-linux").writeShellScriptBin "diff-configs" (builtins.readFile ./scripts/diff-configs.sh)}/bin/diff-configs";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Development shells
|
||||||
|
devShells.x86_64-linux.default = (pkgsFor "x86_64-linux").mkShell {
|
||||||
|
packages = with (pkgsFor "x86_64-linux"); [
|
||||||
|
nvd
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.aarch64-linux.default = (pkgsFor "aarch64-linux").mkShell {
|
||||||
|
packages = with (pkgsFor "aarch64-linux"); [
|
||||||
|
nvd
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
|
checks = builtins.mapAttrs (system: deployLib: deployLib.deployChecks self.deploy) deploy-rs.lib;
|
||||||
|
|
||||||
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt-rfc-style;
|
formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt-rfc-style;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
MOSH_SERVER_NETWORK_TMOUT = 604800;
|
MOSH_SERVER_NETWORK_TMOUT = 604800;
|
||||||
NOMAD_ADDR = "http://nomad.service.consul:4646";
|
NOMAD_ADDR = "http://nomad.service.consul:4646";
|
||||||
LESS = "-F -i -M -+S -R -w -X -z-4";
|
LESS = "-F -i -M -+S -R -w -X -z-4";
|
||||||
SYSTEMD_LESS = "FiM+SRwXz-4";
|
SYSTEMD_LESS = "FiM+SRwX";
|
||||||
NIX_LD = "${pkgs.glibc}/lib/ld-linux-x86-64.so.2";
|
NIX_LD = "${pkgs.glibc}/lib/ld-linux-x86-64.so.2";
|
||||||
NIX_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
|
NIX_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
|
||||||
pkgs.stdenv.cc.cc
|
pkgs.stdenv.cc.cc
|
||||||
@@ -27,22 +27,12 @@
|
|||||||
reload-home-manager-config = "home-manager switch --flake ${builtins.toString ./.}";
|
reload-home-manager-config = "home-manager switch --flake ${builtins.toString ./.}";
|
||||||
};
|
};
|
||||||
|
|
||||||
persistence."/persist/home/ppetru" = {
|
file.".ssh/rc".text = ''
|
||||||
directories = [
|
#!/bin/sh
|
||||||
".cache/nix"
|
if test "$SSH_AUTH_SOCK"; then
|
||||||
".cache/nix-index"
|
ln -sf "$SSH_AUTH_SOCK" "$HOME/.ssh/ssh_auth_sock"
|
||||||
".claude/"
|
fi
|
||||||
".codex/"
|
'';
|
||||||
".config/io.datasette.llm/"
|
file.".ssh/rc".executable = true;
|
||||||
".config/sops/"
|
|
||||||
".docker/"
|
|
||||||
".local/share/direnv"
|
|
||||||
".local/share/fish"
|
|
||||||
".ssh"
|
|
||||||
"projects"
|
|
||||||
];
|
|
||||||
files = [ ];
|
|
||||||
allowOther = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,4 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
packages = workstationProfile.packages ++ desktopPkgs;
|
packages = workstationProfile.packages ++ desktopPkgs;
|
||||||
environment.persistence."/persist/home/ppetru".directories = [
|
|
||||||
".cache"
|
|
||||||
".config/google-chrome"
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|||||||
5
home/profiles/minimal.nix
Normal file
5
home/profiles/minimal.nix
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{ pkgs }:
|
||||||
|
{
|
||||||
|
# Minimal profile: reuses server.nix for basic package list
|
||||||
|
packages = (import ./server.nix { inherit pkgs; }).packages;
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ let
|
|||||||
fishPkgs = with pkgs.fishPlugins; [
|
fishPkgs = with pkgs.fishPlugins; [
|
||||||
pure
|
pure
|
||||||
# don't add failed commands to history
|
# don't add failed commands to history
|
||||||
sponge
|
# sponge
|
||||||
transient-fish
|
transient-fish
|
||||||
];
|
];
|
||||||
in
|
in
|
||||||
|
|||||||
@@ -2,83 +2,26 @@
|
|||||||
{
|
{
|
||||||
imports = [ ./workstation.nix ];
|
imports = [ ./workstation.nix ];
|
||||||
|
|
||||||
# Hyprland window manager configuration
|
# Override ghostty to use unstable version (1.2.0+) for ssh-terminfo support
|
||||||
|
programs.ghostty.package = pkgs.unstable.ghostty;
|
||||||
|
|
||||||
wayland.windowManager.hyprland = {
|
wayland.windowManager.hyprland = {
|
||||||
enable = true;
|
enable = true;
|
||||||
settings = {
|
settings = {
|
||||||
monitor = "DP-1,preferred,auto,auto";
|
|
||||||
|
|
||||||
# Remap CapsLock to Super (Mod4)
|
# Remap CapsLock to Super (Mod4)
|
||||||
"$mod" = "SUPER";
|
"$mod" = "SUPER";
|
||||||
|
|
||||||
input = {
|
input = {
|
||||||
kb_options = "caps:super";
|
kb_options = "caps:super";
|
||||||
follow_mouse = 1;
|
|
||||||
sensitivity = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
master = {
|
"$browser" = "google-chrome-stable --new-window --ozone-platform=wayland";
|
||||||
new_status = "master";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Key bindings
|
|
||||||
bind = [
|
|
||||||
# Application launchers
|
|
||||||
"$mod, Q, exec, foot"
|
|
||||||
"$mod, D, exec, wofi --show drun"
|
|
||||||
"$mod SHIFT, D, exec, wofi --show run"
|
|
||||||
"$mod, C, killactive,"
|
|
||||||
"$mod SHIFT, E, exit,"
|
|
||||||
"$mod, V, togglefloating,"
|
|
||||||
"$mod, P, pseudo,"
|
|
||||||
"$mod, J, togglesplit,"
|
|
||||||
|
|
||||||
# Move focus with mod + arrow keys
|
|
||||||
"$mod, left, movefocus, l"
|
|
||||||
"$mod, right, movefocus, r"
|
|
||||||
"$mod, up, movefocus, u"
|
|
||||||
"$mod, down, movefocus, d"
|
|
||||||
|
|
||||||
# Move focus with mod + hjkl (vim-style)
|
|
||||||
"$mod, h, movefocus, l"
|
|
||||||
"$mod, l, movefocus, r"
|
|
||||||
"$mod, k, movefocus, u"
|
|
||||||
"$mod, j, movefocus, d"
|
|
||||||
|
|
||||||
# Switch workspaces with mod + [0-9]
|
|
||||||
"$mod, 1, workspace, 1"
|
|
||||||
"$mod, 2, workspace, 2"
|
|
||||||
"$mod, 3, workspace, 3"
|
|
||||||
"$mod, 4, workspace, 4"
|
|
||||||
"$mod, 5, workspace, 5"
|
|
||||||
"$mod, 6, workspace, 6"
|
|
||||||
"$mod, 7, workspace, 7"
|
|
||||||
"$mod, 8, workspace, 8"
|
|
||||||
"$mod, 9, workspace, 9"
|
|
||||||
"$mod, 0, workspace, 10"
|
|
||||||
|
|
||||||
# Move active window to a workspace with mod + SHIFT + [0-9]
|
|
||||||
"$mod SHIFT, 1, movetoworkspace, 1"
|
|
||||||
"$mod SHIFT, 2, movetoworkspace, 2"
|
|
||||||
"$mod SHIFT, 3, movetoworkspace, 3"
|
|
||||||
"$mod SHIFT, 4, movetoworkspace, 4"
|
|
||||||
"$mod SHIFT, 5, movetoworkspace, 5"
|
|
||||||
"$mod SHIFT, 6, movetoworkspace, 6"
|
|
||||||
"$mod SHIFT, 7, movetoworkspace, 7"
|
|
||||||
"$mod SHIFT, 8, movetoworkspace, 8"
|
|
||||||
"$mod SHIFT, 9, movetoworkspace, 9"
|
|
||||||
"$mod SHIFT, 0, movetoworkspace, 10"
|
|
||||||
|
|
||||||
# Scroll through existing workspaces with mod + scroll
|
|
||||||
"$mod, mouse_down, workspace, e+1"
|
|
||||||
"$mod, mouse_up, workspace, e-1"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Mouse bindings
|
|
||||||
bindm = [
|
|
||||||
"$mod, mouse:272, movewindow"
|
|
||||||
"$mod, mouse:273, resizewindow"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Extend ghostty configuration from omarchy-nix
|
||||||
|
programs.ghostty.settings = {
|
||||||
|
# Automatically handle TERM compatibility for SSH (requires ghostty 1.2.0+)
|
||||||
|
shell-integration-features = "ssh-terminfo";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
5
home/programs/minimal.nix
Normal file
5
home/programs/minimal.nix
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
{
|
||||||
|
# Minimal profile: reuses server.nix for basic CLI programs
|
||||||
|
imports = [ ./server.nix ];
|
||||||
|
}
|
||||||
@@ -327,7 +327,6 @@
|
|||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
shellAbbrs = {
|
shellAbbrs = {
|
||||||
fix-ssh = "eval $(tmux show-env | grep ^SSH_AUTH_SOCK | sed 's/=/ /;s/^/set /')";
|
|
||||||
diff-persist = "sudo rsync -amvxx --dry-run --no-links --exclude '/tmp/*' --exclude '/root/*' / /persist/ | rg -v '^skipping|/$'";
|
diff-persist = "sudo rsync -amvxx --dry-run --no-links --exclude '/tmp/*' --exclude '/root/*' / /persist/ | rg -v '^skipping|/$'";
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -398,6 +397,12 @@
|
|||||||
|
|
||||||
setw -g automatic-rename on
|
setw -g automatic-rename on
|
||||||
set -g set-titles on
|
set -g set-titles on
|
||||||
|
|
||||||
|
# first, unset update-environment[SSH_AUTH_SOCK] (idx 3), to prevent
|
||||||
|
# the client overriding the global value
|
||||||
|
set-option -g -u update-environment[3]
|
||||||
|
# And set the global value to our static symlink'd path:
|
||||||
|
set-environment -g SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
{ pkgs, inputs, ... }:
|
{ pkgs, lib, inputs, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
../../common/global
|
../../common/global
|
||||||
|
../../common/minimal-node.nix
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
./reverse-proxy.nix
|
./reverse-proxy.nix
|
||||||
];
|
];
|
||||||
@@ -11,4 +12,27 @@
|
|||||||
|
|
||||||
networking.hostName = "alo-cloud-1";
|
networking.hostName = "alo-cloud-1";
|
||||||
services.tailscaleAutoconnect.authkey = "tskey-auth-kbdARC7CNTRL-pNQddmWV9q5C2sRV3WGep5ehjJ1qvcfD";
|
services.tailscaleAutoconnect.authkey = "tskey-auth-kbdARC7CNTRL-pNQddmWV9q5C2sRV3WGep5ehjJ1qvcfD";
|
||||||
|
|
||||||
|
services.tailscale = {
|
||||||
|
enable = true;
|
||||||
|
useRoutingFeatures = lib.mkForce "server"; # enables IPv4/IPv6 forwarding + loose rp_filter
|
||||||
|
extraUpFlags = [ "--advertise-exit-node" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.nat = {
|
||||||
|
enable = true;
|
||||||
|
externalInterface = "enp1s0";
|
||||||
|
internalInterfaces = [ "tailscale0" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall = {
|
||||||
|
enable = lib.mkForce true;
|
||||||
|
allowedTCPPorts = [ 80 443 ]; # Public web traffic only
|
||||||
|
allowedUDPPorts = [ 41641 ]; # Tailscale
|
||||||
|
trustedInterfaces = [ "tailscale0" ]; # Full access via VPN
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh = {
|
||||||
|
settings.PasswordAuthentication = false; # Keys only
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, config, ... }:
|
||||||
{
|
{
|
||||||
environment.systemPackages = [ pkgs.traefik ];
|
environment.systemPackages = [ pkgs.traefik ];
|
||||||
environment.persistence."/persist".files = [ "/acme/acme.json" ];
|
environment.persistence.${config.custom.impermanence.persistPath}.files = [ "/acme/acme.json" ];
|
||||||
|
|
||||||
services.traefik = {
|
services.traefik = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
24
hosts/beefy/default.nix
Normal file
24
hosts/beefy/default.nix
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{ pkgs, inputs, ... }:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../common/encrypted-btrfs-layout.nix
|
||||||
|
../../common/global
|
||||||
|
../../common/desktop-node.nix # Hyprland + GUI environment
|
||||||
|
../../common/cluster-member.nix # Consul + storage clients
|
||||||
|
../../common/cluster-tools.nix # Nomad CLI (no service)
|
||||||
|
./hardware.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
diskLayout = {
|
||||||
|
mainDiskDevice = "/dev/disk/by-id/nvme-CT1000P3PSSD8_25164F81F31D";
|
||||||
|
#keyDiskDevice = "/dev/disk/by-id/usb-Intenso_Micro_Line_22080777650797-0:0";
|
||||||
|
keyDiskDevice = "/dev/sda";
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.hostName = "beefy";
|
||||||
|
networking.cluster.primaryInterface = "enp1s0";
|
||||||
|
services.tailscaleAutoconnect.authkey = "tskey-auth-k79UsDTw2v11CNTRL-oYqji35BE9c7CqM89Dzs9cBF14PmqYsi";
|
||||||
|
|
||||||
|
# Enable all SysRq functions for debugging hangs
|
||||||
|
boot.kernel.sysctl."kernel.sysrq" = 1;
|
||||||
|
}
|
||||||
19
hosts/beefy/hardware.nix
Normal file
19
hosts/beefy/hardware.nix
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "usbhid" "usb_storage" "sd_mod" ];
|
||||||
|
boot.initrd.kernelModules = [ ];
|
||||||
|
boot.kernelModules = [ "kvm-amd" ];
|
||||||
|
boot.extraModulePackages = [ ];
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
|
hardware.cpu.amd.updateMicrocode = true; # Uncomment for AMD
|
||||||
|
}
|
||||||
BIN
hosts/beefy/key.bin
Normal file
BIN
hosts/beefy/key.bin
Normal file
Binary file not shown.
@@ -3,7 +3,9 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../common/encrypted-btrfs-layout.nix
|
../../common/encrypted-btrfs-layout.nix
|
||||||
../../common/global
|
../../common/global
|
||||||
../../common/compute-node.nix
|
../../common/cluster-member.nix # Consul + storage clients
|
||||||
|
../../common/nomad-worker.nix # Nomad client (runs jobs)
|
||||||
|
../../common/nomad-server.nix # Consul + Nomad server mode
|
||||||
../../common/nfs-services-standby.nix # NFS standby for /data/services
|
../../common/nfs-services-standby.nix # NFS standby for /data/services
|
||||||
# To promote to NFS server (during failover):
|
# To promote to NFS server (during failover):
|
||||||
# 1. Follow procedure in docs/NFS_FAILOVER.md
|
# 1. Follow procedure in docs/NFS_FAILOVER.md
|
||||||
@@ -21,8 +23,8 @@
|
|||||||
networking.hostName = "c1";
|
networking.hostName = "c1";
|
||||||
services.tailscaleAutoconnect.authkey = "tskey-auth-k2nQ771YHM11CNTRL-YVpoumL2mgR6nLPG51vNhRpEKMDN7gLAi";
|
services.tailscaleAutoconnect.authkey = "tskey-auth-k2nQ771YHM11CNTRL-YVpoumL2mgR6nLPG51vNhRpEKMDN7gLAi";
|
||||||
|
|
||||||
# NFS standby configuration: accept replication from zippy
|
|
||||||
nfsServicesStandby.replicationKeys = [
|
nfsServicesStandby.replicationKeys = [
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHyTKsMCbwCIlMcC/aopgz5Yfx/Q9QdlWC9jzMLgYFAV root@zippy-replication"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHyTKsMCbwCIlMcC/aopgz5Yfx/Q9QdlWC9jzMLgYFAV root@zippy-replication"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO5s73FSUiysHijWRGYCJY8lCtZkX1DGKAqp2671REDq root@sparky-replication"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,16 +3,18 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../common/encrypted-btrfs-layout.nix
|
../../common/encrypted-btrfs-layout.nix
|
||||||
../../common/global
|
../../common/global
|
||||||
../../common/compute-node.nix
|
../../common/cluster-member.nix # Consul + storage clients
|
||||||
|
../../common/nomad-worker.nix # Nomad client (runs jobs)
|
||||||
|
../../common/nomad-server.nix # Consul + Nomad server mode
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
diskLayout = {
|
diskLayout = {
|
||||||
mainDiskDevice = "/dev/disk/by-id/nvme-KINGSTON_SNV3S1000G_50026B7383365CD5";
|
mainDiskDevice = "/dev/disk/by-id/nvme-KINGSTON_SNV3S1000G_50026B73841C1892";
|
||||||
#keyDiskDevice = "/dev/disk/by-id/usb-Intenso_Micro_Line_22080777650675-0:0";
|
#keyDiskDevice = "/dev/disk/by-id/usb-Intenso_Micro_Line_22080777650675-0:0";
|
||||||
keyDiskDevice = "/dev/sda";
|
keyDiskDevice = "/dev/sda";
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.hostName = "c2";
|
networking.hostName = "c2";
|
||||||
services.tailscaleAutoconnect.authkey = "tskey-auth-kBxfZWwkwN11CNTRL-NPkBePmSvdErPVZ5ECuefE12ZWPzpNou";
|
services.tailscaleAutoconnect.authkey = "tskey-auth-kQ11fTmrzd11CNTRL-N4c2L3SAzUbvcAVhqCFWUbAEasJNTknd";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../common/encrypted-btrfs-layout.nix
|
../../common/encrypted-btrfs-layout.nix
|
||||||
../../common/global
|
../../common/global
|
||||||
../../common/compute-node.nix
|
../../common/cluster-member.nix # Consul + storage clients
|
||||||
|
../../common/nomad-worker.nix # Nomad client (runs jobs)
|
||||||
|
../../common/nomad-server.nix # Consul + Nomad server mode
|
||||||
../../common/binary-cache-server.nix
|
../../common/binary-cache-server.nix
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../common/encrypted-btrfs-layout.nix
|
../../common/encrypted-btrfs-layout.nix
|
||||||
../../common/global
|
../../common/global
|
||||||
|
../../common/workstation-node.nix # Dev tools (deploy-rs, docker, nix-ld)
|
||||||
|
../../common/cluster-member.nix # Consul + storage clients
|
||||||
|
../../common/cluster-tools.nix # Nomad CLI (no service)
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -18,8 +21,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
networking.hostName = "chilly";
|
networking.hostName = "chilly";
|
||||||
|
networking.cluster.primaryInterface = "br0";
|
||||||
services.tailscaleAutoconnect.authkey = "tskey-auth-kRXS9oPyPm11CNTRL-BE6YnbP9J6ZZuV9dHkX17ZMnm1JGdu93";
|
services.tailscaleAutoconnect.authkey = "tskey-auth-kRXS9oPyPm11CNTRL-BE6YnbP9J6ZZuV9dHkX17ZMnm1JGdu93";
|
||||||
services.consul.interface.advertise = lib.mkForce "br0";
|
|
||||||
|
|
||||||
networking.useNetworkd = true;
|
networking.useNetworkd = true;
|
||||||
systemd.network.enable = true;
|
systemd.network.enable = true;
|
||||||
|
|||||||
@@ -3,15 +3,24 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../common/encrypted-btrfs-layout.nix
|
../../common/encrypted-btrfs-layout.nix
|
||||||
../../common/global
|
../../common/global
|
||||||
|
../../common/cluster-member.nix
|
||||||
|
../../common/nomad-worker.nix
|
||||||
|
../../common/nfs-services-server.nix
|
||||||
|
# To move NFS server role to another host:
|
||||||
|
# 1. Follow procedure in docs/NFS_FAILOVER.md
|
||||||
|
# 2. Replace above line with: ../../common/nfs-services-standby.nix
|
||||||
|
# 3. Add nfsServicesStandby.replicationKeys with the new server's public key
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
diskLayout = {
|
diskLayout = {
|
||||||
mainDiskDevice = "/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_250GB_S4EUNF0MA33640P";
|
mainDiskDevice = "/dev/disk/by-id/nvme-KIOXIA-EXCERIA_with_Heatsink_SSD_84GF7016FA4S";
|
||||||
#keyDiskDevice = "/dev/disk/by-id/usb-Intenso_Micro_Line_22080777660468-0:0";
|
#keyDiskDevice = "/dev/disk/by-id/usb-Intenso_Micro_Line_22080777660468-0:0";
|
||||||
keyDiskDevice = "/dev/sda";
|
keyDiskDevice = "/dev/sda";
|
||||||
};
|
};
|
||||||
|
|
||||||
networking.hostName = "sparky";
|
networking.hostName = "sparky";
|
||||||
services.tailscaleAutoconnect.authkey = "tskey-auth-kFGr5T4rtT11CNTRL-Ls3wbQz5Nr2AUyzeLaC3s2eChNasyPdR";
|
services.tailscaleAutoconnect.authkey = "tskey-auth-k6VC79UrzN11CNTRL-rvPmd4viyrQ261ifCrfTrQve7c2FesxrG";
|
||||||
|
|
||||||
|
nfsServicesServer.standbys = [ "c1" ];
|
||||||
}
|
}
|
||||||
|
|||||||
61
hosts/stinky/default.nix
Normal file
61
hosts/stinky/default.nix
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../common/global
|
||||||
|
../../common/impermanence-common.nix # Impermanence with custom root config (see hardware.nix)
|
||||||
|
../../common/resource-limits.nix
|
||||||
|
../../common/sshd.nix
|
||||||
|
../../common/user-ppetru.nix
|
||||||
|
../../common/wifi.nix
|
||||||
|
# Note: No systemd-boot.nix - Raspberry Pi uses generic-extlinux-compatible (from sd-image module)
|
||||||
|
./hardware.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
hardware = {
|
||||||
|
raspberry-pi."4".apply-overlays-dtmerge.enable = true;
|
||||||
|
deviceTree = {
|
||||||
|
enable = true;
|
||||||
|
filter = "*rpi-4-*.dtb";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.hostName = "stinky";
|
||||||
|
|
||||||
|
# Configure impermanence for tmpfs root (filesystem config in hardware.nix)
|
||||||
|
custom.impermanence.persistPath = "/nix/persist";
|
||||||
|
|
||||||
|
# Tailscale configuration
|
||||||
|
services.tailscaleAutoconnect.authkey = "tskey-auth-kZC8HX3wSw11CNTRL-7QvqxAphyzM7QeMUTKXv2Ng2RK4XCmg9A";
|
||||||
|
|
||||||
|
# OctoPrint for 3D printer
|
||||||
|
services.octoprint = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Persist OctoPrint data
|
||||||
|
environment.persistence.${config.custom.impermanence.persistPath}.directories = [
|
||||||
|
"/var/lib/octoprint"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Pi HQ Camera support
|
||||||
|
boot.kernelModules = [ "bcm2835-v4l2" ];
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
libcamera
|
||||||
|
libraspberrypi
|
||||||
|
raspberrypi-eeprom
|
||||||
|
];
|
||||||
|
|
||||||
|
# Firewall: Allow access to OctoPrint
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
5000 # OctoPrint
|
||||||
|
];
|
||||||
|
|
||||||
|
# Override global default (stinky is a new system with 25.05)
|
||||||
|
system.stateVersion = lib.mkForce "25.05";
|
||||||
|
}
|
||||||
73
hosts/stinky/hardware.nix
Normal file
73
hosts/stinky/hardware.nix
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/installer/sd-card/sd-image-aarch64.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
# Raspberry Pi 4 platform
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
|
||||||
|
|
||||||
|
# Disable ZFS (not needed, and broken with latest kernel)
|
||||||
|
boot.supportedFilesystems.zfs = lib.mkForce false;
|
||||||
|
|
||||||
|
# Boot configuration - provided by sd-image-aarch64.nix
|
||||||
|
# (grub disabled, generic-extlinux-compatible enabled, U-Boot setup)
|
||||||
|
|
||||||
|
# /boot/firmware is automatically configured by sd-image module
|
||||||
|
# Device: /dev/disk/by-label/FIRMWARE (vfat)
|
||||||
|
|
||||||
|
# tmpfs root with impermanence
|
||||||
|
# Override sd-image module's ext4 root definition with mkForce
|
||||||
|
fileSystems."/" = lib.mkForce {
|
||||||
|
device = "none";
|
||||||
|
fsType = "tmpfs";
|
||||||
|
options = [
|
||||||
|
"defaults"
|
||||||
|
"size=2G"
|
||||||
|
"mode=755"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# The SD partition contains /nix/store and /nix/persist at its root
|
||||||
|
# Mount it at a hidden location, then bind mount its /nix to /nix
|
||||||
|
fileSystems."/mnt/nixos-sd" = {
|
||||||
|
device = "/dev/disk/by-label/NIXOS_SD";
|
||||||
|
fsType = "ext4";
|
||||||
|
options = [ "noatime" ];
|
||||||
|
neededForBoot = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Bind mount /nix from the SD partition
|
||||||
|
fileSystems."/nix" = {
|
||||||
|
device = "/mnt/nixos-sd/nix";
|
||||||
|
fsType = "none";
|
||||||
|
options = [ "bind" ];
|
||||||
|
neededForBoot = true;
|
||||||
|
depends = [ "/mnt/nixos-sd" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# No swap on SD card (wear concern)
|
||||||
|
swapDevices = [ ];
|
||||||
|
|
||||||
|
# SD image build configuration
|
||||||
|
sdImage = {
|
||||||
|
compressImage = true;
|
||||||
|
|
||||||
|
# Populate root with directories
|
||||||
|
populateRootCommands = ''
|
||||||
|
mkdir -p ./files/boot
|
||||||
|
${config.boot.loader.generic-extlinux-compatible.populateCmd} -c ${config.system.build.toplevel} -d ./files/boot
|
||||||
|
|
||||||
|
# Create /nix/persist directory structure for impermanence
|
||||||
|
mkdir -p ./files/nix/persist/var/lib/nixos
|
||||||
|
mkdir -p ./files/nix/persist/home/ppetru
|
||||||
|
mkdir -p ./files/nix/persist/etc
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -3,13 +3,8 @@
|
|||||||
imports = [
|
imports = [
|
||||||
../../common/encrypted-btrfs-layout.nix
|
../../common/encrypted-btrfs-layout.nix
|
||||||
../../common/global
|
../../common/global
|
||||||
../../common/compute-node.nix
|
../../common/cluster-member.nix # Consul + storage clients
|
||||||
# ../../common/ethereum.nix
|
../../common/nomad-worker.nix # Nomad client (runs jobs)
|
||||||
../../common/nfs-services-server.nix # NFS server for /data/services
|
|
||||||
# To move NFS server role to another host:
|
|
||||||
# 1. Follow procedure in docs/NFS_FAILOVER.md
|
|
||||||
# 2. Replace above line with: ../../common/nfs-services-standby.nix
|
|
||||||
# 3. Add nfsServicesStandby.replicationKeys with the new server's public key
|
|
||||||
./hardware.nix
|
./hardware.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -21,7 +16,4 @@
|
|||||||
|
|
||||||
networking.hostName = "zippy";
|
networking.hostName = "zippy";
|
||||||
services.tailscaleAutoconnect.authkey = "tskey-auth-ktKyQ59f2p11CNTRL-ut8E71dLWPXsVtb92hevNX9RTjmk4owBf";
|
services.tailscaleAutoconnect.authkey = "tskey-auth-ktKyQ59f2p11CNTRL-ut8E71dLWPXsVtb92hevNX9RTjmk4owBf";
|
||||||
|
|
||||||
# NFS server configuration: replicate to c1 as standby
|
|
||||||
nfsServicesServer.standbys = [ "c1" ];
|
|
||||||
}
|
}
|
||||||
|
|||||||
374
scripts/diff-configs.sh
Executable file
374
scripts/diff-configs.sh
Executable file
@@ -0,0 +1,374 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Compare NixOS configurations between current state and HEAD
|
||||||
|
# Shows what would change if you committed the current changes
|
||||||
|
#
|
||||||
|
# Requirements: nvd must be in PATH
|
||||||
|
# Run inside `nix develop` or with direnv enabled
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
YELLOW='\033[0;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Normalize nix store paths by replacing 32-char hashes with placeholder
|
||||||
|
normalize_nix_paths() {
|
||||||
|
sed -E 's|/nix/store/[a-z0-9]{32}-|/nix/store/HASH-|g'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Filter diff output to remove hunks where only nix store hashes differ
|
||||||
|
# Returns: filtered diff (empty if only hash changes), exit code 0 if real changes found
|
||||||
|
filter_hash_only_diffs() {
|
||||||
|
local diff_output="$1"
|
||||||
|
local current_hunk=""
|
||||||
|
local output=""
|
||||||
|
local has_real_changes=false
|
||||||
|
|
||||||
|
# Process line by line
|
||||||
|
while IFS= read -r line || [ -n "$line" ]; do
|
||||||
|
if [[ "$line" =~ ^@@ ]]; then
|
||||||
|
# New hunk starts - process previous one if it exists
|
||||||
|
if [ -n "$current_hunk" ]; then
|
||||||
|
if hunk_has_real_changes "$current_hunk"; then
|
||||||
|
output+="$current_hunk"$'\n'
|
||||||
|
has_real_changes=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Start new hunk
|
||||||
|
current_hunk="$line"$'\n'
|
||||||
|
else
|
||||||
|
# Add line to current hunk
|
||||||
|
current_hunk+="$line"$'\n'
|
||||||
|
fi
|
||||||
|
done <<< "$diff_output"
|
||||||
|
|
||||||
|
# Process last hunk
|
||||||
|
if [ -n "$current_hunk" ]; then
|
||||||
|
if hunk_has_real_changes "$current_hunk"; then
|
||||||
|
output+="$current_hunk"
|
||||||
|
has_real_changes=true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove trailing newline
|
||||||
|
output="${output%$'\n'}"
|
||||||
|
|
||||||
|
if [ "$has_real_changes" = true ]; then
|
||||||
|
echo "$output"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if a diff hunk has real changes (not just hash changes)
|
||||||
|
hunk_has_real_changes() {
|
||||||
|
local hunk="$1"
|
||||||
|
|
||||||
|
# Use temp file to avoid bash here-string issues
|
||||||
|
local temp_hunk=$(mktemp)
|
||||||
|
printf '%s' "$hunk" > "$temp_hunk"
|
||||||
|
|
||||||
|
local minus_lines=()
|
||||||
|
local plus_lines=()
|
||||||
|
|
||||||
|
# Extract - and + lines (skip @@ and context lines)
|
||||||
|
while IFS= read -r line || [ -n "$line" ]; do
|
||||||
|
if [[ "$line" =~ ^- && ! "$line" =~ ^--- ]]; then
|
||||||
|
minus_lines+=("${line:1}") # Remove the - prefix
|
||||||
|
elif [[ "$line" =~ ^\+ && ! "$line" =~ ^\+\+\+ ]]; then
|
||||||
|
plus_lines+=("${line:1}") # Remove the + prefix
|
||||||
|
fi
|
||||||
|
done < "$temp_hunk"
|
||||||
|
|
||||||
|
rm -f "$temp_hunk"
|
||||||
|
|
||||||
|
# If counts don't match, there are structural changes
|
||||||
|
if [ ${#minus_lines[@]} -ne ${#plus_lines[@]} ]; then
|
||||||
|
return 0 # Has real changes
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If no changes at all, skip
|
||||||
|
if [ ${#minus_lines[@]} -eq 0 ]; then
|
||||||
|
return 1 # No real changes
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compare each pair of lines after normalization
|
||||||
|
for i in "${!minus_lines[@]}"; do
|
||||||
|
local minus_norm=$(echo "${minus_lines[$i]}" | normalize_nix_paths)
|
||||||
|
local plus_norm=$(echo "${plus_lines[$i]}" | normalize_nix_paths)
|
||||||
|
|
||||||
|
if [ "$minus_norm" != "$plus_norm" ]; then
|
||||||
|
return 0 # Has real changes
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# All changes are hash-only
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for nvd
|
||||||
|
if ! command -v nvd &> /dev/null; then
|
||||||
|
echo "Error: nvd not found in PATH"
|
||||||
|
echo "Run this script inside 'nix develop' or enable direnv"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse flags
|
||||||
|
verbose=false
|
||||||
|
deep=false
|
||||||
|
hosts_args=()
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: $0 [-v|--verbose] [-d|--deep] [HOST...]"
|
||||||
|
echo "Compare NixOS configurations between working tree and HEAD"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " -v, --verbose Show detailed list of added/removed store paths"
|
||||||
|
echo " -d, --deep Show content diffs of changed files (implies -v)"
|
||||||
|
echo ""
|
||||||
|
echo "Arguments:"
|
||||||
|
echo " HOST One or more hostnames to compare (default: all)"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " $0 # Compare all hosts (summary)"
|
||||||
|
echo " $0 -v c1 # Compare c1 with path list"
|
||||||
|
echo " $0 --deep c1 # Compare c1 with content diffs"
|
||||||
|
echo " $0 c1 c2 c3 # Compare only c1, c2, c3"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-v|--verbose)
|
||||||
|
verbose=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-d|--deep)
|
||||||
|
deep=true
|
||||||
|
verbose=true # deep implies verbose
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
hosts_args+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Restore positional parameters
|
||||||
|
set -- "${hosts_args[@]}"
|
||||||
|
|
||||||
|
# Check if we're in a git repo
|
||||||
|
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||||
|
echo "Error: Not in a git repository"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if there are any changes
|
||||||
|
if git diff --quiet && git diff --cached --quiet; then
|
||||||
|
echo "No changes detected between working tree and HEAD"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Comparing configurations: current working tree vs HEAD"
|
||||||
|
echo "======================================================="
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Get list of hosts to compare
|
||||||
|
if [ $# -gt 0 ]; then
|
||||||
|
# Use hosts provided as arguments
|
||||||
|
hosts="$@"
|
||||||
|
echo -e "${YELLOW}Comparing selected hosts: $hosts${NC}"
|
||||||
|
else
|
||||||
|
# Get all hosts from flake
|
||||||
|
echo "Discovering all hosts from flake..."
|
||||||
|
hosts=$(nix eval --raw .#deploy.nodes --apply 'nodes: builtins.concatStringsSep "\n" (builtins.attrNames nodes)' 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -z "$hosts" ]; then
|
||||||
|
echo "Error: No hosts found in flake"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Create temp worktree at HEAD
|
||||||
|
worktree=$(mktemp -d)
|
||||||
|
trap "git worktree remove --force '$worktree' &>/dev/null || true; rm -rf '$worktree'" EXIT
|
||||||
|
|
||||||
|
echo "Creating temporary worktree at HEAD..."
|
||||||
|
git worktree add --quiet --detach "$worktree" HEAD
|
||||||
|
|
||||||
|
echo "Building and comparing configurations..."
|
||||||
|
echo
|
||||||
|
|
||||||
|
any_changes=false
|
||||||
|
|
||||||
|
for host in $hosts; do
|
||||||
|
echo -e "${BLUE}━━━ $host ━━━${NC}"
|
||||||
|
|
||||||
|
# Build current (with uncommitted changes)
|
||||||
|
echo -n " Building current... "
|
||||||
|
if ! current=$(nix build --no-link --print-out-paths \
|
||||||
|
".#nixosConfigurations.$host.config.system.build.toplevel" 2>/dev/null); then
|
||||||
|
echo -e "${RED}FAILED${NC}"
|
||||||
|
# Re-run to show error
|
||||||
|
nix build --no-link ".#nixosConfigurations.$host.config.system.build.toplevel" 2>&1 | head -20 | sed 's/^/ /'
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "done"
|
||||||
|
|
||||||
|
# Build HEAD
|
||||||
|
echo -n " Building HEAD... "
|
||||||
|
if ! head=$(nix build --no-link --print-out-paths \
|
||||||
|
"$worktree#nixosConfigurations.$host.config.system.build.toplevel" 2>/dev/null); then
|
||||||
|
echo -e "${RED}FAILED${NC}"
|
||||||
|
# Re-run to show error
|
||||||
|
nix build --no-link "$worktree#nixosConfigurations.$host.config.system.build.toplevel" 2>&1 | head -20 | sed 's/^/ /'
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
echo "done"
|
||||||
|
|
||||||
|
# Compare
|
||||||
|
if [ "$head" = "$current" ]; then
|
||||||
|
echo -e " ${GREEN}✓ No changes${NC}"
|
||||||
|
else
|
||||||
|
any_changes=true
|
||||||
|
echo -e " ${RED}⚠ Configuration changed${NC}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Show nvd summary
|
||||||
|
if ! nvd diff "$head" "$current" 2>&1; then
|
||||||
|
echo -e " ${RED}(nvd diff failed - see error above)${NC}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show detailed closure diff if verbose
|
||||||
|
if [ "$verbose" = true ]; then
|
||||||
|
echo
|
||||||
|
echo -e " ${YELLOW}Changed store paths:${NC}"
|
||||||
|
|
||||||
|
# Get paths unique to HEAD and current
|
||||||
|
head_only=$(comm -23 <(nix-store -q --requisites "$head" 2>/dev/null | sort) \
|
||||||
|
<(nix-store -q --requisites "$current" 2>/dev/null | sort))
|
||||||
|
current_only=$(comm -13 <(nix-store -q --requisites "$head" 2>/dev/null | sort) \
|
||||||
|
<(nix-store -q --requisites "$current" 2>/dev/null | sort))
|
||||||
|
|
||||||
|
# Count changes
|
||||||
|
removed_count=$(echo "$head_only" | wc -l)
|
||||||
|
added_count=$(echo "$current_only" | wc -l)
|
||||||
|
|
||||||
|
echo -e " ${RED}Removed ($removed_count paths):${NC}"
|
||||||
|
echo "$head_only" | head -10 | sed 's|^/nix/store/[^-]*-| - |'
|
||||||
|
if [ "$removed_count" -gt 10 ]; then
|
||||||
|
echo " ... and $((removed_count - 10)) more"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e " ${GREEN}Added ($added_count paths):${NC}"
|
||||||
|
echo "$current_only" | head -10 | sed 's|^/nix/store/[^-]*-| - |'
|
||||||
|
if [ "$added_count" -gt 10 ]; then
|
||||||
|
echo " ... and $((added_count - 10)) more"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show content diffs if deep mode
|
||||||
|
if [ "$deep" = true ]; then
|
||||||
|
echo
|
||||||
|
echo -e " ${YELLOW}Content diffs of changed files:${NC}"
|
||||||
|
|
||||||
|
# Extract basenames for matching
|
||||||
|
declare -A head_paths
|
||||||
|
while IFS= read -r path; do
|
||||||
|
[ -z "$path" ] && continue
|
||||||
|
basename="${path#/nix/store/[a-z0-9]*-}"
|
||||||
|
head_paths["$basename"]="$path"
|
||||||
|
done <<< "$head_only"
|
||||||
|
|
||||||
|
# Find matching pairs and diff them
|
||||||
|
matched=false
|
||||||
|
while IFS= read -r path; do
|
||||||
|
[ -z "$path" ] && continue
|
||||||
|
basename="${path#/nix/store/[a-z0-9]*-}"
|
||||||
|
|
||||||
|
# Check if we have a matching path in head
|
||||||
|
if [ -n "${head_paths[$basename]:-}" ]; then
|
||||||
|
old_path="${head_paths[$basename]}"
|
||||||
|
new_path="$path"
|
||||||
|
matched=true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e " ${BLUE}▸ $basename${NC}"
|
||||||
|
|
||||||
|
# If it's a directory, diff all files within it
|
||||||
|
if [ -d "$old_path" ] && [ -d "$new_path" ]; then
|
||||||
|
# Count files to avoid processing huge directories
|
||||||
|
file_count=$(find "$new_path" -maxdepth 3 -type f 2>/dev/null | wc -l)
|
||||||
|
|
||||||
|
# Skip very large directories (e.g., system-path with 900+ files)
|
||||||
|
if [ "$file_count" -gt 100 ]; then
|
||||||
|
echo " (skipping directory with $file_count files - too large)"
|
||||||
|
else
|
||||||
|
# Diff all files in the directory
|
||||||
|
for file in $(find "$new_path" -maxdepth 3 -type f 2>/dev/null); do
|
||||||
|
[ -z "$file" ] && continue
|
||||||
|
relpath="${file#$new_path/}"
|
||||||
|
old_file="$old_path/$relpath"
|
||||||
|
|
||||||
|
if [ -f "$old_file" ] && [ -f "$file" ]; then
|
||||||
|
# Check if file is text
|
||||||
|
if file "$file" | grep -q "text"; then
|
||||||
|
# Get diff output
|
||||||
|
diff_output=$(diff -u "$old_file" "$file" 2>/dev/null | head -50 | tail -n +3 || true)
|
||||||
|
|
||||||
|
# Filter hash-only changes
|
||||||
|
if [ -n "$diff_output" ]; then
|
||||||
|
filtered_diff=$(filter_hash_only_diffs "$diff_output" || true)
|
||||||
|
|
||||||
|
if [ -n "$filtered_diff" ]; then
|
||||||
|
echo -e " ${YELLOW}$relpath:${NC}"
|
||||||
|
echo "$filtered_diff" | sed 's/^/ /'
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
# If it's a file, diff it directly
|
||||||
|
elif [ -f "$old_path" ] && [ -f "$new_path" ]; then
|
||||||
|
if file "$new_path" | grep -q "text"; then
|
||||||
|
# Get diff output
|
||||||
|
diff_output=$(diff -u "$old_path" "$new_path" 2>/dev/null | head -50 | tail -n +3 || true)
|
||||||
|
|
||||||
|
# Filter hash-only changes
|
||||||
|
if [ -n "$diff_output" ]; then
|
||||||
|
filtered_diff=$(filter_hash_only_diffs "$diff_output" || true)
|
||||||
|
|
||||||
|
if [ -n "$filtered_diff" ]; then
|
||||||
|
echo "$filtered_diff" | sed 's/^/ /'
|
||||||
|
else
|
||||||
|
echo " (only hash changes)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " (binary file)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$current_only"
|
||||||
|
|
||||||
|
if [ "$matched" = false ]; then
|
||||||
|
echo " (no matching paths found to compare)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$any_changes" = false ]; then
|
||||||
|
echo -e "${GREEN}✓ All configurations unchanged${NC}"
|
||||||
|
else
|
||||||
|
echo -e "${RED}⚠ Some configurations changed - review carefully before committing${NC}"
|
||||||
|
fi
|
||||||
25
secrets/beefy.yaml
Normal file
25
secrets/beefy.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
kopia: ENC[AES256_GCM,data:/6jqArNgeBoGnEdJ1eshrsG8RJs=,iv:2nNdrKczus70QDdvO/MC2wJubGnAf3M8PtzSe1aoBF4=,tag:aOoktsqhQLXr0YkjYZq4OQ==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBODczb2FsMis0cVIvN2FK
|
||||||
|
UG1QVWt6U1MvaU1Rd0dXWDhmK2RpZ2dSUXlRClZ5ZGRZRk1vUFp0eVVwVzA5R0Ni
|
||||||
|
RUdjVFh5T3o5ZllFaHVFS1pCWjNzVkEKLS0tIGoxNWhhZUhVSms5cEJEa3lZQWlz
|
||||||
|
aXNBMWhUNFBHTDJUZEtDeU85Z1pPU1kKWNm6Wk+Mbc9QIXMXiwleIvP4hlGLvmpI
|
||||||
|
u+udOAinxTxmB9LOXG+y3iPuS9n0B6Y+4WbTjKm9jEqaqNoW8JypJA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1cs8uqj243lspyp042ueu5aes4t3azgyuaxl9au70ggrl2meulq4sgqpc7y
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjTG1MZjM1bVNqeFNqeTgy
|
||||||
|
UXZBWVVacVVsaHJKMkJ1ZWdCbG4zS2tBWDFjCnpSbUw0ZFZMVENNNmYyTWZFdndL
|
||||||
|
RmxUajdsU1l1cmlZa2NQQjJublVsMmMKLS0tIHNpZmRpY2hIbVVZSUdGNHM2WnN6
|
||||||
|
R21jYU96SGVHOUxmZjlldS96K2VqbWcKC28wLdT/zx6yHluCLqB/cFRmc0Alq6AH
|
||||||
|
DqmAaxRhOg/SI5ljCX1gE5BB9rNIJ1Gq8+li7wCpsdfLMr5Yy/HAsw==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2025-11-04T20:25:17Z"
|
||||||
|
mac: ENC[AES256_GCM,data:llS+R5Pj51ZUkU8FkJx2KqqE4D42Uno3Btn31FadIl4kFamnrL6uJjbiNEJpFFO+SchXD3l7VCatbBhMSoxsPYd+rdDRT2klq+iIcZU/k413GC87xdmHIwWE+L2pujv36iBjtM+HJTSvXI0xOxjUmzH4FPdEa1r3Z5yGNnCI+Q4=,iv:ld6pSEzvKTSZtBb+QjHyqqj2VT05YegxBrUR2yxhjKY=,tag:7/vYBh8lDOcVXJL3esTIZQ==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.11.0
|
||||||
@@ -1,30 +1,25 @@
|
|||||||
kopia: ENC[AES256_GCM,data:pZrOFlW5wy8I/leTc1mJEB31Kr0=,iv:COsdcI32ZD66M6h+5L2bBf1N8471LbVEt7TlhYQyMnM=,tag:hJXohn6/zUd5WOSYzXdPwQ==,type:str]
|
kopia: ENC[AES256_GCM,data:pZrOFlW5wy8I/leTc1mJEB31Kr0=,iv:COsdcI32ZD66M6h+5L2bBf1N8471LbVEt7TlhYQyMnM=,tag:hJXohn6/zUd5WOSYzXdPwQ==,type:str]
|
||||||
sops:
|
sops:
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
age:
|
||||||
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAybTNNK3lNZFJremVmUFc1
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpTGZsSS9MWmZFTFdKa0hz
|
||||||
cjZqRjJhSDJ3OGFQOWpITFNZdVdQTi9nWDE4CkZJNjNtdHRBeS85OU8ybXNXVk5l
|
SENqbHVIMzlPVGkvNThOQ0JHNXZFR1ZkdTFVClNoUVdUVkxEV3NCVXZ1eE5uY2pW
|
||||||
SVFBMHlVZVBKdUphWWZaRzhPaUltek0KLS0tIFVWWG43Um54Mm5LS0d2MTZkN3Ay
|
TmVLSWRaaVd4ZzdVYnZvekpWK2dUb0kKLS0tIEw5WjVoc1ZBTmluUVhlVmdKc0tB
|
||||||
K3J2cnlpRGlNQm1abmdMMzJXdER0NHcK0HbMgUuxwa7OqvWi+fDqNBflxzZoOm9I
|
bzZ1U0YydlNMSGExUTRrMWViWXhTekEK51bUaoMKTPTvGeG0vk9tu1TxkbgkNdff
|
||||||
dCHVWjoBL8j6CIpn9ybCBv9oUWhb17xwxd7YIVmkZ7oIQ7F9f3r/Yg==
|
u9NLDF1LhHOet7iisUOUFjXtZuA/1IFwUlFMKgF7w1PQtoA+G3+X6A==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1c2kc034n7tqztarcu7n5ldnjmy9sr3jgwrsaddsj0hwfus9mdp3sctts4m
|
- recipient: age1jy7pe4530s8w904wtvrmpxvteztqy5ewdt92a7y3lq87sg9jce5qxxuydt
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDYzBoQURsckNBTDFBcENw
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1N0JsTmJUTE5Qd3QyaDV5
|
||||||
ak8xZ3NIWDM0OGZmVElVVWJWbndwMjRJMlFBCnp3M2EwaDJkYWxrbHkwNUttREl3
|
ejBmMS82OHFSZW9tQTUvbVlKaVY2N0lqVWtZCnAxSnFreklwWG91cFFEelVHZ0pJ
|
||||||
cWRFWVpLbGMySGNFcENXbzJyd0k0NVEKLS0tIEtNd2Y2V2ZMWC9rQ0Z2Slk4YjBt
|
eDBYVzVwNHlZZUx0bXZvZm9GdUttR1UKLS0tIHc0N01UNFcxL1V2cHMwVXVkZ3pB
|
||||||
S1lKalRuSmRYYmlDeHgrUFFnL0lzaVkKE8mk9PiPD/Tb+e3GEy1sXvIxdInlNGh0
|
dUFCbXZtWjJNL0xEMmRtZjBEdnpLOWsKHaS5RtzjIRyQLEwiTrDaGB/oN6dMi/DL
|
||||||
HVHuQ/22UDTKSxXGKkD8WTl4VZVmJAwLAU4TbvtVzx96+SCi8uVy1Q==
|
Hf0pBSvjLjuAL7YIgfTzLUuHR62PdgH39fhpd3W7LG4/WerXjLS/Lg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-03-12T11:54:39Z"
|
lastmodified: "2025-03-12T11:54:39Z"
|
||||||
mac: ENC[AES256_GCM,data:g8nz1Azs5X59ulimMRzgvKz9Y7lKnjFq2SCctdt+yMBLojlk8RXMSf7tY311dZLcd00wi8xsGlBY1XaCbDjIlkG4sLWuQIareYjfqGK5s0pRvELTTF2ZE9yY+5iYdeVkBe7yv44sWJGNN1BcgFpR9zUouA+6yKVt2/XcPu8+7Fs=,iv:zDyECD2w1bTq0xbart+cIjHBAmfSHnpFG5nHPbiT2UY=,tag:b50oQfRgLtI/XbkINuzx5A==,type:str]
|
mac: ENC[AES256_GCM,data:g8nz1Azs5X59ulimMRzgvKz9Y7lKnjFq2SCctdt+yMBLojlk8RXMSf7tY311dZLcd00wi8xsGlBY1XaCbDjIlkG4sLWuQIareYjfqGK5s0pRvELTTF2ZE9yY+5iYdeVkBe7yv44sWJGNN1BcgFpR9zUouA+6yKVt2/XcPu8+7Fs=,iv:zDyECD2w1bTq0xbart+cIjHBAmfSHnpFG5nHPbiT2UY=,tag:b50oQfRgLtI/XbkINuzx5A==,type:str]
|
||||||
pgp: []
|
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.9.4
|
version: 3.9.4
|
||||||
|
|||||||
@@ -1,84 +1,97 @@
|
|||||||
ppetru-password: ENC[AES256_GCM,data:ykxGdbwTLNGKGy7PI/6uLyeWzEyfTo6R7d56m8Lb7kyY6rF0ovDzMGv71ruBA3CwznIp5EaCopvKVXf35xIEyptpQJie++ireQ==,iv:ArWScjeDHp/4DurW+id6PLUiwnMVVwk7iD5S9Bzc8lc=,tag:uErsF74I5D1M86Yl78Gqlw==,type:str]
|
ppetru-password: ENC[AES256_GCM,data:ykxGdbwTLNGKGy7PI/6uLyeWzEyfTo6R7d56m8Lb7kyY6rF0ovDzMGv71ruBA3CwznIp5EaCopvKVXf35xIEyptpQJie++ireQ==,iv:ArWScjeDHp/4DurW+id6PLUiwnMVVwk7iD5S9Bzc8lc=,tag:uErsF74I5D1M86Yl78Gqlw==,type:str]
|
||||||
sops:
|
sops:
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
age:
|
||||||
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpeCtRemFxOUErVll5OGlx
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4WExPaEtTdEljYkF1ZUQw
|
||||||
Sk5UM3Z2SUdJeUVoYlBXZFdiMlc2NlFLNEhFCk94YUtDbGtzVm9wbkRWNkFNbjY1
|
UHhRNDJZb2wydWVUaXFmR213SjJsNDFKU0FjCnJ3Tk1yZDZkU3orcHZ2UDY3elRi
|
||||||
aUQxSVhmWVVLRThMRWRCR00xbFk5czgKLS0tIG5wMGlaNi8wT3FTdkhhMkhvV3Ft
|
WW9FMXU0cDNjV3QrOWo3MVB0UzMwakUKLS0tIEhQVldBVWhmR0k0WW9jTE0xc2ZW
|
||||||
WHg4Zis0K20vM1MwcFVDSDQ3Tmx5N3cK8QO9Uyc11TdIDTUiOvTgAvgehVnWclRI
|
RWp4ZjlVN0FWaURlRHNONDhXdmJpS1EKZVXYyFRFD9KdyWuMoQytkQk4VxpBRyAV
|
||||||
UX7ISxlF+qBwfkoXeo3N6jl4buAOrKhY/ssrvjF8fXwl/dc4iVRbRw==
|
lF4FA99wjGMhHFNQExnqYYLYtFkA18/SB6pkneOjdhIvEr0IFLJEqg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1gtyw202hd07hddac9886as2cs8pm07e4exlnrgfm72lync75ng9qc5fjac
|
- recipient: age1gtyw202hd07hddac9886as2cs8pm07e4exlnrgfm72lync75ng9qc5fjac
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1bm9uQVZ3YlFXaldDSGhC
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjZ29wdk1aOHZJYWFjaG9v
|
||||||
d3lEbjFweGY3b1Eyd2RQcFRYQ1ZCNDU5U0ZBCjVBUHhmOEtieVp3M0UrbzE5U0Nn
|
RGxsek95QmtrZS9xRWdKMFdLSHZ3NmlZRGxzCnBvRXZkYnkxdkhJWkY0Ukg1M0dE
|
||||||
cnJjR0g3MCt0SngreWJpMFlFM2RDekUKLS0tIGdmQWgzelpabFJ0VWRaQ1FiRjRZ
|
dWc3QWtCdkV5Ymd4MkxhZWl0ZDNCZXcKLS0tIGMrVWtNNWtscm9STUN1aHVZc2Ny
|
||||||
UW9GbmUybkpXUExtWnJldENMek5wV00K/3ZKwVjEc/gfkwPZ/baPPNrc1SN9Yudn
|
Vm1oaFFTbTBpRWxuR3gxbUZ0YkZieVkKdaSSXrDzAUGkj3w8/YcFZaJTiUUEbJdw
|
||||||
DtKZfbR9nsqflEtuP2y7vEkEzBj3u/nRD8t7gvj9bAnjJGB+9HCdyA==
|
GjuLz7bxX8+HQvhSbu6/KCwG6R4j1eO5Zg1w0wYtyeUOV1HfZEGQog==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age16yqffw4yl5jqvsr7tyd883vn98zw0attuv9g5snc329juff6dy3qw2w5wp
|
- recipient: age16yqffw4yl5jqvsr7tyd883vn98zw0attuv9g5snc329juff6dy3qw2w5wp
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLQk9lUWRWcEpzYlNnSStt
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIMGpibmNRUDRFaFVOTDB4
|
||||||
L2E3RUE0VG9SZ2pZcmYrbmZ3M3c2VkVWckFNClRHSnJhakcwNkZaSmg3aWVPSXZG
|
RVdTc1RrTmRPb0dlZGlpcGxuRlJ1L2w5MVVBCi9HdXNGZmdSaVZsQWRoa2RpVDNV
|
||||||
dUVQQWpqQjlwazQ4SitScllWMnhHRG8KLS0tIFZRWU1lbWhEdkZ5VFl2bWRJTkZM
|
OXBtS0pwYnhjS2hCUk10UUtwam4zMWcKLS0tIFV0dVpQNGpSOEVoZnE5OGpCZkxa
|
||||||
Q1VaTjl6U2hzeWZUeDlab0RaNGlIa1EKaiEDRzdkn0dAoQdps1W1UHAYATDvP531
|
MFMxSG95dmJncGJzR29mQkVzNjFIQUEKrJ0MDTBmiwiAaLt7CJ1pjlxuFvZJuRkR
|
||||||
6V/KikZPwY8g6UBUsq53CKKx8tx4SvqixAuAYJT29WtPLIfn2wGnDA==
|
EuLYOYLdVaxgZ442io5OE7wme0P4LLcxSAreDG84GVs67JHvsFE89g==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1zxf8263nk04zf4pu5x2czh6g4trv4e2xydypyjschyekr6udqcsqmrgv68
|
- recipient: age14aml5s3sxksa8qthnt6apl3pu6egxyn0cz7pdzzvp2yl6wncad0q56udyj
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFVnZ0OERvMzRxSVE2MEFI
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBucHdSNGNyRkVITmNDVkpx
|
||||||
dmRCQUZ1a2YyN1JoMGcxdGhwT0cvcFhnSDNZCnYxa2R2T01aWmVpWUdrK0JTNGkv
|
QVFKK0VucFNSMnNqSGRFRmRoRWpsZ0srUUhrCkwwY2pDSkJ0aGlqc3U3ZXNJUVl0
|
||||||
empMTjFkRzZLZUFJVkpZU0tXUnRlcTgKLS0tIFU4QXk3NlR3b1o0UmVhNWt4NVR3
|
bXZMSVg3bDhaK3d1MTBnL1BQVUhkMUkKLS0tIDdxSk1DMVpsbnI1QlFnNEFJYXRD
|
||||||
anJ5R3Z0MVNFWEZVM0pnQVgzcjdaSVUKcKKDp0mu4yO6Sxu6CDweETwJ6b404+rT
|
RTNxYUxlUGxsM1NvekZ4R1hQVE9KMk0KocfE75DTfQMj/RsznOdeF82aO8WwO4HD
|
||||||
YfznubwZw+bbTS/W1yXvmKE9cSZ1A6EUldaGjizS+wR1fKpCwEGoHQ==
|
1xakOM2FHoHi60Q5uOWzfGtz0i+R4ue9hafa5Esn01TOjc3qWSlW3A==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1me78u46409q9ez6fj0qanrfffc5e9kuq7n7uuvlljfwwc2mdaezqmyzxhx
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYTEhiSDZvZTg3ZWxJRXlu
|
||||||
|
a0ozOXRVL2lia054SkNLc2tEYmlZUCt1NW1JCkorK0hub1pLQTE0QThEUDRDWXJV
|
||||||
|
YWtGamNxMTFIYjVDT2RqTXh0Z2hVTjAKLS0tIGxoRTAwc3FKVVNSQndtbTZmc3BR
|
||||||
|
QnMrK2lMT25tR1ErV2xvS01JWWswVUEKtrGaLETMfY2D8qmgml/fgGxkvQLoiMTP
|
||||||
|
l3a7Y6kwutuzRnmW1tnWv7yoPbTn+BDwfOwBcnesl2x0aJ5iLUKruA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1cs8uqj243lspyp042ueu5aes4t3azgyuaxl9au70ggrl2meulq4sgqpc7y
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqMFJ1bzQxWjlZTmF6eEl0
|
||||||
|
d3VVd0VsbGZGdDBKRG9uNEhaMThmWmpuQ1hFClA1aDhwRU1Pb2pibGh6T0pqdmlq
|
||||||
|
S3cxM0wyWWlCL3U5TjV4Vkg4blRsUVkKLS0tIENnYk5GbmZWbFo4cElON1Z0ZVlv
|
||||||
|
ZDdsci9rcG5Wc2V0NlQ3MWx1cFF4dUkKumFT4xtjGDBGK+/SV27Dh/vyGMJAEZNo
|
||||||
|
9gTmVLfR9vXVAXUdOMcqgo7Nl4OJCS4HrDxvVCoER/bVoQVRiPzuXw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1w5w4wfvtul3sge9mt205zvrkjaeh3qs9gsxhmq7df2g4dztnvv6qylup8z
|
- recipient: age1w5w4wfvtul3sge9mt205zvrkjaeh3qs9gsxhmq7df2g4dztnvv6qylup8z
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBTm1XZTdDU2tCMlRUZlR3
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCM2E5a2lsZGJzRnk5N3Rr
|
||||||
SURZbU5LOHl6MlVpb0J1QW5TbmZ1S3J5aERFCm5pTnJjUmg0Q1VWWUJ6TThTWGx0
|
bWRwRlI2c0c4NzBNdEVqMGZFWTZtNDlvSzJFCmFPM05XbndsazRGWEw3Zy83dldm
|
||||||
dmMwUGlVc3FqTHFvRWhiQnp0UWljSTgKLS0tIHVXWjlaNjBTaTM4ck1XVWRFcXNi
|
eXhEZUZQZWk5bVNwaEk5SDRka0NOWjAKLS0tIHNvZ016Rjh5bmYwRUxyRWRydFpI
|
||||||
L2pWazRCVnZDUHd6bUpvbG1JWEgvNFEKKT3AWCrMFyGp2bnAUMi1RDxKvJSUm5We
|
Z0NHYjFzem55bVNORGlVbVNxR2psc2cK6JpNZwznwgl61d/W9g+48/894TQRe4gJ
|
||||||
qt5ZaZbV8VqAhrZhHXb3KpWZYcof5yxTRGOalfKMSaAGg9Mr0itN6w==
|
nl4oDwRPbZwJZgdAKQVfTTujB0QbWpJc24mDGD4I4CydqTKwy6FN3A==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1wwufz86tm3auxn6pn27c47s8rvu7en58rk00nghtaxsdpw0gya6qj6qxdt
|
- recipient: age1wwufz86tm3auxn6pn27c47s8rvu7en58rk00nghtaxsdpw0gya6qj6qxdt
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKQWhWcC95OGRpNStyY21U
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlK1A1eVdRQThQUHdqbHdk
|
||||||
K3UyaXR3dUJhelVVUXpvMDRpNzlYZHFUVFNvCitzaUM5akl2RGlsTDBsdHptaTRM
|
b1MyMlBJUFluTm13ZWwwc1RNbThFZUMrNXhzCnRPTVhPSzUzM0VtaUVJbFl5Wllj
|
||||||
MUFsNmlrS1JYV0w4anZMc2QxNy9sbjAKLS0tIHFGY2cwekpoL3IyMHAwK1VBai9D
|
NUlndzc3Yzhjd1JSb3czajI3UmRDZ1kKLS0tIE03M1hab1MxU0I2VExBWlh2TnJC
|
||||||
NlVPMFNySmhjNzhSR0k2Z3kyRnpKZEkKfTCC2nPXDFEx7w2U5Z2Kdp8FPHAFakL1
|
eGRXRTlsWmlpenJrVkMxakJZVTV0cE0KMQCKscSLnCu3NsurFFiDaUGjJbyIAwd0
|
||||||
xX4L4l878IfuRz7yMQGdS90tCexPocord/zWRks65JFdm31TLdkOVg==
|
HTutCiuPYVI4zznQ3RZDBeO5L6a/twXxMRTePUCwOkRNWRWpzR9nxg==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1c2kc034n7tqztarcu7n5ldnjmy9sr3jgwrsaddsj0hwfus9mdp3sctts4m
|
- recipient: age1jy7pe4530s8w904wtvrmpxvteztqy5ewdt92a7y3lq87sg9jce5qxxuydt
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXT2Q5Z3BoZzFPQ2FSbkY4
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1VEJmMWlnemFGNExWYUI4
|
||||||
dFYyRHc0dlpHdktUR2tKYUJ3Zjg3dWJpMWxJCkthenZ5TnkwL3B2bzFFQzN5WUJ0
|
QWRwRktwODNvSmlEcGJORHNlQXNVeXVpbFNrCms0QUFNdDlrNjMxazU1UTcwc2JF
|
||||||
Uk5iRm5QOTk2Y1BDcXFmVElDTjAySDAKLS0tIElVUkpyeXYwQ2Z6N0QvdDZVdkVo
|
RC9JUnJsWmgyc01zZU9JQmxuM3V6STQKLS0tIGxQZGFsZ0pNTjQ3QW1sS0E2Y2RM
|
||||||
K1MySzNiNWhBV2VaTVdEQ2pzZjJmME0K+Fvb4fpLEc8fcAFyeCQmdrXERUogjIvR
|
aVVrNW1BNXQ5UDk1UEtVVWJPNHpwUFUKcArFPFknBj8ss1lD38YtMaB06L/ASeu5
|
||||||
hlkO/x5nFdipBqNPLzY5ytE3GpgRTuq/O3+uXpdOk65Eq1Uwlrcm7w==
|
u4ff0rTDx237snaSFg5RIJ+6uxX16p5ODg3xOYGOMkDeuTLdl2bg3A==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1zjgqu3zks5kvlw6hvy6ytyygq7n25lu0uj2435zlf30smpxuy4hshpmfer
|
- recipient: age1zjgqu3zks5kvlw6hvy6ytyygq7n25lu0uj2435zlf30smpxuy4hshpmfer
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPdkE0Uk5RNzI0MnRnc0Q5
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArWTNkaFlrQkJHRnd4cTBw
|
||||||
UFVxOVRyQjRrTUNla0lpblVBUDNCVGU3clVzCk1Pd0RzUmxuVVI5WHRhYVdVYUVQ
|
N3dnTXk3SlJkQkZDdWpLcEpNQ2Z2RHZoVjBJCjBaK1MzbzdaaXluR1dFaFFNaGEx
|
||||||
MGkyS0F2ZlhIT0d3WU5SQloyYWN0eXMKLS0tIGROZ3J5SUZBVGt5SkZRY3dpdzht
|
VTNrVU0yeG9KQkhqUkYxU3VBM0E0R1UKLS0tIDJHek9vVldSZGN0M0c0UHcySGhk
|
||||||
bkFsT1NyWXhXbGJ6dWJRcWZBbE1vZ1UK2q/dIfdaRn18XvPJJUC/ML/cHZN+/XhQ
|
Z2RoZno4bmhidytlL2ZmNWUzNTcwcVEKXvgaO8Uo0R+Kc8lizLtVxmTi0W5XHjYw
|
||||||
BYxCkg+8z6F+tWzJ/7yuV522fKRW7Vw/8jPQ1obPTRTYGvWSgPVVBg==
|
7evdCHQHmFl0vg/bGOJBmcTUhioJv06D0LR3XMl9I6ufXDNaT/NHxw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-04-04T09:34:06Z"
|
lastmodified: "2025-04-04T09:34:06Z"
|
||||||
mac: ENC[AES256_GCM,data:YIcRrsPparPfPaI2+MLlKsxu7M19H8nndOsrDLuh/5BXzIZNiuTIWyvxODyhI745rDwlibO+7Q0QctanhTl4+IzGaYtuY4i+rb+3dzBMpcdT2VAbtCHHxcltWeanRGFq2K3WM2tbnQCERst5kejfn0Razjq3UU5vNwfBsdJMwGc=,iv:izDxy0ufVnH8ImkZIngcYhGuj0PGpLqBD/ZDvQyE+5I=,tag:oYBUEQS52pr09h5OvOadNg==,type:str]
|
mac: ENC[AES256_GCM,data:YIcRrsPparPfPaI2+MLlKsxu7M19H8nndOsrDLuh/5BXzIZNiuTIWyvxODyhI745rDwlibO+7Q0QctanhTl4+IzGaYtuY4i+rb+3dzBMpcdT2VAbtCHHxcltWeanRGFq2K3WM2tbnQCERst5kejfn0Razjq3UU5vNwfBsdJMwGc=,iv:izDxy0ufVnH8ImkZIngcYhGuj0PGpLqBD/ZDvQyE+5I=,tag:oYBUEQS52pr09h5OvOadNg==,type:str]
|
||||||
pgp: []
|
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.9.4
|
version: 3.9.4
|
||||||
|
|||||||
@@ -1,30 +1,25 @@
|
|||||||
kopia: ENC[AES256_GCM,data:AS5zTDpPPuPGEoT05uHyAfPTbls=,iv:YZK8O0/osP0/ay1tw2kkiCoxws+DlzquVqXNdVayE+k=,tag:tCNM8fzEEuRTPDJybq7fUA==,type:str]
|
kopia: ENC[AES256_GCM,data:AS5zTDpPPuPGEoT05uHyAfPTbls=,iv:YZK8O0/osP0/ay1tw2kkiCoxws+DlzquVqXNdVayE+k=,tag:tCNM8fzEEuRTPDJybq7fUA==,type:str]
|
||||||
sops:
|
sops:
|
||||||
kms: []
|
|
||||||
gcp_kms: []
|
|
||||||
azure_kv: []
|
|
||||||
hc_vault: []
|
|
||||||
age:
|
age:
|
||||||
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwOUY0MFRzNkV4WTlyVXhj
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtSjhXazlWd3YwNVFKVkw4
|
||||||
L2drMTlUZ2pzN09mVk4xYk90cmg0VXVvbXdFCjNrYjNCQ1RXaXo3Nm5ScTZIcHJy
|
dDMydVFCN1lLeUJOWkxuSGJ1a0srNm9PaWswCm8yZ3hiOWFHUlAzNVRrck53OElD
|
||||||
eGdVRkhpV0J1bC9jenkwS3l0UXVSMXMKLS0tIDZXbythcWN3Y21zZVVvNkhiVmY5
|
b056YmV4S2NtNnEzRkpnRVNEblV5blkKLS0tIG1ramoya3RHV1FJZGlFU2ZSeUtS
|
||||||
cnJZYWg3VVZsbGZhSHM5b2tXMTk2d1EKz1Dd5jhfVT+f+nRCYNFo1YuTDVzTUq91
|
KzJlbEsvYWlXaHhEQU5oOS9HaDdYSDAKvlhKgi4Pf8xVB5MnO33GWYg313mRdUGu
|
||||||
W1HDd/6SvBfky80+KXTEqZL/TL+gjgKEdyXQryrfH/rfvymqzDpGaA==
|
kFCs5b1N96x9JOS7zgnM0AKDY8IPBSe33tmDqtYygwPdkOys1PmZkw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
- recipient: age1zxf8263nk04zf4pu5x2czh6g4trv4e2xydypyjschyekr6udqcsqmrgv68
|
- recipient: age14aml5s3sxksa8qthnt6apl3pu6egxyn0cz7pdzzvp2yl6wncad0q56udyj
|
||||||
enc: |
|
enc: |
|
||||||
-----BEGIN AGE ENCRYPTED FILE-----
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPcWZxaE9EbWlIM0R5Wkhj
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBYTVovQld2RkRxaW90b3lR
|
||||||
MmFMdlhyR2Vma3RsbnM4ak9sKzdLWENaUTJFCkNXVDNmRUJTRWFPeEpXcWl0cE9Z
|
NGFtbWVLZUNHdnlZVWkrL1RXUHBVeGdvSDJrClJmSmZRZmdjcy8rNnJBVmVUWDZq
|
||||||
dm53UTJVSlZpNmdieFJEYmU5TVhhUkUKLS0tIHhwSWhuWUhUYmZrK1Ezelpud3J3
|
M2lPbDBhT0Y0NkJ5a1FNYnU3Zkl0TkEKLS0tIGxqM2h2TDB2akl4ODlYY042R1Z4
|
||||||
Sit5S0hzcGZEL0oxRmNVbVNhYklaaTAKf0ts/HpTcrLH8svaB3gwFH4W4QIdrPPE
|
ZVJWN3pZelFJR0Jid3JseEZKVFZtYmsKmKXQRjnghuF/s9z2Xk98sFvxic91fGa2
|
||||||
trGqXGj8YOkiA78J1maKijXuqjtPvKkBEPYekEY3c378gZhFdL+8lQ==
|
V7IGmpqAYQV3jJ1G4cjJxtpidQ6fLCqlnR+sq+y8+dT+LN7i+Zbnnw==
|
||||||
-----END AGE ENCRYPTED FILE-----
|
-----END AGE ENCRYPTED FILE-----
|
||||||
lastmodified: "2025-10-19T17:33:13Z"
|
lastmodified: "2025-10-19T17:33:13Z"
|
||||||
mac: ENC[AES256_GCM,data:IwEyBr/I7BJa0gWZ494dCT0ogyP2PbnUg5fLOn15vZAHIyYtTB3dI3gV5Lx7oPdqOPlI61MsShIYBnk0uBChpNu6O4oiGUfwvBfegzlDyHHERLx+S7nZpcwmf/3JoNXwq0f2OtOu8nA6Q1V4gVjFFNWUCAh5cq106vG1awsQkn0=,iv:j+JcVtKz2RfyWu55dUeJJTRK6prB9DGLvcjiAAdVySM=,tag:Pg5sKiLzYUFoN9Duu+nF0w==,type:str]
|
mac: ENC[AES256_GCM,data:IwEyBr/I7BJa0gWZ494dCT0ogyP2PbnUg5fLOn15vZAHIyYtTB3dI3gV5Lx7oPdqOPlI61MsShIYBnk0uBChpNu6O4oiGUfwvBfegzlDyHHERLx+S7nZpcwmf/3JoNXwq0f2OtOu8nA6Q1V4gVjFFNWUCAh5cq106vG1awsQkn0=,iv:j+JcVtKz2RfyWu55dUeJJTRK6prB9DGLvcjiAAdVySM=,tag:Pg5sKiLzYUFoN9Duu+nF0w==,type:str]
|
||||||
pgp: []
|
|
||||||
unencrypted_suffix: _unencrypted
|
unencrypted_suffix: _unencrypted
|
||||||
version: 3.9.4
|
version: 3.9.4
|
||||||
|
|||||||
25
secrets/stinky.yaml
Normal file
25
secrets/stinky.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
kopia: ENC[AES256_GCM,data:boi8V0Kn,iv:Kwe1hn44DJe9dpv8jVrJjwyblVouakuCdnEK9uotTkY=,tag:B5hrpRBP17kFVn4iy5TOlA==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4aXRBWUg3QU12UWNBNXI4
|
||||||
|
RS91amdnOXhibXpiYjgrQ2FwR3J0VER1cEdjCnlaTXFSMzFPNmlnSTIvejJuMUFU
|
||||||
|
T2lUSDRQeFVtT1ZHb2xNZVNpWDJOTmsKLS0tIElHK3FVbUFSREMwcVN5V0tPSEtt
|
||||||
|
a2ZyNXFnZzBkeWZsU2docUxzQVMyUFkKkiEW3ovgVBLlBEHyx6hSXVp8PTeZ+2PL
|
||||||
|
kzW8AnQTi714iQqyN3NlkJ8r+1doGBr9U492KXpjdt1woY4MwMvWkA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1me78u46409q9ez6fj0qanrfffc5e9kuq7n7uuvlljfwwc2mdaezqmyzxhx
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCN0Fvdm5Mc3lqNDh6VEp5
|
||||||
|
Mk83N0dNU2pnWVFRODl5MllIaHdIUm5SclJJCjNPQVBGOGRIRlVVL1lzYU5ocjRx
|
||||||
|
Sis5VzZXN3AxYUpxNm9pZE5WUzZGaTQKLS0tIFlpL09vQmpDWjNJeXg5dUZZSm5O
|
||||||
|
S2ZOdExQdzJRcGdmUWtrRUpmVy9lY3cKJwEoO9WltW2FIFEylGuWBHwSJlnAIy8M
|
||||||
|
FFCmmApdkzJLwvQGg5kNC/4Xx34ZfNTTpePxh9qP0ASxUQASZo2urA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2025-10-26T16:59:40Z"
|
||||||
|
mac: ENC[AES256_GCM,data:FlSv9PIcmX+oJNVaUpXIG2thzUvEb7bMGDOvIRgAFVzoUipIes0qdbU0R/pqogW0NpgbXNLhNBmemKfheGusngatJmbNwHT9Hqo7a82U9j1G302sziqrcz1pOxG79oacFEM+coWpXGgmMXYeNlQEihUvvvUt810VWBb3Hjba80g=,iv:6gSTUd2y9YxiOCzwQ/udLN46lgfwgWDgfSTOpaJpPmY=,tag:q/Ta6fejjKMg0TmZhNmy8Q==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.11.0
|
||||||
25
secrets/wifi.yaml
Normal file
25
secrets/wifi.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
wifi-password-pi: ENC[AES256_GCM,data:n5ZfyhBCrHx98uUxFQ==,iv:9SQHcIw252GeS0IxON3ThqOk02Wtlfu/Df6KMLAmokw=,tag:F5pAHlInkqVUQDg8MPnMgQ==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- recipient: age1df9ukkmg9yn9cjeheq9m6wspa420su8qarmq570rdvf2de3rl38saqauwn
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUd1lyZG9GVHBZZHU0Wkl5
|
||||||
|
RFJ2NUdtUFRUbmd3aTRFV2dGaVA2S3RWOGk0CmlLV2ZYdERvb21iT0dlUk42TW5S
|
||||||
|
LzdxVlA1U1FpWkxIb1pMeUtRRm9NdFkKLS0tIGszaFM0dkhHeWZUcXc1dlo3SDBX
|
||||||
|
WjltV282VlJtTlBCRmdzOU16R0x5UUUKBTFArSUNWtq7r+HduxT0ChvYfjo8HtbG
|
||||||
|
KeYBoB9QwY5wNRMlk0AIlJVNLKW8A2tC9T8ehbtjol13H7PQK+wsQQ==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1me78u46409q9ez6fj0qanrfffc5e9kuq7n7uuvlljfwwc2mdaezqmyzxhx
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4THVFa1p5c2l5V0pKckVC
|
||||||
|
YUdYbitJbUpjclAydG4yekxhbXdzeDNpbXdRCnRCZVI1cWJiQi9TdkR3Y0E5TklO
|
||||||
|
T2dHYXFKeW9KSkdXOWFnbWVRQUZOL28KLS0tIDVMVldvd0NWcU5QWkhDTTBmUTla
|
||||||
|
aUs0dTB3Y3RXTlBCOCtYSHdOMUYxdTgKQShxsJ+3EQU18uixmM3FlCe5C9Rl3oS5
|
||||||
|
gwZIrh0amSzX3f9SOjf42h1d+IDL/DMWAlSA/3XMx8TK9A1zKZDgVA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2025-10-29T14:55:56Z"
|
||||||
|
mac: ENC[AES256_GCM,data:2zTEzx8UxOMHIytiufCHS/B1ci7kI05+SIE8ziMY8/ItoAYtt0zXXEgRWs0NLVb3P2vXMOhnXG4qO1o20UXt6Wqq9j1zXPVaQTQie4QSPDdX/8OXXi87Ggm3WQyeA1IfABacfL0D6XkNvxfMHGvMrnhYltPPgYDuNlgjnnjTm8o=,iv:FJMKLSlAenvSNUH6OmeGIR7f9Bzl3NwqaUaokoHEj50=,tag:WU4BnlLu5cKSbtiYL0mNKg==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.11.0
|
||||||
@@ -27,7 +27,7 @@ job "adminer" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.adminer.entryPoints=websecure",
|
"traefik.http.routers.adminer.entryPoints=websecure",
|
||||||
"traefik.http.routers.adminer.middlewares=authentik@file",
|
"traefik.http.routers.adminer.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
job "authentik" {
|
|
||||||
datacenters = ["alo"]
|
|
||||||
|
|
||||||
group "auth" {
|
|
||||||
network {
|
|
||||||
port "http" {
|
|
||||||
# traefik forwardAuth hardcodes this port
|
|
||||||
static = 9000
|
|
||||||
}
|
|
||||||
port "https" {
|
|
||||||
to = 9443
|
|
||||||
}
|
|
||||||
port "metrics" {
|
|
||||||
to = 9300
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task "server" {
|
|
||||||
driver = "docker"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image = "ghcr.io/goauthentik/server:${var.authentik_version}"
|
|
||||||
ports = [
|
|
||||||
"http",
|
|
||||||
"https",
|
|
||||||
"metrics"
|
|
||||||
]
|
|
||||||
command = "server"
|
|
||||||
}
|
|
||||||
|
|
||||||
env {
|
|
||||||
AUTHENTIK_REDIS__HOST = "redis.service.consul"
|
|
||||||
AUTHENTIK_POSTGRESQL__HOST = "postgres.service.consul"
|
|
||||||
AUTHENTIK_POSTGRESQL__NAME = "${var.pg_db}"
|
|
||||||
AUTHENTIK_POSTGRESQL__USER = "${var.pg_user}"
|
|
||||||
AUTHENTIK_POSTGRESQL__PASSWORD = "${var.pg_password}"
|
|
||||||
AUTHENTIK_SECRET_KEY = "${var.secret_key}"
|
|
||||||
AUTHENTIK_EMAIL__HOST = "192.168.1.1"
|
|
||||||
AUTHENTIK_EMAIL__FROM = "authentik@paler.net"
|
|
||||||
}
|
|
||||||
|
|
||||||
resources {
|
|
||||||
cpu = 2000
|
|
||||||
memory = 1024
|
|
||||||
}
|
|
||||||
|
|
||||||
service {
|
|
||||||
name = "authentik"
|
|
||||||
port = "http"
|
|
||||||
tags = [
|
|
||||||
"traefik.enable=true",
|
|
||||||
# Main UI
|
|
||||||
"traefik.http.routers.authentik.entryPoints=websecure",
|
|
||||||
"traefik.http.routers.authentik.rule=Host(`authentik.v.paler.net`) || Host(`authentik.alo.land`)",
|
|
||||||
# Embedded outpost for forward auth
|
|
||||||
"traefik.http.routers.authentik-palernet.entryPoints=websecure",
|
|
||||||
"traefik.http.routers.authentik-palernet.rule=HostRegexp(`{subdomain:[a-z0-9-]+}.v.paler.net`) && PathPrefix(`/outpost.goauthentik.io/`)",
|
|
||||||
"traefik.http.routers.authentik-aloland.entryPoints=websecure",
|
|
||||||
"traefik.http.routers.authentik-aloland.rule=HostRegexp(`{subdomain:[a-z0-9-]+}.alo.land`) && PathPrefix(`/outpost.goauthentik.io/`)",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
service {
|
|
||||||
name = "authentik-metrics"
|
|
||||||
port = "metrics"
|
|
||||||
tags = [ "metrics" ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task "worker" {
|
|
||||||
driver = "docker"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image = "ghcr.io/goauthentik/server:${var.authentik_version}"
|
|
||||||
command = "worker"
|
|
||||||
}
|
|
||||||
|
|
||||||
env {
|
|
||||||
AUTHENTIK_REDIS__HOST = "redis.service.consul"
|
|
||||||
AUTHENTIK_POSTGRESQL__HOST = "postgres.service.consul"
|
|
||||||
AUTHENTIK_POSTGRESQL__NAME = "${var.pg_db}"
|
|
||||||
AUTHENTIK_POSTGRESQL__USER = "${var.pg_user}"
|
|
||||||
AUTHENTIK_POSTGRESQL__PASSWORD = "${var.pg_password}"
|
|
||||||
AUTHENTIK_SECRET_KEY = "${var.secret_key}"
|
|
||||||
AUTHENTIK_EMAIL__HOST = "192.168.1.1"
|
|
||||||
AUTHENTIK_EMAIL__FROM = "authentik@paler.net"
|
|
||||||
}
|
|
||||||
|
|
||||||
resources {
|
|
||||||
memory = 600
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "pg_user" {
|
|
||||||
type = string
|
|
||||||
default = "authentik"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "pg_password" {
|
|
||||||
type = string
|
|
||||||
default = "aQueiquuo6aiyah5eoch"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "pg_db" {
|
|
||||||
type = string
|
|
||||||
default = "authentik"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "secret_key" {
|
|
||||||
type = string
|
|
||||||
default = "uUzCYhGV93Z8wKLAScuGFqBskxyzSfG4cz6bnXq6McM67Ho7p9"
|
|
||||||
}
|
|
||||||
|
|
||||||
variable "authentik_version" {
|
|
||||||
type = string
|
|
||||||
default = "2025.6"
|
|
||||||
}
|
|
||||||
@@ -37,7 +37,7 @@ job "beancount" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.finances.entryPoints=websecure",
|
"traefik.http.routers.finances.entryPoints=websecure",
|
||||||
"traefik.http.routers.finances.middlewares=authentik@file",
|
"traefik.http.routers.finances.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,120 +0,0 @@
|
|||||||
job "code-server" {
|
|
||||||
datacenters = ["alo"]
|
|
||||||
|
|
||||||
meta {
|
|
||||||
uuid = uuidv4()
|
|
||||||
}
|
|
||||||
|
|
||||||
group "code" {
|
|
||||||
network {
|
|
||||||
port "http" {
|
|
||||||
to = 8080
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
volume "appdata" {
|
|
||||||
type = "host"
|
|
||||||
read_only = false
|
|
||||||
source = "appdata"
|
|
||||||
}
|
|
||||||
volume "nix-store" {
|
|
||||||
type = "host"
|
|
||||||
read_only = true
|
|
||||||
source = "nix-store"
|
|
||||||
}
|
|
||||||
volume "sw" {
|
|
||||||
type = "host"
|
|
||||||
read_only = true
|
|
||||||
source = "sw"
|
|
||||||
}
|
|
||||||
|
|
||||||
task "server" {
|
|
||||||
driver = "docker"
|
|
||||||
|
|
||||||
config {
|
|
||||||
image = "codercom/code-server:latest"
|
|
||||||
ports = ["http"]
|
|
||||||
|
|
||||||
volumes = [
|
|
||||||
"/data/services/code:/home/coder",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
env {
|
|
||||||
ANTHROPIC_API_KEY = "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"
|
|
||||||
}
|
|
||||||
|
|
||||||
user = "1000"
|
|
||||||
|
|
||||||
resources {
|
|
||||||
cpu = 1000
|
|
||||||
memory = 1024
|
|
||||||
}
|
|
||||||
|
|
||||||
service {
|
|
||||||
name = "code"
|
|
||||||
port = "http"
|
|
||||||
|
|
||||||
tags = [
|
|
||||||
"traefik.enable=true",
|
|
||||||
"traefik.http.routers.code.entryPoints=websecure",
|
|
||||||
"traefik.http.routers.code.middlewares=authentik@file",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
volume_mount {
|
|
||||||
volume = "nix-store"
|
|
||||||
destination = "/nix/store"
|
|
||||||
}
|
|
||||||
volume_mount {
|
|
||||||
volume = "sw"
|
|
||||||
destination = "/sw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task "setup" {
|
|
||||||
driver = "exec"
|
|
||||||
|
|
||||||
lifecycle {
|
|
||||||
hook = "prestart"
|
|
||||||
sidecar = false
|
|
||||||
}
|
|
||||||
|
|
||||||
config {
|
|
||||||
command = "sh"
|
|
||||||
args = ["-c", <<EOF
|
|
||||||
# Set up npm global directory
|
|
||||||
export NPM_CONFIG_PREFIX=/appdata/code/.npm-global
|
|
||||||
mkdir -p $NPM_CONFIG_PREFIX
|
|
||||||
|
|
||||||
# Check if we should update (weekly check)
|
|
||||||
WEEK_AGO=$(date -d '7 days ago' +%s 2>/dev/null || date -v-7d +%s 2>/dev/null || echo 0)
|
|
||||||
LAST_UPDATE=$(stat -c %Y /appdata/code/.claude-last-update 2>/dev/null || echo 0)
|
|
||||||
|
|
||||||
if [ ! -f /appdata/code/.claude-installed ] || [ $LAST_UPDATE -lt $WEEK_AGO ]; then
|
|
||||||
echo "Installing/updating Claude Code..."
|
|
||||||
/sw/bin/npm install -g @anthropic-ai/claude-code --prefix=$NPM_CONFIG_PREFIX
|
|
||||||
touch /appdata/code/.claude-installed
|
|
||||||
touch /appdata/code/.claude-last-update
|
|
||||||
else
|
|
||||||
echo "Claude Code is up to date (checked within last week)"
|
|
||||||
fi
|
|
||||||
EOF
|
|
||||||
]
|
|
||||||
}
|
|
||||||
user = "1000"
|
|
||||||
volume_mount {
|
|
||||||
volume = "appdata"
|
|
||||||
destination = "/appdata"
|
|
||||||
}
|
|
||||||
volume_mount {
|
|
||||||
volume = "nix-store"
|
|
||||||
destination = "/nix/store"
|
|
||||||
}
|
|
||||||
volume_mount {
|
|
||||||
volume = "sw"
|
|
||||||
destination = "/sw"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -49,7 +49,7 @@ job "evcc" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.evcc.entryPoints=websecure",
|
"traefik.http.routers.evcc.entryPoints=websecure",
|
||||||
"traefik.http.routers.evcc.middlewares=authentik@file",
|
"traefik.http.routers.evcc.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ job "gitea" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.gitea.entryPoints=websecure",
|
"traefik.http.routers.gitea.entryPoints=websecure",
|
||||||
|
"traefik.http.services.gitea.loadBalancer.serversTransport=gitea-transport@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,19 +25,22 @@ job "grafana" {
|
|||||||
GF_SERVER_ROOT_URL = "https://grafana.v.paler.net"
|
GF_SERVER_ROOT_URL = "https://grafana.v.paler.net"
|
||||||
GF_AUTH_BASIC_ENABLED = "false"
|
GF_AUTH_BASIC_ENABLED = "false"
|
||||||
GF_AUTH_GENERIC_OAUTH_ENABLED = "true"
|
GF_AUTH_GENERIC_OAUTH_ENABLED = "true"
|
||||||
GF_AUTH_GENERIC_OAUTH_NAME = "authentik"
|
GF_AUTH_GENERIC_OAUTH_NAME = "Pocket ID"
|
||||||
GF_AUTH_GENERIC_OAUTH_CLIENT_ID = "E78NG1AZeW6FaAox0mUhaTSrHeqFgNkWG12My2zx"
|
GF_AUTH_GENERIC_OAUTH_CLIENT_ID = "99e44cf2-ecc6-4e82-8882-129c017f8a4a"
|
||||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET = "N7u2RfFZ5KVLdEkhlpUTzymGxeK5rLo9SYZLSGGBXJDr46p5g5uv1qZ4Jm2d1rP4aJX4PSzauZlxHhkG2byiBFMbdo6K742KXcEimZsOBFiNKeWOHxofYerBnPuoECQW"
|
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET = "NjJ9Uro4MK7siqLGSmkiQmjFuESulqQN"
|
||||||
GF_AUTH_GENERIC_OAUTH_SCOPES = "openid profile email offline_access"
|
GF_AUTH_GENERIC_OAUTH_SCOPES = "openid profile email groups"
|
||||||
GF_AUTH_GENERIC_OAUTH_AUTH_URL = "https://authentik.v.paler.net/application/o/authorize/"
|
GF_AUTH_GENERIC_OAUTH_AUTH_URL = "https://pocket-id.v.paler.net/authorize"
|
||||||
GF_AUTH_GENERIC_OAUTH_TOKEN_URL = "https://authentik.v.paler.net/application/o/token/"
|
GF_AUTH_GENERIC_OAUTH_TOKEN_URL = "https://pocket-id.v.paler.net/api/oidc/token"
|
||||||
GF_AUTH_GENERIC_OAUTH_API_URL = "https://authentik.v.paler.net/application/o/userinfo/"
|
GF_AUTH_GENERIC_OAUTH_API_URL = "https://pocket-id.v.paler.net/api/oidc/userinfo"
|
||||||
GF_AUTH_SIGNOUT_REDIRECT_URL = "https://authentik.v.paler.net/application/o/grafana/end-session/"
|
GF_AUTH_SIGNOUT_REDIRECT_URL = "https://pocket-id.v.paler.net/logout"
|
||||||
# Optionally enable auto-login (bypasses Grafana login screen)
|
# Optionally enable auto-login (bypasses Grafana login screen)
|
||||||
GF_AUTH_OAUTH_AUTO_LOGIN = "true"
|
GF_AUTH_OAUTH_AUTO_LOGIN = "true"
|
||||||
# Optionally map user groups to Grafana roles
|
# Optionally map user groups to Grafana roles
|
||||||
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH = "contains(groups[*], 'Grafana Admins') && 'Admin' || contains(groups[*], 'Grafana Editors') && 'Editor' || 'Viewer'"
|
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH = "contains(groups[*], 'admins') && 'Admin' || contains(groups[*], 'residents') && 'Editor' || 'Viewer'"
|
||||||
GF_AUTH_GENERIC_OAUTH_USE_REFRESH_TOKEN = "true"
|
GF_AUTH_GENERIC_OAUTH_USE_REFRESH_TOKEN = "true"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_EMAIL_ATTRIBUTE_PATH = "email"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_LOGIN_ATTRIBUTE_PATH = "preferred_username"
|
||||||
|
GF_AUTH_GENERIC_OAUTH_NAME_ATTRIBUTE_PATH = "name"
|
||||||
#GF_LOG_LEVEL = "debug"
|
#GF_LOG_LEVEL = "debug"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
services/homepage.hcl
Normal file
50
services/homepage.hcl
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
job "homepage" {
|
||||||
|
datacenters = ["alo"]
|
||||||
|
|
||||||
|
group "app" {
|
||||||
|
network {
|
||||||
|
port "http" { to = 3000 }
|
||||||
|
}
|
||||||
|
|
||||||
|
task "homepage" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "ghcr.io/gethomepage/homepage:latest"
|
||||||
|
ports = [ "http" ]
|
||||||
|
volumes = [
|
||||||
|
"/data/services/homepage:/app/config",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
PUID = 1000
|
||||||
|
PGID = 1000
|
||||||
|
HOMEPAGE_ALLOWED_HOSTS = "homepage.v.paler.net"
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 200
|
||||||
|
memory = 256
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "homepage"
|
||||||
|
port = "http"
|
||||||
|
|
||||||
|
tags = [
|
||||||
|
"traefik.enable=true",
|
||||||
|
"traefik.http.routers.homepage.entryPoints=websecure",
|
||||||
|
"traefik.http.routers.homepage.middlewares=oidc-auth@file",
|
||||||
|
]
|
||||||
|
|
||||||
|
check {
|
||||||
|
type = "http"
|
||||||
|
path = "/"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,7 +38,7 @@ job "jupyter" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.jupyter.entryPoints=websecure",
|
"traefik.http.routers.jupyter.entryPoints=websecure",
|
||||||
"traefik.http.routers.jupyter.middlewares=authentik@file",
|
"traefik.http.routers.jupyter.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ EOH
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.loki.entryPoints=websecure",
|
"traefik.http.routers.loki.entryPoints=websecure",
|
||||||
"traefik.http.routers.loki.middlewares=authentik@file",
|
"traefik.http.routers.loki.middlewares=oidc-auth@file",
|
||||||
"metrics",
|
"metrics",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ job "maps" {
|
|||||||
to = 80
|
to = 80
|
||||||
}
|
}
|
||||||
port "php" {
|
port "php" {
|
||||||
static = 9001
|
static = 9000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,12 @@ job "media" {
|
|||||||
|
|
||||||
group "servers" {
|
group "servers" {
|
||||||
network {
|
network {
|
||||||
port "radarr" { to = 7878 }
|
port "radarr" { static = 7878 }
|
||||||
port "sonarr" { to = 8989 }
|
port "sonarr" { static = 8989 }
|
||||||
port "bazarr" { to = 6767 }
|
port "bazarr" { to = 6767 }
|
||||||
|
port "prowlarr" { static = 9696 }
|
||||||
|
port "jellyseerr" { static = 5055 }
|
||||||
|
port "flaresolverr" { static = 8191 }
|
||||||
port "pms" { static = 32400 }
|
port "pms" { static = 32400 }
|
||||||
port "qbt_ui" { static = 8080 }
|
port "qbt_ui" { static = 8080 }
|
||||||
port "qbt_torrent" { static = 51413 }
|
port "qbt_torrent" { static = 51413 }
|
||||||
@@ -34,7 +37,7 @@ job "media" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resources {
|
resources {
|
||||||
cpu = 200
|
cpu = 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
service {
|
service {
|
||||||
@@ -44,7 +47,7 @@ job "media" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.radarr.entryPoints=websecure",
|
"traefik.http.routers.radarr.entryPoints=websecure",
|
||||||
"traefik.http.routers.radarr.middlewares=authentik@file",
|
"traefik.http.routers.radarr.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +71,8 @@ job "media" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resources {
|
resources {
|
||||||
cpu = 200
|
cpu = 1000
|
||||||
|
memory = 500
|
||||||
}
|
}
|
||||||
|
|
||||||
service {
|
service {
|
||||||
@@ -78,20 +82,54 @@ job "media" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.sonarr.entryPoints=websecure",
|
"traefik.http.routers.sonarr.entryPoints=websecure",
|
||||||
"traefik.http.routers.sonarr.middlewares=authentik@file",
|
"traefik.http.routers.sonarr.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task "bazarr" {
|
# task "bazarr" {
|
||||||
|
# driver = "docker"
|
||||||
|
#
|
||||||
|
# config {
|
||||||
|
# image = "ghcr.io/hotio/bazarr:latest"
|
||||||
|
# ports = [ "bazarr" ]
|
||||||
|
# volumes = [
|
||||||
|
# "/data/services/media/bazarr:/config",
|
||||||
|
# "/data/media/media:/data/media",
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# env {
|
||||||
|
# PUID = 1000
|
||||||
|
# PGID = 1000
|
||||||
|
# TZ = "Europe/Lisbon"
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# resources {
|
||||||
|
# cpu = 200
|
||||||
|
# memory = 500
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# service {
|
||||||
|
# name = "bazarr"
|
||||||
|
# port = "bazarr"
|
||||||
|
#
|
||||||
|
# tags = [
|
||||||
|
# "traefik.enable=true",
|
||||||
|
# "traefik.http.routers.bazarr.entryPoints=websecure",
|
||||||
|
# "traefik.http.routers.bazarr.middlewares=oidc-auth@file",
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
task "prowlarr" {
|
||||||
driver = "docker"
|
driver = "docker"
|
||||||
|
|
||||||
config {
|
config {
|
||||||
image = "ghcr.io/hotio/bazarr:latest"
|
image = "ghcr.io/hotio/prowlarr:latest"
|
||||||
ports = [ "bazarr" ]
|
ports = [ "prowlarr" ]
|
||||||
volumes = [
|
volumes = [
|
||||||
"/data/services/media/bazarr:/config",
|
"/data/services/media/prowlarr:/config",
|
||||||
"/data/media/media:/data/media",
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,17 +144,93 @@ job "media" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
service {
|
service {
|
||||||
name = "bazarr"
|
name = "prowlarr"
|
||||||
port = "bazarr"
|
port = "prowlarr"
|
||||||
|
|
||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.bazarr.entryPoints=websecure",
|
"traefik.http.routers.prowlarr.entryPoints=websecure",
|
||||||
"traefik.http.routers.bazarr.middlewares=authentik@file",
|
"traefik.http.routers.prowlarr.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task "jellyseerr" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "fallenbagel/jellyseerr:latest"
|
||||||
|
ports = [ "jellyseerr" ]
|
||||||
|
volumes = [
|
||||||
|
"/data/services/media/jellyseerr:/app/config",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
TZ = "Europe/Lisbon"
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 200
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "jellyseerr"
|
||||||
|
port = "jellyseerr"
|
||||||
|
|
||||||
|
tags = [
|
||||||
|
"traefik.enable=true",
|
||||||
|
"traefik.http.routers.jellyseerr.entryPoints=websecure",
|
||||||
|
"traefik.http.routers.jellyseerr.middlewares=oidc-auth@file",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "flaresolverr" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "ghcr.io/flaresolverr/flaresolverr:latest"
|
||||||
|
ports = [ "flaresolverr" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
LOG_LEVEL = "info"
|
||||||
|
TZ = "Europe/Lisbon"
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 500
|
||||||
|
memory = 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "flaresolverr"
|
||||||
|
port = "flaresolverr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "recyclarr" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "ghcr.io/recyclarr/recyclarr:latest"
|
||||||
|
volumes = [
|
||||||
|
"/data/services/media/recyclarr:/config",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
TZ = "Europe/Lisbon"
|
||||||
|
CRON_SCHEDULE = "0 0 * * *" # Daily at midnight
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 100
|
||||||
|
memory = 256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
task "plex" {
|
task "plex" {
|
||||||
driver = "docker"
|
driver = "docker"
|
||||||
|
|
||||||
@@ -138,7 +252,7 @@ job "media" {
|
|||||||
|
|
||||||
resources {
|
resources {
|
||||||
cpu = 2000
|
cpu = 2000
|
||||||
memory = 1000
|
memory = 2000
|
||||||
}
|
}
|
||||||
|
|
||||||
service {
|
service {
|
||||||
@@ -148,7 +262,7 @@ job "media" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.plex.entryPoints=websecure",
|
"traefik.http.routers.plex.entryPoints=websecure",
|
||||||
"traefik.http.routers.plex.middlewares=authentik@file",
|
"traefik.http.routers.plex.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,7 +291,7 @@ job "media" {
|
|||||||
|
|
||||||
resources {
|
resources {
|
||||||
cpu = 2000
|
cpu = 2000
|
||||||
memory = 1000
|
memory = 1500
|
||||||
}
|
}
|
||||||
|
|
||||||
service {
|
service {
|
||||||
@@ -187,7 +301,7 @@ job "media" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.torrent.entryPoints=websecure",
|
"traefik.http.routers.torrent.entryPoints=websecure",
|
||||||
"traefik.http.routers.torrent.middlewares=authentik@file",
|
"traefik.http.routers.torrent.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ job "netbox" {
|
|||||||
REMOTE_AUTH_ENABLED = "true"
|
REMOTE_AUTH_ENABLED = "true"
|
||||||
REMOTE_AUTH_BACKEND = "social_core.backends.open_id_connect.OpenIdConnectAuth"
|
REMOTE_AUTH_BACKEND = "social_core.backends.open_id_connect.OpenIdConnectAuth"
|
||||||
|
|
||||||
SOCIAL_AUTH_OIDC_ENDPOINT = "https://authentik.v.paler.net/application/o/netbox/"
|
SOCIAL_AUTH_OIDC_ENDPOINT = "https://pocket-id.v.paler.net/"
|
||||||
SOCIAL_AUTH_OIDC_KEY = "XiPhZmWy2mp8hQyHLXCwk7njRNPSLTp2vSHhvWYI"
|
SOCIAL_AUTH_OIDC_KEY = "6ce1f1bb-d5e8-4ba5-b136-2643dc8bcbcf"
|
||||||
SOCIAL_AUTH_OIDC_SECRET = "Kkop2dStx0gN52V1LfPnoxcaemuur6zMsvRnqpWSDe2qSngJVcqWfvFXaNeTbdURRB6TPwjlaNJ5BXR2ChcSmokWGTGargu84Ox1D6M2zXTsfLFj9B149Mhblos4mJL1"
|
SOCIAL_AUTH_OIDC_SECRET = "Af7sJvCn9BuijoJXrB5aWv6fTmEqLCAf"
|
||||||
LOGOUT_REDIRECT_URL = "https://authentik.v.paler.net/application/o/netbox/end-session/"
|
LOGOUT_REDIRECT_URL = "https://pocket-id.v.paler.net/logout"
|
||||||
}
|
}
|
||||||
|
|
||||||
resources {
|
resources {
|
||||||
|
|||||||
39
services/ollama.hcl
Normal file
39
services/ollama.hcl
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
job "ollama" {
|
||||||
|
datacenters = ["alo"]
|
||||||
|
type = "service"
|
||||||
|
|
||||||
|
group "ollama" {
|
||||||
|
network {
|
||||||
|
port "http" {
|
||||||
|
static = 11434
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "server" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "ollama/ollama:latest"
|
||||||
|
ports = ["http"]
|
||||||
|
volumes = ["/data/services/ollama:/root/.ollama"]
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "ollama"
|
||||||
|
port = "http"
|
||||||
|
|
||||||
|
check {
|
||||||
|
type = "http"
|
||||||
|
path = "/"
|
||||||
|
interval = "30s"
|
||||||
|
timeout = "5s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 8000
|
||||||
|
memory = 2048
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
services/pocket-id.hcl
Normal file
51
services/pocket-id.hcl
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
job "pocket-id" {
|
||||||
|
datacenters = ["alo"]
|
||||||
|
|
||||||
|
group "app" {
|
||||||
|
network {
|
||||||
|
port "http" {
|
||||||
|
to = 1411
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task "server" {
|
||||||
|
driver = "docker"
|
||||||
|
|
||||||
|
config {
|
||||||
|
image = "ghcr.io/pocket-id/pocket-id:v1"
|
||||||
|
ports = ["http"]
|
||||||
|
volumes = [
|
||||||
|
"/data/services/pocket-id:/app/data",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
APP_URL = "https://pocket-id.v.paler.net"
|
||||||
|
TRUST_PROXY = "true"
|
||||||
|
MAXMIND_LICENSE_KEY = "${var.maxmind_license_key}"
|
||||||
|
PUID = "1000"
|
||||||
|
PGID = "1000"
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
cpu = 500
|
||||||
|
memory = 512
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "pocket-id"
|
||||||
|
port = "http"
|
||||||
|
|
||||||
|
tags = [
|
||||||
|
"traefik.enable=true",
|
||||||
|
"traefik.http.routers.pocket-id.entryPoints=websecure",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "maxmind_license_key" {
|
||||||
|
type = string
|
||||||
|
default = "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"
|
||||||
|
}
|
||||||
@@ -91,15 +91,15 @@ job "postgres" {
|
|||||||
PGADMIN_CONFIG_OAUTH2_AUTO_CREATE_USER = "True"
|
PGADMIN_CONFIG_OAUTH2_AUTO_CREATE_USER = "True"
|
||||||
PGADMIN_CONFIG_OAUTH2_CONFIG = <<EOH
|
PGADMIN_CONFIG_OAUTH2_CONFIG = <<EOH
|
||||||
[{
|
[{
|
||||||
'OAUTH2_NAME' : 'authentik',
|
'OAUTH2_NAME' : 'pocket-id',
|
||||||
'OAUTH2_DISPLAY_NAME' : 'SSO',
|
'OAUTH2_DISPLAY_NAME' : 'SSO',
|
||||||
'OAUTH2_CLIENT_ID' : 'o4p3B03ayTQ2kpwmM7GswbcfO78JHCTdoZqKJEut',
|
'OAUTH2_CLIENT_ID' : '180133da-1bd7-4cde-9c18-2f277e962dab',
|
||||||
'OAUTH2_CLIENT_SECRET' : '7UYHONOCVdjpRMK9Ojwds0qPPpxCiztbIRhK7FJ2IFBpUgN6tnmpEjlkPYimiGKfaHLhy4XE7kQm7Et1Jm0hgyia0iB1VIlp623ckppbwkM6IfpTE1LfEmTMtPrxSngx',
|
'OAUTH2_CLIENT_SECRET' : 'ELYNAfiWSGYJQUXUDOdpm7tTtyLbrs4E',
|
||||||
'OAUTH2_TOKEN_URL' : 'https://authentik.v.paler.net/application/o/token/',
|
'OAUTH2_TOKEN_URL' : 'https://pocket-id.v.paler.net/api/oidc/token',
|
||||||
'OAUTH2_AUTHORIZATION_URL' : 'https://authentik.v.paler.net/application/o/authorize/',
|
'OAUTH2_AUTHORIZATION_URL' : 'https://pocket-id.v.paler.net/authorize',
|
||||||
'OAUTH2_API_BASE_URL' : 'https://authentik.v.paler.net/',
|
'OAUTH2_API_BASE_URL' : 'https://pocket-id.v.paler.net/',
|
||||||
'OAUTH2_USERINFO_ENDPOINT' : 'https://authentik.v.paler.net/application/o/userinfo/',
|
'OAUTH2_USERINFO_ENDPOINT' : 'https://pocket-id.v.paler.net/api/oidc/userinfo',
|
||||||
'OAUTH2_SERVER_METADATA_URL' : 'https://authentik.v.paler.net/application/o/pgadmin/.well-known/openid-configuration',
|
'OAUTH2_SERVER_METADATA_URL' : 'https://pocket-id.v.paler.net/.well-known/openid-configuration',
|
||||||
'OAUTH2_SCOPE' : 'openid email profile',
|
'OAUTH2_SCOPE' : 'openid email profile',
|
||||||
'OAUTH2_ICON' : 'fa-database',
|
'OAUTH2_ICON' : 'fa-database',
|
||||||
'OAUTH2_BUTTON_COLOR' : '#00ff00'
|
'OAUTH2_BUTTON_COLOR' : '#00ff00'
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ job "prometheus" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.prometheus.entryPoints=websecure",
|
"traefik.http.routers.prometheus.entryPoints=websecure",
|
||||||
"traefik.http.routers.prometheus.middlewares=authentik@file",
|
"traefik.http.routers.prometheus.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
|
|
||||||
check {
|
check {
|
||||||
|
|||||||
82
services/tiddlywiki-mcp.hcl
Normal file
82
services/tiddlywiki-mcp.hcl
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
job "tiddlywiki-mcp" {
|
||||||
|
datacenters = ["alo"]
|
||||||
|
|
||||||
|
group "captainslog" {
|
||||||
|
network {
|
||||||
|
port "http" {
|
||||||
|
static = 3500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
volume "services" {
|
||||||
|
type = "host"
|
||||||
|
source = "services"
|
||||||
|
read_only = false
|
||||||
|
}
|
||||||
|
|
||||||
|
volume "nix-store" {
|
||||||
|
type = "host"
|
||||||
|
source = "nix-store"
|
||||||
|
read_only = true
|
||||||
|
}
|
||||||
|
|
||||||
|
volume "sw" {
|
||||||
|
type = "host"
|
||||||
|
source = "sw"
|
||||||
|
read_only = true
|
||||||
|
}
|
||||||
|
|
||||||
|
task "mcp-server" {
|
||||||
|
driver = "exec"
|
||||||
|
|
||||||
|
config {
|
||||||
|
command = "/sw/bin/node"
|
||||||
|
args = ["/data/services/tiddlywiki-mcp/dist/index.js"]
|
||||||
|
}
|
||||||
|
|
||||||
|
env {
|
||||||
|
MCP_TRANSPORT = "http"
|
||||||
|
MCP_PORT = "${NOMAD_PORT_http}"
|
||||||
|
CONSUL_SERVICE = "captainslog.service.consul"
|
||||||
|
AUTH_HEADER = "X-Oidc-Username"
|
||||||
|
AUTH_USER = "claude-code"
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_mount {
|
||||||
|
volume = "services"
|
||||||
|
destination = "/data/services"
|
||||||
|
read_only = false
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_mount {
|
||||||
|
volume = "nix-store"
|
||||||
|
destination = "/nix/store"
|
||||||
|
read_only = true
|
||||||
|
}
|
||||||
|
|
||||||
|
volume_mount {
|
||||||
|
volume = "sw"
|
||||||
|
destination = "/sw"
|
||||||
|
read_only = true
|
||||||
|
}
|
||||||
|
|
||||||
|
service {
|
||||||
|
name = "tiddlywiki-mcp-captainslog"
|
||||||
|
port = "http"
|
||||||
|
|
||||||
|
check {
|
||||||
|
type = "http"
|
||||||
|
path = "/health"
|
||||||
|
interval = "10s"
|
||||||
|
timeout = "2s"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resources {
|
||||||
|
memory = 256
|
||||||
|
}
|
||||||
|
|
||||||
|
user = "ppetru"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ job "traefik" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.api.entryPoints=websecure",
|
"traefik.http.routers.api.entryPoints=websecure",
|
||||||
"traefik.http.routers.api.middlewares=authentik@file",
|
"traefik.http.routers.api.middlewares=oidc-auth@file",
|
||||||
"traefik.http.routers.api.rule=Host(`traefik.v.paler.net`)",
|
"traefik.http.routers.api.rule=Host(`traefik.v.paler.net`)",
|
||||||
"traefik.http.routers.api.service=api@internal",
|
"traefik.http.routers.api.service=api@internal",
|
||||||
]
|
]
|
||||||
@@ -63,6 +63,7 @@ job "traefik" {
|
|||||||
volumes = [
|
volumes = [
|
||||||
"local/traefik.yml:/etc/traefik/traefik.yml",
|
"local/traefik.yml:/etc/traefik/traefik.yml",
|
||||||
"/data/services/traefik:/config",
|
"/data/services/traefik:/config",
|
||||||
|
"/data/services/traefik/plugins-storage:/plugins-storage",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,6 +76,12 @@ global:
|
|||||||
#log:
|
#log:
|
||||||
# level: debug
|
# level: debug
|
||||||
|
|
||||||
|
experimental:
|
||||||
|
plugins:
|
||||||
|
traefik-oidc-auth:
|
||||||
|
moduleName: "github.com/sevensolutions/traefik-oidc-auth"
|
||||||
|
version: "v0.16.0"
|
||||||
|
|
||||||
api:
|
api:
|
||||||
dashboard: true
|
dashboard: true
|
||||||
|
|
||||||
@@ -145,7 +152,7 @@ EOH
|
|||||||
}
|
}
|
||||||
|
|
||||||
resources {
|
resources {
|
||||||
cpu = 100
|
cpu = 200
|
||||||
memory = 512
|
memory = 512
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ job "unifi" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.unifi.entryPoints=websecure",
|
"traefik.http.routers.unifi.entryPoints=websecure",
|
||||||
"traefik.http.routers.unifi.middlewares=authentik@file",
|
"traefik.http.routers.unifi.middlewares=oidc-auth@file",
|
||||||
"traefik.http.services.unifi.loadbalancer.server.scheme=https",
|
"traefik.http.services.unifi.loadbalancer.server.scheme=https",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ job "urbit" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.urbit.entryPoints=websecure",
|
"traefik.http.routers.urbit.entryPoints=websecure",
|
||||||
"traefik.http.routers.urbit.middlewares=authentik@file",
|
"traefik.http.routers.urbit.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ EOH
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.webodm.entryPoints=websecure",
|
"traefik.http.routers.webodm.entryPoints=websecure",
|
||||||
"traefik.http.routers.webodm.middlewares=authentik@file",
|
"traefik.http.routers.webodm.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +97,7 @@ EOH
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.clusterodm.entryPoints=websecure",
|
"traefik.http.routers.clusterodm.entryPoints=websecure",
|
||||||
"traefik.http.routers.clusterodm.middlewares=authentik@file",
|
"traefik.http.routers.clusterodm.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ job "whoami" {
|
|||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.whoami.rule=Host(`test.alo.land`)",
|
"traefik.http.routers.whoami.rule=Host(`test.alo.land`)",
|
||||||
"traefik.http.routers.whoami.entryPoints=websecure",
|
"traefik.http.routers.whoami.entryPoints=websecure",
|
||||||
"traefik.http.routers.whoami.middlewares=authentik@file",
|
"traefik.http.routers.whoami.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ job "wiki" {
|
|||||||
"--listen",
|
"--listen",
|
||||||
"host=0.0.0.0",
|
"host=0.0.0.0",
|
||||||
"port=${NOMAD_PORT_captainslog}",
|
"port=${NOMAD_PORT_captainslog}",
|
||||||
"authenticated-user-header=X-authentik-username",
|
"authenticated-user-header=X-Oidc-Username",
|
||||||
"readers=ppetru",
|
"readers=ppetru,claude-code",
|
||||||
"writers=ppetru",
|
"writers=ppetru,claude-code",
|
||||||
"admin=ppetru",
|
"admin=ppetru",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ job "wiki" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.captainslog.entryPoints=websecure",
|
"traefik.http.routers.captainslog.entryPoints=websecure",
|
||||||
"traefik.http.routers.captainslog.middlewares=authentik@file",
|
"traefik.http.routers.captainslog.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ job "wiki" {
|
|||||||
"--listen",
|
"--listen",
|
||||||
"host=0.0.0.0",
|
"host=0.0.0.0",
|
||||||
"port=${NOMAD_PORT_alo}",
|
"port=${NOMAD_PORT_alo}",
|
||||||
"authenticated-user-header=X-authentik-username",
|
"authenticated-user-header=X-Oidc-Username",
|
||||||
"readers=ppetru,ines",
|
"readers=ppetru,ines",
|
||||||
"writers=ppetru,ines",
|
"writers=ppetru,ines",
|
||||||
"admin=ppetru",
|
"admin=ppetru",
|
||||||
@@ -112,7 +112,7 @@ job "wiki" {
|
|||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.alowiki.rule=Host(`wiki.alo.land`)",
|
"traefik.http.routers.alowiki.rule=Host(`wiki.alo.land`)",
|
||||||
"traefik.http.routers.alowiki.entryPoints=websecure",
|
"traefik.http.routers.alowiki.entryPoints=websecure",
|
||||||
"traefik.http.routers.alowiki.middlewares=authentik@file",
|
"traefik.http.routers.alowiki.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ job "wiki" {
|
|||||||
"--listen",
|
"--listen",
|
||||||
"host=0.0.0.0",
|
"host=0.0.0.0",
|
||||||
"port=${NOMAD_PORT_pispace}",
|
"port=${NOMAD_PORT_pispace}",
|
||||||
"authenticated-user-header=X-authentik-username",
|
"authenticated-user-header=X-Oidc-Username",
|
||||||
"readers=ppetru,ines",
|
"readers=ppetru,ines",
|
||||||
"writers=ppetru,ines",
|
"writers=ppetru,ines",
|
||||||
"admin=ppetru",
|
"admin=ppetru",
|
||||||
@@ -160,7 +160,7 @@ job "wiki" {
|
|||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.pispace.rule=Host(`pi.paler.net`)",
|
"traefik.http.routers.pispace.rule=Host(`pi.paler.net`)",
|
||||||
"traefik.http.routers.pispace.entryPoints=websecure",
|
"traefik.http.routers.pispace.entryPoints=websecure",
|
||||||
"traefik.http.routers.pispace.middlewares=authentik@file",
|
"traefik.http.routers.pispace.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ job "wiki" {
|
|||||||
"--listen",
|
"--listen",
|
||||||
"host=0.0.0.0",
|
"host=0.0.0.0",
|
||||||
"port=${NOMAD_PORT_grok}",
|
"port=${NOMAD_PORT_grok}",
|
||||||
"authenticated-user-header=X-authentik-username",
|
"authenticated-user-header=X-Oidc-Username",
|
||||||
"readers=ppetru",
|
"readers=ppetru",
|
||||||
"writers=ppetru",
|
"writers=ppetru",
|
||||||
"admin=ppetru",
|
"admin=ppetru",
|
||||||
@@ -207,7 +207,7 @@ job "wiki" {
|
|||||||
tags = [
|
tags = [
|
||||||
"traefik.enable=true",
|
"traefik.enable=true",
|
||||||
"traefik.http.routers.groktw.entryPoints=websecure",
|
"traefik.http.routers.groktw.entryPoints=websecure",
|
||||||
"traefik.http.routers.groktw.middlewares=authentik@file",
|
"traefik.http.routers.groktw.middlewares=oidc-auth@file",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user