797 lines
23 KiB
Markdown
797 lines
23 KiB
Markdown
# RhemaWave Kiosk Infrastructure — Complete Maintainer Guide
|
|
|
|
## Purpose
|
|
|
|
This document describes the **complete** infrastructure for building, distributing, and deploying the RhemaWave kiosk application on NixOS. It is written so that a new developer can reconstruct the entire system from scratch on a fresh machine.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. Architecture Overview
|
|
2. Repositories
|
|
3. Key Files and Secrets — What Lives Where
|
|
4. Development Machine Setup (From Scratch)
|
|
5. The RhemaWave Flake (Application)
|
|
6. The NixConfig Flake (Kiosk System)
|
|
7. Binary Cache Setup
|
|
8. Caddy Server Configuration
|
|
9. Signing Keys
|
|
10. Sops-Nix Secrets Management
|
|
11. GitHub Access
|
|
12. Building and Publishing a New Release
|
|
13. Deploying a New Kiosk (nixos-anywhere)
|
|
14. Auto-Update System
|
|
15. Testing and Debugging
|
|
16. Common Errors and Solutions
|
|
|
|
---
|
|
|
|
## 1. Architecture Overview
|
|
|
|
```
|
|
┌─────────────────────────────────┐
|
|
│ Developer Machine (P15) │
|
|
│ │
|
|
│ RhemaWave repo NixConfig repo│
|
|
│ (Go application) (NixOS cfg) │
|
|
│ │ │ │
|
|
│ nix build nix flake │
|
|
│ nix store sign update │
|
|
│ nix copy git push │
|
|
│ │ │ │
|
|
└─────────┼───────────────┼───────┘
|
|
│ │
|
|
▼ ▼
|
|
┌─────────────────┐ ┌──────────┐
|
|
│ Web Server │ │ GitHub │
|
|
│ (Caddy) │ │ (private)│
|
|
│ │ │ │
|
|
│ Binary cache: │ │ NixConfig│
|
|
│ repository. │ │ flake │
|
|
│ rhemawavetech │ │ │
|
|
│ .com │ │ RhemaWave│
|
|
│ │ │ flake │
|
|
│ Static files: │ │ │
|
|
│ .narinfo + .nar │ └────┬─────┘
|
|
└────────┬────────┘ │
|
|
│ │
|
|
▼ ▼
|
|
┌─────────────────────────────────┐
|
|
│ Kiosk Machines │
|
|
│ │
|
|
│ systemd timer (every 15min): │
|
|
│ 1. Fetch NixConfig from │
|
|
│ GitHub │
|
|
│ 2. Evaluate flake │
|
|
│ 3. Download RhemaWave binary │
|
|
│ from binary cache │
|
|
│ 4. nixos-rebuild switch │
|
|
│ │
|
|
│ Cage compositor → RhemaWave │
|
|
│ (fullscreen, locked, no TTY │
|
|
│ switching, auto-restart) │
|
|
└─────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Repositories
|
|
|
|
| Repo | URL | Branch | Contents |
|
|
|------|-----|--------|----------|
|
|
| RhemaWave | `github:Rhema-Wave-Technologies/RhemaWave` | `dev` | Go application source, `flake.nix` (package + NixOS module), `nixos/module.nix` |
|
|
| NixConfig | `github:Rhema-Wave-Technologies/NixConfig` | `main` | NixOS kiosk configuration, disk layout, encrypted secrets, sops config |
|
|
|
|
Both repositories are **private**. Access requires a GitHub fine-grained personal access token with read-only Contents permission on both repos.
|
|
|
|
---
|
|
|
|
## 3. Key Files and Secrets — What Lives Where
|
|
|
|
### On the Developer Machine
|
|
|
|
| File | Path | Purpose | Backup? |
|
|
|------|------|---------|---------|
|
|
| Binary cache private key | `~/Keys/nix/cache/rhemawave/cache-priv-key.pem` | Signs packages for the binary cache | **CRITICAL** — without this, you cannot publish new builds. Back up to encrypted offline storage. |
|
|
| Binary cache public key | `~/Keys/nix/cache/rhemawave/cache-pub-key.pem` | Distributed to all client machines for verification | Can be regenerated from private key |
|
|
| Sops age private key | `~/Keys/nix/sops/age-key.txt` | Encrypts/decrypts secrets in NixConfig | **CRITICAL** — without this, you cannot edit secrets. Back up to encrypted offline storage. |
|
|
| GitHub access token | `~/.config/nix/nix.conf` | Nix uses this to access private GitHub repos | Can be regenerated from GitHub |
|
|
| Sops age key env var | `~/.bashrc` | `SOPS_AGE_KEY_FILE=~/Keys/nix/sops/age-key.txt` | Convention only |
|
|
|
|
### On the Web Server
|
|
|
|
| File | Path | Purpose |
|
|
|------|------|---------|
|
|
| Binary cache files | `/var/lib/nix-cache/` | Static files served by Caddy |
|
|
| `nix-cache-info` | `/var/lib/nix-cache/nix-cache-info` | Metadata file for Nix clients |
|
|
| Caddy config | Caddyfile (location varies) | Serves the cache directory |
|
|
|
|
The server does **not** need any signing keys. It is a dumb static file host.
|
|
|
|
### On Each Kiosk
|
|
|
|
| File | Path | Purpose |
|
|
|------|------|---------|
|
|
| SSH host key (private) | `/etc/ssh/ssh_host_ed25519_key` | Used by sops-nix to decrypt secrets |
|
|
| SSH host key (public) | `/etc/ssh/ssh_host_ed25519_key.pub` | Converted to age key for sops `.sops.yaml` |
|
|
| Decrypted secrets | `/run/secrets/*` | Runtime-only, never persisted to disk |
|
|
|
|
### What to Back Up (Priority Order)
|
|
|
|
1. **`~/Keys/nix/cache/rhemawave/cache-priv-key.pem`** — If lost, you must generate a new key pair and update the public key in every kiosk configuration and redeploy.
|
|
2. **`~/Keys/nix/sops/age-key.txt`** — If lost, you must re-encrypt all secrets with a new key.
|
|
3. **GitHub token** — Easily regenerated, low priority.
|
|
|
|
Store backups on an encrypted USB drive or a password manager's secure notes. Never store these in any Git repository, cloud drive, or unencrypted medium.
|
|
|
|
---
|
|
|
|
## 4. Development Machine Setup (From Scratch)
|
|
|
|
Starting from a fresh NixOS installation on a development machine.
|
|
|
|
### 4.1 NixOS Configuration Prerequisites
|
|
|
|
In your system `configuration.nix`:
|
|
|
|
```nix
|
|
nix.settings = {
|
|
experimental-features = [ "nix-command" "flakes" ];
|
|
trusted-users = [ "root" "yourusername" ];
|
|
substituters = [
|
|
"https://cache.nixos.org"
|
|
"https://repository.rhemawavetech.com"
|
|
];
|
|
trusted-public-keys = [
|
|
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
|
|
"repository.rhemawavetech.com-1:hbaEpYz5jE9SeNgkF2jAgjMtjXzruj7lEk6Lvx9ll40="
|
|
];
|
|
};
|
|
nixpkgs.config.allowUnfree = true;
|
|
```
|
|
|
|
Rebuild: `sudo nixos-rebuild switch`
|
|
|
|
### 4.2 Add the RhemaWave Flake to Your System Config
|
|
|
|
In your system `flake.nix`, add the input and package:
|
|
|
|
```nix
|
|
inputs.rhemawave = {
|
|
url = "github:Rhema-Wave-Technologies/RhemaWave/dev";
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
```
|
|
|
|
Add `rhemawave` to the `outputs` function arguments, then add to a module:
|
|
|
|
```nix
|
|
{
|
|
environment.systemPackages = [
|
|
rhemawave.packages.x86_64-linux.default
|
|
];
|
|
}
|
|
```
|
|
|
|
### 4.3 GitHub Access Token
|
|
|
|
Generate a fine-grained personal access token at `github.com/settings/tokens`:
|
|
- Resource owner: `Rhema-Wave-Technologies`
|
|
- Repository access: Select `NixConfig` and `RhemaWave`
|
|
- Permissions: Contents → Read-only
|
|
- Expiration: Set as appropriate
|
|
|
|
Configure Nix to use it:
|
|
|
|
```bash
|
|
mkdir -p ~/.config/nix
|
|
echo "access-tokens = github.com=YOUR_TOKEN_HERE" > ~/.config/nix/nix.conf
|
|
```
|
|
|
|
Also copy to root (needed for `sudo` operations):
|
|
|
|
```bash
|
|
sudo mkdir -p /root/.config/nix
|
|
sudo cp ~/.config/nix/nix.conf /root/.config/nix/nix.conf
|
|
```
|
|
|
|
### 4.4 Signing Keys
|
|
|
|
If you're taking over from an existing maintainer, obtain:
|
|
- `cache-priv-key.pem` → save to `~/Keys/nix/cache/rhemawave/cache-priv-key.pem`
|
|
- `age-key.txt` → save to `~/Keys/nix/sops/age-key.txt`
|
|
|
|
If starting fresh (new cache):
|
|
|
|
```bash
|
|
mkdir -p ~/Keys/nix/cache/rhemawave
|
|
nix key generate-secret --key-name repository.rhemawavetech.com-1 > ~/Keys/nix/cache/rhemawave/cache-priv-key.pem
|
|
nix key convert-secret-to-public < ~/Keys/nix/cache/rhemawave/cache-priv-key.pem > ~/Keys/nix/cache/rhemawave/cache-pub-key.pem
|
|
```
|
|
|
|
If starting fresh (new sops key):
|
|
|
|
```bash
|
|
mkdir -p ~/Keys/nix/sops
|
|
nix shell nixpkgs#age -c age-keygen -o ~/Keys/nix/sops/age-key.txt
|
|
```
|
|
|
|
Note the public key (starts with `age1...`) — it goes in `.sops.yaml`.
|
|
|
|
### 4.5 Sops Environment Variable
|
|
|
|
Add to `~/.bashrc`:
|
|
|
|
```bash
|
|
echo 'export SOPS_AGE_KEY_FILE=~/Keys/nix/sops/age-key.txt' >> ~/.bashrc
|
|
source ~/.bashrc
|
|
```
|
|
|
|
### 4.6 Clone the Repositories
|
|
|
|
```bash
|
|
mkdir -p ~/Work/RhemaWave
|
|
cd ~/Work/RhemaWave
|
|
git clone git@github.com:Rhema-Wave-Technologies/RhemaWave.git
|
|
git clone git@github.com:Rhema-Wave-Technologies/NixConfig.git
|
|
```
|
|
|
|
### 4.7 Verify Everything Works
|
|
|
|
```bash
|
|
# Test GitHub access
|
|
cd ~/Work/RhemaWave/NixConfig
|
|
nix flake show github:Rhema-Wave-Technologies/NixConfig
|
|
|
|
# Test RhemaWave build
|
|
cd ~/Work/RhemaWave/RhemaWave
|
|
nix build .#default
|
|
|
|
# Test binary runs
|
|
./result/bin/rhemawave
|
|
|
|
# Test secrets decryption
|
|
cd ~/Work/RhemaWave/NixConfig
|
|
SOPS_AGE_KEY_FILE=~/Keys/nix/sops/age-key.txt nix shell nixpkgs#sops -c sops secrets.yaml
|
|
# Should open in editor with plaintext values
|
|
# Close without saving
|
|
```
|
|
|
|
---
|
|
|
|
## 5. The RhemaWave Flake (Application)
|
|
|
|
Located at `~/Work/RhemaWave/RhemaWave/flake.nix`.
|
|
|
|
### Key Points
|
|
|
|
- Uses `buildGoModule` with `vendorHash = null` (vendor directory committed to repo)
|
|
- CGo is enabled (`env.CGO_ENABLED = "1"`)
|
|
- SDL2 mixer/ttf/image flags are set in `preBuild` via `pkg-config`
|
|
- The `share/` directory is copied to `$out/share` in `postInstall`
|
|
- License is set to `unfree` — consumers must set `allowUnfreePredicate`
|
|
- Exports `nixosModules.default` (the kiosk module) alongside per-system packages and dev shells
|
|
|
|
### Flake Outputs
|
|
|
|
| Output | Description |
|
|
|--------|-------------|
|
|
| `packages.<system>.default` | The RhemaWave binary |
|
|
| `devShells.<system>.default` | Development shell with Go + SDL2 deps |
|
|
| `nixosModules.default` | NixOS module for kiosk configuration (greetd, cage, PipeWire, polkit) |
|
|
|
|
### The NixOS Module (`nixos/module.nix`)
|
|
|
|
Imported via `import ./nixos/module.nix self` — the `self` argument gives the module access to the flake's packages. The module exposes `services.rhemawave.*` options.
|
|
|
|
---
|
|
|
|
## 6. The NixConfig Flake (Kiosk System)
|
|
|
|
Located at `~/Work/RhemaWave/NixConfig/flake.nix`.
|
|
|
|
### Flake Inputs
|
|
|
|
```nix
|
|
nixpkgs → github:NixOS/nixpkgs/nixpkgs-unstable
|
|
disko → github:nix-community/disko
|
|
nixos-facter → github:numtide/nixos-facter-modules
|
|
rhemawave → github:Rhema-Wave-Technologies/RhemaWave/dev
|
|
sops-nix → github:Mic92/sops-nix
|
|
```
|
|
|
|
All inputs follow `nixpkgs` to ensure a single nixpkgs version.
|
|
|
|
### System Configuration Modules
|
|
|
|
The NixOS system (`rhemawavekiosk`) loads these modules:
|
|
1. `disko.nixosModules.disko` — disk partitioning
|
|
2. `rhemawave.nixosModules.default` — RhemaWave kiosk module
|
|
3. `sops-nix.nixosModules.sops` — secrets management
|
|
4. `./configuration.nix` — main system config
|
|
5. Hardware facter report
|
|
6. Inline module adding `rhemawave.packages.x86_64-linux.default` to `environment.systemPackages`
|
|
|
|
---
|
|
|
|
## 7. Binary Cache Setup
|
|
|
|
### What It Is
|
|
|
|
A Nix binary cache is a static HTTP file server with a specific directory structure. When a NixOS machine needs a package, it checks each configured cache by making HTTP GET requests for `.narinfo` files. If found and the signature is valid, it downloads the pre-built `.nar.xz` archive instead of building from source.
|
|
|
|
### Directory Structure
|
|
|
|
```
|
|
/var/lib/nix-cache/
|
|
├── nix-cache-info # Cache metadata
|
|
├── fv5iinvsldz9l2s8ikm0mw8ykhriad1g.narinfo # Package metadata + signature
|
|
├── nar/
|
|
│ └── 1j7d9cif4xjq7i5rw5dmivxyninh7z1cm7zvdknsp8vjd9rjmzkc.nar.xz # Compressed package
|
|
└── ... (more .narinfo and .nar.xz files)
|
|
```
|
|
|
|
### nix-cache-info
|
|
|
|
```
|
|
StoreDir: /nix/store
|
|
WantMassQuery: 1
|
|
Priority: 40
|
|
```
|
|
|
|
This file must exist at the root. `Priority: 40` means this cache is checked after the official NixOS cache (priority 30).
|
|
|
|
### Creating the Cache (One-Time)
|
|
|
|
If setting up a new cache server:
|
|
|
|
```bash
|
|
# On the server
|
|
sudo mkdir -p /var/lib/nix-cache
|
|
cat > /var/lib/nix-cache/nix-cache-info <<EOF
|
|
StoreDir: /nix/store
|
|
WantMassQuery: 1
|
|
Priority: 40
|
|
EOF
|
|
```
|
|
|
|
Then configure Caddy (see section 8).
|
|
|
|
---
|
|
|
|
## 8. Caddy Server Configuration
|
|
|
|
The web server at `repository.rhemawavetech.com` runs Caddy with a `file_server` directive pointing at the cache directory.
|
|
|
|
### Caddyfile
|
|
|
|
```caddyfile
|
|
repository.rhemawavetech.com {
|
|
root * /var/lib/nix-cache
|
|
file_server browse
|
|
}
|
|
```
|
|
|
|
The `browse` directive is optional (useful for debugging). Caddy handles TLS automatically via Let's Encrypt.
|
|
|
|
### Verification
|
|
|
|
```bash
|
|
curl https://repository.rhemawavetech.com/nix-cache-info
|
|
```
|
|
|
|
Should return the three-line metadata file.
|
|
|
|
---
|
|
|
|
## 9. Signing Keys
|
|
|
|
### How Signing Works
|
|
|
|
1. The developer builds a package with `nix build`
|
|
2. The store path is signed with the private key: `nix store sign --key-file ...`
|
|
3. The signed package is exported to cache format: `nix copy --to file:// ...`
|
|
4. The `.narinfo` file contains a `Sig:` line with the key name and signature
|
|
5. Client machines verify the signature against the public key in `trusted-public-keys`
|
|
|
|
### Key Name
|
|
|
|
The key name `repository.rhemawavetech.com-1` is embedded in both the key files and the `.narinfo` signatures. If you generate new keys, use the same naming convention with an incremented number (e.g., `-2`).
|
|
|
|
### Generating New Keys
|
|
|
|
```bash
|
|
nix key generate-secret --key-name repository.rhemawavetech.com-1 > cache-priv-key.pem
|
|
nix key convert-secret-to-public < cache-priv-key.pem > cache-pub-key.pem
|
|
```
|
|
|
|
### Deriving Public Key from Private Key
|
|
|
|
```bash
|
|
nix key convert-secret-to-public < ~/Keys/nix/cache/rhemawave/cache-priv-key.pem
|
|
```
|
|
|
|
This outputs the public key string. It should match what's in every client's `trusted-public-keys`.
|
|
|
|
### Current Public Key
|
|
|
|
```
|
|
repository.rhemawavetech.com-1:hbaEpYz5jE9SeNgkF2jAgjMtjXzruj7lEk6Lvx9ll40=
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Sops-Nix Secrets Management
|
|
|
|
### How It Works
|
|
|
|
1. Secrets are encrypted in `secrets.yaml` using age public keys
|
|
2. `.sops.yaml` defines which keys can encrypt/decrypt
|
|
3. Each kiosk's SSH host key is converted to an age key for decryption
|
|
4. On activation, sops-nix decrypts secrets and places them at `/run/secrets/<name>`
|
|
|
|
### .sops.yaml
|
|
|
|
```yaml
|
|
keys:
|
|
- &admin age1ptpn9zee8x7vjaaktx9dv65vysdjfmmgtj96wc3l49vd8g8huy6syk8l26
|
|
- &kiosk-dev age1nmn0r66hl24wrz73q5htt0r90vfse9dvyjwae2evqwrealfgycfsy3apmy
|
|
creation_rules:
|
|
- path_regex: secrets\.yaml$
|
|
key_groups:
|
|
- age:
|
|
- *admin
|
|
- *kiosk-dev
|
|
```
|
|
|
|
### Adding a New Kiosk
|
|
|
|
1. Get the kiosk's SSH host public key:
|
|
```bash
|
|
ssh root@KIOSK_IP "cat /etc/ssh/ssh_host_ed25519_key.pub"
|
|
```
|
|
|
|
2. Convert to age key:
|
|
```bash
|
|
nix shell nixpkgs#ssh-to-age -c ssh-to-age < <(ssh root@KIOSK_IP "cat /etc/ssh/ssh_host_ed25519_key.pub")
|
|
```
|
|
|
|
3. Add the age key to `.sops.yaml` under `keys:` with a descriptive anchor (e.g., `&kiosk-prod-001`)
|
|
|
|
4. Add the anchor reference to the creation rule's age list
|
|
|
|
5. Re-encrypt secrets with the new key:
|
|
```bash
|
|
SOPS_AGE_KEY_FILE=~/Keys/nix/sops/age-key.txt nix shell nixpkgs#sops -c sops updatekeys secrets.yaml
|
|
```
|
|
|
|
6. Commit and push `.sops.yaml` and `secrets.yaml`
|
|
|
|
### Editing Secrets
|
|
|
|
```bash
|
|
cd ~/Work/RhemaWave/NixConfig
|
|
SOPS_AGE_KEY_FILE=~/Keys/nix/sops/age-key.txt nix shell nixpkgs#sops -c sops secrets.yaml
|
|
```
|
|
|
|
The file opens in your editor with plaintext values. Edit, save, close — sops re-encrypts automatically.
|
|
|
|
### Secret Format for github-token
|
|
|
|
The `github-token` secret must contain the full nix.conf line (because it's included via `!include`):
|
|
|
|
```yaml
|
|
github-token: "access-tokens = github.com=ghp_yourtokenhere"
|
|
```
|
|
|
|
---
|
|
|
|
## 11. GitHub Access
|
|
|
|
### Developer Machine
|
|
|
|
The token is stored in `~/.config/nix/nix.conf`:
|
|
|
|
```
|
|
access-tokens = github.com=YOUR_TOKEN_HERE
|
|
```
|
|
|
|
Also needs to be in `/root/.config/nix/nix.conf` for `sudo` operations.
|
|
|
|
Flake URLs use the `github:` scheme (not `git+https://`), which reads the `access-tokens` setting.
|
|
|
|
### Kiosk Machines
|
|
|
|
The token is managed via sops-nix and included in `nix.conf` via `!include /run/secrets/github-token`.
|
|
|
|
### Token Scope
|
|
|
|
Fine-grained personal access token:
|
|
- Resource owner: `Rhema-Wave-Technologies`
|
|
- Repositories: `NixConfig`, `RhemaWave`
|
|
- Permissions: Contents → Read-only
|
|
|
|
---
|
|
|
|
## 12. Building and Publishing a New Release
|
|
|
|
Complete procedure, every command, in order. All commands run on your development machine.
|
|
|
|
### Step 1: Commit Application Changes
|
|
|
|
```bash
|
|
cd ~/Work/RhemaWave/RhemaWave
|
|
|
|
# If go.mod/go.sum changed:
|
|
nix shell nixpkgs#go -c go mod vendor
|
|
git add vendor/
|
|
|
|
git add -A
|
|
git commit -m "your changes"
|
|
git push origin dev
|
|
```
|
|
|
|
### Step 2: Build
|
|
|
|
```bash
|
|
nix build .#default
|
|
```
|
|
|
|
### Step 3: Sign
|
|
|
|
```bash
|
|
nix store sign --key-file ~/Keys/nix/cache/rhemawave/cache-priv-key.pem $(nix path-info ./result)
|
|
```
|
|
|
|
### Step 4: Export to Cache Format
|
|
|
|
```bash
|
|
rm -rf /tmp/nix-cache
|
|
nix copy --to file:///tmp/nix-cache ./result --secret-key-files ~/Keys/nix/cache/rhemawave/cache-priv-key.pem
|
|
```
|
|
|
|
### Step 5: Verify Signature
|
|
|
|
```bash
|
|
cat /tmp/nix-cache/*.narinfo | grep Sig
|
|
```
|
|
|
|
Must show `Sig: repository.rhemawavetech.com-1:...`
|
|
|
|
### Step 6: Upload to Server
|
|
|
|
```bash
|
|
rsync -av /tmp/nix-cache/ YOUR_USER@your-server:/var/lib/nix-cache/
|
|
```
|
|
|
|
### Step 7: Bump NixConfig
|
|
|
|
```bash
|
|
cd ~/Work/RhemaWave/NixConfig
|
|
nix flake update rhemawave
|
|
git add flake.lock
|
|
git commit -m "bump rhemawave"
|
|
git push
|
|
```
|
|
|
|
### Step 8: Wait
|
|
|
|
Kiosks pick up the update within 15 minutes via the auto-update timer.
|
|
|
|
---
|
|
|
|
## 13. Deploying a New Kiosk (nixos-anywhere)
|
|
|
|
### Prerequisites
|
|
|
|
- Target machine booted from NixOS installer USB
|
|
- SSH access to the target as root
|
|
- Target's IP address known
|
|
|
|
### Procedure
|
|
|
|
From your development machine:
|
|
|
|
```bash
|
|
cd ~/Work/RhemaWave/NixConfig
|
|
|
|
# Deploy
|
|
nix run github:nix-community/nixos-anywhere -- --flake .#rhemawavekiosk root@TARGET_IP
|
|
```
|
|
|
|
This:
|
|
1. kexec's into the NixOS installer on the target
|
|
2. Partitions the disk according to `disk-config.nix`
|
|
3. Installs NixOS with the full kiosk configuration
|
|
4. Reboots
|
|
|
|
**Note:** Uses the local flake (`.#`) so it can access local files and secrets. The `--flake` path must be the NixConfig directory.
|
|
|
|
### After Deployment
|
|
|
|
1. Get the kiosk's age key (see section 10, "Adding a New Kiosk")
|
|
2. Add it to `.sops.yaml` and re-encrypt secrets
|
|
3. Push changes
|
|
4. The kiosk will pick up the updated secrets on its next auto-update cycle
|
|
|
|
### If nixos-rebuild --target-host Fails with Bootloader Errors
|
|
|
|
Use the manual three-step deploy instead:
|
|
|
|
```bash
|
|
nix build .#nixosConfigurations.rhemawavekiosk.config.system.build.toplevel
|
|
nix copy --to ssh://root@TARGET_IP ./result
|
|
ssh root@TARGET_IP "$(readlink -f ./result)/bin/switch-to-configuration switch"
|
|
```
|
|
|
|
---
|
|
|
|
## 14. Auto-Update System
|
|
|
|
### How It Works
|
|
|
|
Each kiosk runs a systemd timer (`kiosk-auto-update.timer`) that fires every 15 minutes. The associated service runs:
|
|
|
|
```bash
|
|
nixos-rebuild switch --flake github:Rhema-Wave-Technologies/NixConfig#rhemawavekiosk
|
|
```
|
|
|
|
This:
|
|
1. Fetches the latest NixConfig flake from GitHub (using the encrypted GitHub token)
|
|
2. Evaluates the configuration (including the pinned RhemaWave version from `flake.lock`)
|
|
3. Checks the binary cache for pre-built packages
|
|
4. Downloads any new packages
|
|
5. Switches to the new configuration
|
|
|
|
### What Triggers an Update
|
|
|
|
An update is triggered when either:
|
|
- `flake.lock` changes (new RhemaWave version pinned)
|
|
- `configuration.nix` or other NixConfig files change
|
|
- Any flake input is updated
|
|
|
|
If nothing has changed, `nixos-rebuild` is a no-op.
|
|
|
|
### Monitoring
|
|
|
|
```bash
|
|
# Check timer status
|
|
ssh root@KIOSK_IP "systemctl status kiosk-auto-update.timer"
|
|
|
|
# Check last update result
|
|
ssh root@KIOSK_IP "systemctl status kiosk-auto-update.service"
|
|
|
|
# Full update logs
|
|
ssh root@KIOSK_IP "journalctl -u kiosk-auto-update -n 100"
|
|
```
|
|
|
|
### Force Immediate Update
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP "systemctl start kiosk-auto-update"
|
|
```
|
|
|
|
---
|
|
|
|
## 15. Testing and Debugging
|
|
|
|
### SSH into a Running Kiosk
|
|
|
|
Even with the kiosk locked down (cage compositor, single TTY), SSH always works:
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP
|
|
```
|
|
|
|
### Check What's Running
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP "systemctl status greetd"
|
|
ssh root@KIOSK_IP "systemctl status kiosk-auto-update.timer"
|
|
ssh root@KIOSK_IP "ls -la /run/secrets/"
|
|
ssh root@KIOSK_IP "cat /run/secrets/wifi-psk" # verify decryption
|
|
```
|
|
|
|
### Check Binary Cache Connectivity
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP "curl -s https://repository.rhemawavetech.com/nix-cache-info"
|
|
```
|
|
|
|
### Check GitHub Connectivity
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP "cat /etc/nix/nix.conf | grep access-tokens"
|
|
```
|
|
|
|
### Restart the Kiosk Application
|
|
|
|
If the application crashes or you want to restart it without a full reboot:
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP "systemctl restart greetd"
|
|
```
|
|
|
|
greetd will restart, auto-login the kiosk user, and re-launch rhemawave in cage.
|
|
|
|
### View Application Logs
|
|
|
|
```bash
|
|
ssh root@KIOSK_IP "journalctl -u greetd -n 100"
|
|
```
|
|
|
|
### Test a Configuration Change Without Pushing
|
|
|
|
Build and deploy directly from your development machine:
|
|
|
|
```bash
|
|
cd ~/Work/RhemaWave/NixConfig
|
|
nix build .#nixosConfigurations.rhemawavekiosk.config.system.build.toplevel
|
|
nix copy --to ssh://root@KIOSK_IP ./result
|
|
ssh root@KIOSK_IP "$(readlink -f ./result)/bin/switch-to-configuration switch"
|
|
```
|
|
|
|
---
|
|
|
|
## 16. Common Errors and Solutions
|
|
|
|
### `env attribute set cannot contain any attributes passed to derivation`
|
|
|
|
**Cause:** `CGO_ENABLED` set as both a top-level attribute and in `env`.
|
|
**Fix:** Use only `env.CGO_ENABLED = "1";` in the `buildGoModule` block.
|
|
|
|
### `vendor/modules.txt` inconsistency
|
|
|
|
**Cause:** `go.mod` changed but `vendor/` wasn't updated.
|
|
**Fix:** Run `nix shell nixpkgs#go -c go mod vendor`, then `git add vendor/` and commit.
|
|
|
|
### `unfree license, refusing to evaluate`
|
|
|
|
**Cause:** Missing `allowUnfreePredicate` in the nixpkgs config.
|
|
**Fix:** Add `config.allowUnfreePredicate = pkg: (nixpkgs.lib.getName pkg) == "rhemawave";` to the `pkgs` import.
|
|
|
|
### `warning: ignoring the client-specified setting 'secret-key-files'`
|
|
|
|
**Cause:** Your user isn't in `trusted-users`.
|
|
**Fix:** Add your username to `nix.settings.trusted-users` and rebuild your NixOS system.
|
|
|
|
### `invalid character in Base64 string`
|
|
|
|
**Cause:** The `trusted-public-keys` value is malformed — likely doubled key name or invisible characters.
|
|
**Fix:** Regenerate the public key: `nix key convert-secret-to-public < cache-priv-key.pem` and paste it fresh into the config.
|
|
|
|
### `attribute 'nixosModules' missing`
|
|
|
|
**Cause:** The `flake.lock` points to an old RhemaWave commit that doesn't export `nixosModules`.
|
|
**Fix:** Run `nix flake update rhemawave` in the NixConfig directory.
|
|
|
|
### `path '/home/...' is forbidden in pure evaluation mode`
|
|
|
|
**Cause:** Using absolute paths (like `builtins.readFile /home/...`) in a flake. Flakes evaluate in pure mode.
|
|
**Fix:** Use relative paths (`./file.txt`) or manage secrets with sops-nix.
|
|
|
|
### `access to absolute path '/home' is forbidden`
|
|
|
|
**Cause:** Same as above — `readFile` with an absolute path.
|
|
**Fix:** Use sops-nix for secrets or deploy with the local flake (`.#`) instead of `github:`.
|
|
|
|
### Bootloader errors during remote `nixos-rebuild --target-host`
|
|
|
|
**Cause:** GRUB can't detect the disk layout properly over SSH.
|
|
**Fix:** Use the three-step manual deploy: `nix build` → `nix copy --to ssh://` → `switch-to-configuration switch`.
|
|
|
|
### SSH host key changed warning
|
|
|
|
**Cause:** After reinstalling a kiosk, its SSH host key changes.
|
|
**Fix:** `ssh-keygen -R KIOSK_IP` to remove the old key, then reconnect.
|
|
|
|
### Auto-update not working on kiosk
|
|
|
|
**Check:**
|
|
1. Timer is active: `systemctl status kiosk-auto-update.timer`
|
|
2. Service logs: `journalctl -u kiosk-auto-update -n 50`
|
|
3. GitHub token is decrypted: `cat /etc/nix/nix.conf | grep access-tokens`
|
|
4. Network connectivity: `curl https://github.com`
|
|
5. Cache connectivity: `curl https://repository.rhemawavetech.com/nix-cache-info`
|