Compare commits

...

3 commits

Author SHA1 Message Date
steffen
c141e22feb updated digingest 2026-03-14 15:37:09 +01:00
steffen
c2db28eb29 rewrite AGENTS.md: comprehensive agent guidelines
Rewritten from scratch with accurate project state:
- Correct deployment strategy (Comin, not deploy-rs)
- All 4 apps documented (create, deploy, install, rebuild)
- Module pattern with inherit and assertions
- Host service file pattern with constants usage
- lib.utils helpers documented
- Secret path naming convention
- Complete directory structure with current file layout
- Verification checklist including English docs requirement
2026-03-14 15:36:18 +01:00
steffen
a0da5be8fc translate all docs to English
Translate 8 documentation files from German to English:
- docs/index.md (complete)
- docs/getting-started/first-install.md (complete)
- docs/getting-started/new-client.md (complete)
- docs/getting-started/reinstall.md (complete)
- docs/getting-started/sd-image.md (complete)
- docs/deployment/dns.md (PTR, Hetzner, checklist sections)
- docs/services/tailscale.md (code comments)
- docs/services/forgejo.md (placeholder names)
2026-03-14 15:31:50 +01:00
10 changed files with 1681 additions and 1438 deletions

231
AGENTS.md
View file

@ -2,37 +2,33 @@
## Project Overview ## Project Overview
This repository contains a NixOS configuration managed with Nix Flakes. It defines: NixOS infrastructure managed with Nix Flakes. Two hosts, reusable modules, SOPS secrets, Comin auto-deployment.
- **Hosts**: `cryodev-main` (x86_64 server), `cryodev-pi` (aarch64 Raspberry Pi)
- **Hosts**: `cryodev-main` (x86_64 server), `cryodev-pi` (aarch64 Raspberry Pi 4)
- **Modules**: Reusable NixOS modules in `modules/nixos/` - **Modules**: Reusable NixOS modules in `modules/nixos/`
- **Packages**: Custom packages in `pkgs/` - **Apps**: `create`, `deploy`, `install`, `rebuild` in `apps/`
- **Templates**: `raspberry-pi`, `generic-server` for bootstrapping new hosts - **Templates**: `raspberry-pi`, `generic-server` for bootstrapping new hosts
## Build & Development Commands ## Build & Development Commands
### Prerequisites
- **Nix** with Flakes enabled
- **Git**
### Core Commands
```bash ```bash
# Build host configuration # Format code (required before committing, runs nixfmt via pre-commit)
nix fmt
# Run all checks (formatting, package builds, overlay builds)
nix flake check
# Quick evaluation test (faster than full build, use to validate changes)
nix eval .#nixosConfigurations.cryodev-main.config.system.build.toplevel.name
nix eval .#nixosConfigurations.cryodev-pi.config.system.build.toplevel.name
# Full build
nix build .#nixosConfigurations.cryodev-main.config.system.build.toplevel nix build .#nixosConfigurations.cryodev-main.config.system.build.toplevel
nix build .#nixosConfigurations.cryodev-pi.config.system.build.toplevel nix build .#nixosConfigurations.cryodev-pi.config.system.build.toplevel
# Build Raspberry Pi SD image (requires binfmt on x86_64) # Build Raspberry Pi SD image (requires binfmt on x86_64)
nix build .#nixosConfigurations.cryodev-pi.config.system.build.sdImage nix build .#nixosConfigurations.cryodev-pi.config.system.build.sdImage
# Format code (required before committing)
nix fmt
# Run all checks (lint, formatting)
nix flake check
# Quick evaluation test (faster than full build)
nix eval .#nixosConfigurations.cryodev-main.config.system.build.toplevel.name
# Update flake inputs # Update flake inputs
nix flake update nix flake update
@ -42,176 +38,143 @@ nix develop
### Deployment ### Deployment
```bash Both hosts use **Comin** for automatic pull-based deployment (polls the git repo).
# Deploy all hosts via deploy app (uses deploy.json) Manual deployment is only needed for initial setup or emergencies:
nix run .#deploy
# Deploy a specific host ```bash
# Deploy via deploy app (uses deploy.json, SSH port 2299, asks sudo password)
nix run .#deploy -- -n cryodev-main nix run .#deploy -- -n cryodev-main
# Manual deployment via SSH # Manual deployment via nixos-rebuild
NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#<hostname> \ NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#<hostname> \
--target-host <user>@<ip> --sudo --ask-sudo-password --target-host <user>@<ip> --sudo --ask-sudo-password
``` ```
> **Note:** Both hosts use Comin for automatic pull-based deployment.
> Manual deployment is only needed for the initial setup or emergencies.
### Apps ### Apps
```bash ```bash
# Create a new host from template nix run .#create -- -t generic-server -n <hostname> # Scaffold new host
nix run .#create -- -t generic-server -n <hostname> nix run .#install -- -n <hostname> -r <REPO_URL> # Install from NixOS ISO
nix run .#deploy -- -n <hostname> # Deploy to host
# Install NixOS on a new machine (run from NixOS live ISO) nix run .#rebuild -- nixos # Rebuild locally
nix run .#install -- -n <hostname> -r <REPO_URL>
# Deploy to all configured hosts
nix run .#deploy
# Rebuild NixOS/Home Manager configuration
nix run .#rebuild -- nixos
``` ```
## Code Style & Conventions ## Code Style & Conventions
### Formatting ### Formatting
- **Tool**: `nixfmt` via pre-commit hooks - **Tool**: `nixfmt` via `git-hooks.nix` (pre-commit)
- **Run**: `nix fmt` before every commit - **Run**: `nix fmt` before every commit
- **Indentation**: 2 spaces - **Indentation**: 2 spaces (enforced by formatter)
- **Line length**: 80-100 characters (follow formatter)
### Module Structure ### Naming Conventions
| Type | Convention | Example |
|------|------------|---------|
| Files | kebab-case | `hardware-configuration.nix` |
| NixOS options | camelCase | `services.myService.enable` |
| Let bindings | camelCase | `let myValue = ...;` |
| Hosts | kebab-case | `cryodev-main`, `cryodev-pi` |
| Secret paths | kebab-case with `/` | `forgejo-runner/token` |
### Module Pattern
```nix ```nix
# Standard module pattern { config, lib, ... }:
{ config, lib, pkgs, inputs, outputs, constants, ... }:
let let
cfg = config.services.myService; cfg = config.services.myService;
inherit (lib) mkDefault mkEnableOption mkIf mkOption types;
in in
{ {
options.services.myService = { options.services.myService = {
enable = lib.mkEnableOption "My service"; enable = mkEnableOption "My service";
port = lib.mkOption { port = mkOption {
type = lib.types.port; type = types.port;
default = 8080; default = 8080;
description = "Port to listen on"; description = "Port to listen on";
}; };
}; };
config = lib.mkIf cfg.enable { config = mkIf cfg.enable {
# Implementation here assertions = [
{ assertion = cfg.port > 1024; message = "Port must be > 1024"; }
];
# Implementation
}; };
} }
``` ```
### Naming Conventions ### Key Rules
| Type | Convention | Example |
|------|------------|---------|
| Files | kebab-case | `hardware-configuration.nix` |
| Options | camelCase | `services.myService.enable` |
| Variables | camelCase | `let myValue = ...;` |
| Hosts | kebab-case | `cryodev-main`, `cryodev-pi` |
### Imports - **Use `lib.mkDefault`** for all module defaults (allows host-level overrides)
- **Use `constants.nix`** for domains, IPs, ports -- never hardcode these
- **Use `lib.utils`** helpers: `mkReverseProxyOption`, `mkVirtualHost`, `mkUrl`
- **Secrets via SOPS** only, never plaintext. Reference: `config.sops.secrets."path".path`
- **Imports**: relative paths for local files, `outputs.nixosModules.*` for shared modules, `inputs.*` for external
- **Assertions** for invalid configurations, `warnings` for non-critical issues
- **`lib.inherit`** pattern: extract needed functions in `let` block
### Host Service Files
Each service gets its own file in `hosts/<host>/services/`:
```nix ```nix
# Local modules: relative paths # hosts/cryodev-main/services/myservice.nix
imports = [ ./hardware.nix ./networking.nix ]; { outputs, constants, ... }:
# Shared modules: via outputs
imports = [ outputs.nixosModules.common ];
# External inputs
imports = [ inputs.sops-nix.nixosModules.sops ];
```
### Constants
Use `constants.nix` for domains, IPs, and ports:
```nix
{ constants, ... }:
{ {
services.nginx.virtualHosts."${constants.services.forgejo.fqdn}" = { ... }; imports = [ outputs.nixosModules.myservice ];
services.myservice = {
enable = true;
port = constants.services.myservice.port;
};
services.nginx.virtualHosts."${constants.services.myservice.fqdn}" = {
forceSSL = true;
enableACME = true;
locations."/" = {
proxyPass = "http://127.0.0.1:${toString constants.services.myservice.port}";
};
};
} }
``` ```
### Error Handling ### Special Args Available in Modules
```nix
config = lib.mkIf cfg.enable {
assertions = [
{ assertion = cfg.port > 1024; message = "Port must be > 1024"; }
];
warnings = lib.optional (cfg.debug) "Debug mode enabled!";
};
```
### Option Conflicts - `inputs` -- flake inputs (nixpkgs, sops-nix, comin, headplane, etc.)
Use `lib.mkDefault` for default values that can be overridden: - `outputs` -- this flake's outputs (nixosModules, packages)
```nix - `constants` -- values from `constants.nix` (domain, hosts, services)
services.nginx.enable = lib.mkDefault true; - `lib` -- nixpkgs.lib extended with `lib.utils`
```
## Directory Structure ## Directory Structure
``` ```
. .
├── flake.nix # Entry point, inputs/outputs ├── flake.nix # Entry point, inputs/outputs, mkNixosConfiguration
├── constants.nix # Central config (domains, IPs, ports) ├── constants.nix # Central config (domains, IPs, ports)
├── hosts/ ├── hosts/
│ ├── cryodev-main/ # x86_64 server │ ├── cryodev-main/ # x86_64 server (services/, secrets.yaml, binfmt.nix)
│ │ ├── default.nix # Host entry point │ └── cryodev-pi/ # aarch64 RPi (services/, secrets.yaml, sd-image.nix)
│ │ ├── hardware.nix # Hardware configuration ├── modules/nixos/ # Reusable modules (common, forgejo, headscale, ...)
│ │ ├── services/ # Service configurations ├── users/ # User definitions (steffen, ralph, benjamin)
│ │ └── secrets.yaml # SOPS-encrypted secrets ├── apps/ # Nix apps (create, deploy, install, rebuild)
│ └── cryodev-pi/ # aarch64 Raspberry Pi ├── lib/utils.nix # Helper functions (mkUrl, mkVirtualHost, ...)
├── modules/nixos/ # Reusable modules
│ ├── common/ # Shared base configuration
│ ├── sops/ # Secret management
│ ├── forgejo/ # Git server
│ ├── headscale/ # VPN control server
│ └── ...
├── lib/utils.nix # Helper functions
├── apps/ # Nix apps (rebuild)
├── pkgs/ # Custom packages ├── pkgs/ # Custom packages
├── overlays/ # Nixpkgs overlays ├── overlays/ # Nixpkgs overlays
├── templates/ # Host templates ├── templates/ # Host templates (generic-server, raspberry-pi)
├── scripts/ # Helper scripts (install.sh) ├── deploy.json # Deploy app config (hosts, SSH port)
└── docs/ # Documentation ├── .sops.yaml # SOPS encryption rules (age keys per host)
├── .forgejo/workflows/ # CI pipelines (ci.yml, deploy.yml)
└── docs/ # Documentation (English)
``` ```
## Key Patterns
### Adding a New Raspberry Pi Host
1. Copy template: `cp -r templates/raspberry-pi hosts/new-pi`
2. Update `hosts/new-pi/networking.nix` (hostname)
3. Add to `flake.nix`: `new-pi = mkNixosConfiguration "aarch64-linux" [ ./hosts/new-pi ];`
4. Add to `.forgejo/workflows/build-pi-image.yml` matrix
5. Push → SD image is built automatically
### SOPS Secrets
- Secrets encrypted with age using SSH host keys
- Config in `.sops.yaml`, secrets in `hosts/<host>/secrets.yaml`
- Reference: `config.sops.secrets."path/to/secret".path`
### Special Args Available in Modules
- `inputs`: Flake inputs (nixpkgs, sops-nix, etc.)
- `outputs`: This flake's outputs (nixosModules, packages)
- `constants`: Values from `constants.nix`
- `lib`: Extended nixpkgs.lib with `lib.utils`
## Deployment Workflows
| Host | Strategy | Trigger |
|------|----------|---------|
| `cryodev-main` | Pull via Comin | Automatic polling |
| `cryodev-pi` | Pull via Comin | Automatic polling |
| SD Images | Built in CI | Push to main (for Pi hosts) |
## Verification Checklist ## Verification Checklist
Before committing: Before committing:
- [ ] `nix fmt` passes - [ ] `nix fmt` passes
- [ ] `nix flake check` passes (or at least `nix eval` works) - [ ] `nix flake check` passes (or at least `nix eval` works for both hosts)
- [ ] New hosts added to `flake.nix` - [ ] New hosts added to `flake.nix` nixosConfigurations
- [ ] Constants in `constants.nix`, not hardcoded - [ ] Constants in `constants.nix`, not hardcoded
- [ ] Secrets use SOPS, not plaintext - [ ] Secrets use SOPS, not plaintext
- [ ] New services have their own file in `hosts/<host>/services/`
- [ ] New modules registered in `modules/nixos/default.nix`
- [ ] Documentation in English

2116
digest.txt

File diff suppressed because it is too large Load diff

View file

@ -31,12 +31,12 @@ Required DNS records for the cryodev infrastructure.
| `@` | MX | `10 mail.cryodev.xyz.` | Mail delivery | | `@` | MX | `10 mail.cryodev.xyz.` | Mail delivery |
| `@` | TXT | `"v=spf1 mx ~all"` | SPF | | `@` | TXT | `"v=spf1 mx ~all"` | SPF |
| `_dmarc` | TXT | `"v=DMARC1; p=none"` | DMARC | | `_dmarc` | TXT | `"v=DMARC1; p=none"` | DMARC |
| `mail._domainkey` | TXT | *(siehe unten)* | DKIM | | `mail._domainkey` | TXT | *(see below)* | DKIM |
### Reverse DNS (PTR) ### Reverse DNS (PTR)
Fuer zuverlaessige Mail-Zustellung muss ein **PTR Record** beim Hosting-Provider For reliable mail delivery, a **PTR record** must be configured at the hosting
konfiguriert werden (nicht im DNS-Panel der Domain): provider (not in the domain's DNS panel):
| IP | PTR Value | | IP | PTR Value |
|----|-----------| |----|-----------|
@ -45,18 +45,18 @@ konfiguriert werden (nicht im DNS-Panel der Domain):
#### Hetzner Robot (Dedicated Server) #### Hetzner Robot (Dedicated Server)
1. [robot.hetzner.com](https://robot.hetzner.com) > **Server** > Server auswaehlen 1. [robot.hetzner.com](https://robot.hetzner.com) > **Server** > Select the server
2. **IPs** Tab 2. **IPs** tab
3. Bei der IPv4-Adresse auf das **Stift-Symbol** klicken 3. Click the **pencil icon** next to the IPv4 address
4. `mail.cryodev.xyz` eintragen und speichern 4. Enter `mail.cryodev.xyz` and save
5. Fuer IPv6: Unter **Subnets** dasselbe fuer die primaere IPv6-Adresse 5. For IPv6: Under **Subnets**, repeat the same for the primary IPv6 address
#### Hetzner Cloud #### Hetzner Cloud
1. [cloud.hetzner.com](https://cloud.hetzner.com) > Server auswaehlen 1. [cloud.hetzner.com](https://cloud.hetzner.com) > Select the server
2. **Networking** Tab 2. **Networking** tab
3. Bei "Primary IP" auf die IP klicken > **Reverse DNS** 3. Under "Primary IP", click the IP > **Reverse DNS**
4. `mail.cryodev.xyz` eintragen (fuer IPv4 und IPv6) 4. Enter `mail.cryodev.xyz` (for both IPv4 and IPv6)
## Getting the DKIM Key ## Getting the DKIM Key
@ -70,15 +70,15 @@ Add this as a TXT record for `mail._domainkey.cryodev.xyz`.
## Complete Checklist ## Complete Checklist
- [ ] A/AAAA fuer `@` (Root-Domain) - [ ] A/AAAA for `@` (root domain)
- [ ] A/AAAA fuer `www` - [ ] A/AAAA for `www`
- [ ] A/AAAA fuer `mail` - [ ] A/AAAA for `mail`
- [ ] CNAME fuer `git`, `headscale`, `headplane`, `netdata` - [ ] CNAME for `git`, `headscale`, `headplane`, `netdata`
- [ ] MX Record - [ ] MX record
- [ ] TXT fuer SPF (`v=spf1 mx ~all`) - [ ] TXT for SPF (`v=spf1 mx ~all`)
- [ ] TXT fuer DMARC (`v=DMARC1; p=none`) - [ ] TXT for DMARC (`v=DMARC1; p=none`)
- [ ] TXT fuer DKIM (`mail._domainkey` -- nach erstem Deploy) - [ ] TXT for DKIM (`mail._domainkey` -- after first deployment)
- [ ] PTR Record beim Hosting-Provider (Reverse DNS) - [ ] PTR record at hosting provider (reverse DNS)
## Verification ## Verification

View file

@ -1,44 +1,44 @@
# Erstinstallation (x86_64 Server) # Initial Installation (x86_64 Server)
Diese Anleitung beschreibt die **Erstinstallation** eines neuen x86_64 Servers (z.B. cryodev-main). This guide describes the **initial installation** of a new x86_64 server (e.g. cryodev-main).
> **Fuer Raspberry Pi:** Siehe [SD-Image erstellen](sd-image.md). > **For Raspberry Pi:** See [Creating an SD Image](sd-image.md).
## Uebersicht ## Overview
Bei der Erstinstallation gibt es ein Henne-Ei-Problem: During initial installation there is a chicken-and-egg problem:
- SOPS-Secrets werden mit dem SSH-Host-Key verschluesselt - SOPS secrets are encrypted with the SSH host key
- Der SSH-Host-Key wird erst bei der Installation generiert - The SSH host key is only generated during installation
- Daher: **Erst ohne Secrets installieren, dann Secrets konfigurieren** - Therefore: **Install without secrets first, then configure secrets**
### Ablauf ### Process
``` ```
1. Services deaktivieren (die Secrets brauchen) 1. Disable services (that require secrets)
2. NixOS installieren 2. Install NixOS
3. SSH-Host-Key extrahieren, SOPS konfigurieren, sofort erstellbare Secrets anlegen 3. Extract SSH host key, configure SOPS, create immediately available secrets
4. Stufe-1-Services aktivieren und deployen (Headscale, Forgejo, Mail, Nginx) 4. Enable stage-1 services and deploy (Headscale, Forgejo, Mail, Nginx)
5. Restliche Secrets generieren (Tailscale, Headplane, Forgejo-Runner) 5. Generate remaining secrets (Tailscale, Headplane, Forgejo Runner)
6. Stufe-2-Services aktivieren und final deployen 6. Enable stage-2 services and perform final deployment
``` ```
## Schritt 1: Host-Konfiguration vorbereiten ## Step 1: Prepare Host Configuration
> Falls der Host bereits in `hosts/` und `flake.nix` existiert, ueberspringe 1.1-1.2. > If the host already exists in `hosts/` and `flake.nix`, skip 1.1-1.2.
### 1.1 Host aus Template erstellen ### 1.1 Create Host from Template
```bash ```bash
nix run .#create -- -t generic-server -n <hostname> nix run .#create -- -t generic-server -n <hostname>
``` ```
Das Script: The script:
- Kopiert das Template nach `hosts/<hostname>/` - Copies the template to `hosts/<hostname>/`
- Setzt den Hostname in `networking.nix` - Sets the hostname in `networking.nix`
- Erstellt eine leere `secrets.yaml` - Creates an empty `secrets.yaml`
- Fuegt die Dateien zu Git hinzu - Adds the files to Git
### 1.2 In flake.nix registrieren ### 1.2 Register in flake.nix
```nix ```nix
nixosConfigurations = { nixosConfigurations = {
@ -46,24 +46,24 @@ nixosConfigurations = {
}; };
``` ```
Ausserdem `hardware.nix` und `disks.sh` fuer die Zielhardware anpassen. Also adjust `hardware.nix` and `disks.sh` for the target hardware.
### 1.4 Services temporaer deaktivieren ### 1.4 Temporarily Disable Services
Alle Services, die SOPS-Secrets referenzieren, muessen fuer die Erstinstallation deaktiviert werden. Andernfalls schlaegt die Installation fehl, weil die Secrets noch nicht entschluesselt werden koennen. All services that reference SOPS secrets must be disabled for the initial installation. Otherwise the installation will fail because the secrets cannot yet be decrypted.
In `hosts/<hostname>/services/default.nix` die entsprechenden Imports auskommentieren: In `hosts/<hostname>/services/default.nix`, comment out the corresponding imports:
```nix ```nix
{ {
imports = [ imports = [
# Deaktiviert bis SOPS-Secrets konfiguriert sind: # Disabled until SOPS secrets are configured:
# ./forgejo.nix # braucht: forgejo-runner/token, forgejo/mail-pw # ./forgejo.nix # requires: forgejo-runner/token, forgejo/mail-pw
# ./headplane.nix # braucht: headplane/cookie_secret, headplane/agent_pre_authkey # ./headplane.nix # requires: headplane/cookie_secret, headplane/agent_pre_authkey
# ./mailserver.nix # braucht: mailserver/accounts/* # ./mailserver.nix # requires: mailserver/accounts/*
# ./tailscale.nix # braucht: tailscale/auth-key # ./tailscale.nix # requires: tailscale/auth-key
# Diese Services brauchen keine Secrets: # These services do not require secrets:
./headscale.nix ./headscale.nix
./netdata.nix ./netdata.nix
./nginx.nix ./nginx.nix
@ -73,7 +73,7 @@ In `hosts/<hostname>/services/default.nix` die entsprechenden Imports auskomment
} }
``` ```
Zusaetzlich in `hosts/<hostname>/services/sops.nix` die Secrets-Definitionen auskommentieren: Additionally, in `hosts/<hostname>/services/sops.nix`, comment out the secret definitions:
```nix ```nix
sops = { sops = {
@ -85,32 +85,32 @@ sops = {
}; };
``` ```
### 1.5 Konfiguration testen ### 1.5 Test the Configuration
```bash ```bash
nix eval .#nixosConfigurations.<hostname>.config.system.build.toplevel.name nix eval .#nixosConfigurations.<hostname>.config.system.build.toplevel.name
``` ```
## Schritt 2: Installation durchfuehren ## Step 2: Perform Installation
### 2.1 NixOS ISO booten ### 2.1 Boot NixOS ISO
Vom [NixOS Minimal ISO](https://nixos.org/download/#nixos-iso) booten (USB/CD). Boot from the [NixOS Minimal ISO](https://nixos.org/download/#nixos-iso) (USB/CD).
### 2.2 Netzwerk und SSH einrichten ### 2.2 Set Up Network and SSH
```bash ```bash
passwd # Root-Passwort setzen fuer SSH-Zugang passwd # Set root password for SSH access
ip a # IP-Adresse ermitteln ip a # Determine IP address
``` ```
Optional per SSH verbinden (bequemer): Optionally connect via SSH (more convenient):
```bash ```bash
ssh -o StrictHostKeyChecking=no root@<IP> ssh -o StrictHostKeyChecking=no root@<IP>
``` ```
### 2.3 Installieren ### 2.3 Install
```bash ```bash
nix --experimental-features "nix-command flakes" run \ nix --experimental-features "nix-command flakes" run \
@ -119,20 +119,20 @@ nix --experimental-features "nix-command flakes" run \
-r <REPO_URL> -r <REPO_URL>
``` ```
Alternativ, falls das Repository bereits unter `/tmp/nixos` geklont wurde: Alternatively, if the repository has already been cloned to `/tmp/nixos`:
```bash ```bash
nix --experimental-features "nix-command flakes" run /tmp/nixos#install -- -n <hostname> nix --experimental-features "nix-command flakes" run /tmp/nixos#install -- -n <hostname>
``` ```
> **Hinweis:** Die Disk-ID in `hosts/<hostname>/disks.sh` muss zur Hardware passen. > **Note:** The disk ID in `hosts/<hostname>/disks.sh` must match the hardware.
> Pruefen mit `ls -la /dev/disk/by-id/`. > Verify with `ls -la /dev/disk/by-id/`.
Das Script: The script:
1. Klont das Repository (bei `-r`) 1. Clones the repository (when using `-r`)
2. Partitioniert die Disk (via `disks.nix` oder `disks.sh`) 2. Partitions the disk (via `disks.nix` or `disks.sh`)
3. Generiert `hardware.nix` (falls nicht vorhanden) 3. Generates `hardware.nix` (if not present)
4. Installiert NixOS 4. Installs NixOS
### 2.4 Reboot ### 2.4 Reboot
@ -140,34 +140,34 @@ Das Script:
reboot reboot
``` ```
## Schritt 3: SOPS-Secrets konfigurieren ## Step 3: Configure SOPS Secrets
Nach dem ersten Boot einloggen (Passwort: `changeme`, sofort aendern mit `passwd`). After the first boot, log in (password: `changeme`, change immediately with `passwd`).
### 3.1 SSH-Host-Key zu Age-Key konvertieren ### 3.1 Convert SSH Host Key to Age Key
Auf dem **neuen Server**: On the **new server**:
```bash ```bash
nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age' nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
``` ```
Ausgabe notieren (z.B. `age1abc123...`). Note the output (e.g. `age1abc123...`).
Alternativ remote: Alternatively, remotely:
```bash ```bash
nix-shell -p ssh-to-age --run 'ssh-keyscan -p 2299 -t ed25519 <IP> | ssh-to-age' nix-shell -p ssh-to-age --run 'ssh-keyscan -p 2299 -t ed25519 <IP> | ssh-to-age'
``` ```
### 3.2 .sops.yaml aktualisieren ### 3.2 Update .sops.yaml
Auf dem **Entwicklungsrechner** den neuen Host-Key in `.sops.yaml` eintragen: On the **development machine**, add the new host key to `.sops.yaml`:
```yaml ```yaml
keys: keys:
- &steffen_key age1e8p... # steffen (lokal) - &steffen_key age1e8p... # steffen (local)
- &hostname_key age1abc... # Key von Schritt 3.1 - &hostname_key age1abc... # Key from step 3.1
creation_rules: creation_rules:
- path_regex: hosts/<hostname>/secrets.yaml$ - path_regex: hosts/<hostname>/secrets.yaml$
@ -177,38 +177,38 @@ creation_rules:
- *hostname_key - *hostname_key
``` ```
### 3.3 Secrets erstellen ### 3.3 Create Secrets
Secrets-Datei oeffnen: Open the secrets file:
```bash ```bash
sops hosts/<hostname>/secrets.yaml sops hosts/<hostname>/secrets.yaml
``` ```
Die folgende Tabelle zeigt alle Secrets fuer **cryodev-main** und wie sie generiert werden: The following table shows all secrets for **cryodev-main** and how they are generated:
#### Sofort erstellbare Secrets #### Immediately Available Secrets
Diese Secrets haben keine Abhaengigkeiten und koennen direkt generiert werden: These secrets have no dependencies and can be generated directly:
| Secret | Befehl | | Secret | Command |
|--------|--------| |--------|---------|
| `headplane/cookie_secret` | `openssl rand -hex 16` | | `headplane/cookie_secret` | `openssl rand -hex 16` |
| `mailserver/accounts/admin` | `mkpasswd -sm bcrypt` (Passwort merken!) | | `mailserver/accounts/admin` | `mkpasswd -sm bcrypt` (remember the password!) |
| `mailserver/accounts/forgejo` | `mkpasswd -sm bcrypt` (Passwort merken!) | | `mailserver/accounts/forgejo` | `mkpasswd -sm bcrypt` (remember the password!) |
| `forgejo/mail-pw` | Klartext-Passwort das zum bcrypt-Hash von `mailserver/accounts/forgejo` passt | | `forgejo/mail-pw` | Plaintext password matching the bcrypt hash of `mailserver/accounts/forgejo` |
#### Secrets die laufende Services brauchen #### Secrets That Require Running Services
Diese Secrets koennen erst nach Schritt 4 erstellt werden. **Jetzt noch nicht eintragen** -- sie werden spaeter ergaenzt. These secrets can only be created after step 4. **Do not add them yet** -- they will be added later.
| Secret | Befehl | Voraussetzung | | Secret | Command | Prerequisite |
|--------|--------|---------------| |--------|---------|--------------|
| `tailscale/auth-key` | Siehe Schritt 4.1-4.2 | Headscale laeuft | | `tailscale/auth-key` | See steps 4.1-4.2 | Headscale is running |
| `headplane/agent_pre_authkey` | Siehe Schritt 4.1-4.2 | Headscale laeuft | | `headplane/agent_pre_authkey` | See steps 4.1-4.2 | Headscale is running |
| `forgejo-runner/token` | Forgejo Admin Panel > Actions > Runners > Create Runner | Forgejo laeuft | | `forgejo-runner/token` | Forgejo Admin Panel > Actions > Runners > Create Runner | Forgejo is running |
#### Beispiel secrets.yaml (Klartext vor Verschluesselung) #### Example secrets.yaml (Plaintext Before Encryption)
```yaml ```yaml
headplane: headplane:
@ -218,22 +218,22 @@ mailserver:
admin: "$2b$05$..." admin: "$2b$05$..."
forgejo: "$2b$05$..." forgejo: "$2b$05$..."
forgejo: forgejo:
mail-pw: "das-klartext-passwort" mail-pw: "the-plaintext-password"
``` ```
### 3.4 Services stufenweise reaktivieren -- Stufe 1 ### 3.4 Gradually Re-enable Services -- Stage 1
> **Wichtig:** Services die Headscale- oder Forgejo-Secrets brauchen (Tailscale, > **Important:** Services that require Headscale or Forgejo secrets (Tailscale,
> Headplane, Forgejo-Runner) duerfen noch **nicht** aktiviert werden, da diese > Headplane, Forgejo Runner) must **not** be enabled yet, as these
> Secrets erst generiert werden koennen, wenn die Services laufen. > secrets can only be generated once those services are running.
Auf dem **Entwicklungsrechner** in `hosts/<hostname>/services/default.nix` die On the **development machine**, in `hosts/<hostname>/services/default.nix`, enable
Services **ohne externe Abhaengigkeiten** aktivieren: the services **without external dependencies**:
```nix ```nix
{ {
imports = [ imports = [
# Stufe 1: Services ohne externe Abhaengigkeiten # Stage 1: Services without external dependencies
./forgejo.nix ./forgejo.nix
./headscale.nix ./headscale.nix
./mailserver.nix ./mailserver.nix
@ -242,88 +242,88 @@ Services **ohne externe Abhaengigkeiten** aktivieren:
./openssh.nix ./openssh.nix
./sops.nix ./sops.nix
# Stufe 2: Erst nach Schritt 4 aktivieren # Stage 2: Enable only after step 4
# ./forgejo-runner.nix # braucht: forgejo-runner/token (Forgejo) # ./forgejo-runner.nix # requires: forgejo-runner/token (Forgejo)
# ./headplane.nix # braucht: headplane/agent_pre_authkey (Headscale) # ./headplane.nix # requires: headplane/agent_pre_authkey (Headscale)
# ./tailscale.nix # braucht: tailscale/auth-key (Headscale) # ./tailscale.nix # requires: tailscale/auth-key (Headscale)
]; ];
} }
``` ```
### 3.5 Deployen (Stufe 1) ### 3.5 Deploy (Stage 1)
```bash ```bash
nix run .#deploy -- -n <hostname> nix run .#deploy -- -n <hostname>
``` ```
Dies nutzt die Konfiguration aus `deploy.json`. Alternativ manuell: This uses the configuration from `deploy.json`. Alternatively, deploy manually:
```bash ```bash
NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#<hostname> \ NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#<hostname> \
--target-host <user>@<IP> --sudo --ask-sudo-password --target-host <user>@<IP> --sudo --ask-sudo-password
``` ```
Nach diesem Deploy laufen Headscale, Forgejo, Mailserver und Nginx. After this deployment, Headscale, Forgejo, Mailserver, and Nginx are running.
### 3.6 Forgejo Admin-Account erstellen ### 3.6 Create Forgejo Admin Account
Beim ersten Start hat Forgejo noch keine Benutzer. Admin-Account per CLI anlegen On first start, Forgejo has no users. Create an admin account via CLI
(auf dem **Server**): (on the **server**):
```bash ```bash
forgejo admin user create \ forgejo admin user create \
--username <benutzername> \ --username <username> \
--email <email>@<domain> \ --email <email>@<domain> \
--password <passwort> \ --password <password> \
--admin --admin
``` ```
> **Hinweis:** Das `forgejo` Shell-Alias wird vom Modul bereitgestellt und fuehrt > **Note:** The `forgejo` shell alias is provided by the module and automatically
> automatisch den Befehl als `forgejo`-User mit der richtigen Config aus. > runs the command as the `forgejo` user with the correct config.
> Falls der Alias nicht verfuegbar ist, neue Shell starten (`bash` oder `zsh`). > If the alias is not available, start a new shell (`bash` or `zsh`).
> >
> Da `DISABLE_REGISTRATION = true` gesetzt ist, koennen neue Accounts > Since `DISABLE_REGISTRATION = true` is set, new accounts
> nur per CLI erstellt werden. > can only be created via CLI.
## Schritt 4: Restliche Secrets generieren und alle Services aktivieren ## Step 4: Generate Remaining Secrets and Enable All Services
Nachdem der Server mit Headscale und Forgejo laeuft: After the server is running with Headscale and Forgejo:
1. **Headscale-User anlegen** (auf dem Server): 1. **Create Headscale users** (on the server):
```bash ```bash
sudo headscale users create default sudo headscale users create default
sudo headscale users create headplane-agent sudo headscale users create headplane-agent
``` ```
2. **User-IDs ermitteln** (wird fuer die Preauth-Keys benoetigt): 2. **Determine user IDs** (needed for the preauth keys):
```bash ```bash
sudo headscale users list sudo headscale users list
``` ```
Die Ausgabe zeigt die numerischen IDs (z.B. `1` fuer default, `2` fuer headplane-agent). The output shows the numeric IDs (e.g. `1` for default, `2` for headplane-agent).
3. **Preauth-Keys generieren** (mit den IDs aus Schritt 2): 3. **Generate preauth keys** (using the IDs from step 2):
```bash ```bash
# Fuer Tailscale (User-ID von "default" einsetzen) # For Tailscale (use the user ID of "default")
sudo headscale preauthkeys create --expiration 99y --reusable --user <ID> sudo headscale preauthkeys create --expiration 99y --reusable --user <ID>
# Fuer Headplane Agent (User-ID von "headplane-agent" einsetzen) # For Headplane Agent (use the user ID of "headplane-agent")
sudo headscale preauthkeys create --expiration 99y --user <ID> sudo headscale preauthkeys create --expiration 99y --user <ID>
``` ```
4. **Forgejo-Runner-Token** ueber das Forgejo Admin Panel erstellen: 4. **Create the Forgejo Runner token** via the Forgejo Admin Panel:
Administration > Actions > Runners > Create new Runner Administration > Actions > Runners > Create new Runner
5. **Secrets ergaenzen**: 5. **Add the remaining secrets**:
```bash ```bash
sops hosts/<hostname>/secrets.yaml sops hosts/<hostname>/secrets.yaml
``` ```
Die fehlenden Secrets eintragen: Add the missing secrets:
```yaml ```yaml
tailscale: tailscale:
@ -334,7 +334,7 @@ Nachdem der Server mit Headscale und Forgejo laeuft:
agent_pre_authkey: "..." agent_pre_authkey: "..."
``` ```
6. **Stufe-2-Services aktivieren** in `hosts/<hostname>/services/default.nix`: 6. **Enable stage-2 services** in `hosts/<hostname>/services/default.nix`:
```nix ```nix
{ {
@ -353,14 +353,14 @@ Nachdem der Server mit Headscale und Forgejo laeuft:
} }
``` ```
6. **Erneut deployen**: 6. **Deploy again**:
```bash ```bash
nix run .#deploy -- -n <hostname> nix run .#deploy -- -n <hostname>
``` ```
## Naechste Schritte ## Next Steps
- [SOPS-Referenz](../services/sops.md) -- Detail-Dokumentation zur Secret-Verwaltung - [SOPS Reference](../services/sops.md) -- Detailed documentation on secret management
- [SD-Image erstellen](sd-image.md) -- Raspberry Pi installieren - [Creating an SD Image](sd-image.md) -- Install Raspberry Pi
- [CD einrichten](../deployment/cd.md) -- Automatisches Deployment - [Set Up CD](../deployment/cd.md) -- Automatic deployment

View file

@ -1,60 +1,60 @@
# Neuen Raspberry Pi Client hinzufügen # Adding a New Raspberry Pi Client
Diese Anleitung beschreibt das Hinzufügen eines **neuen Raspberry Pi Clients** zur Infrastruktur. This guide describes how to add a **new Raspberry Pi client** to the infrastructure.
## Übersicht: Der Ablauf ## Overview: The Process
``` ```
1. Konfiguration erstellen ──► Template kopieren, anpassen 1. Create configuration ──► Copy template, customize
2. Zur Image-Pipeline hinzufügen ──► Workflow-Matrix erweitern 2. Add to image pipeline ──► Extend workflow matrix
3. Push auf main ──► Forgejo baut automatisch SD-Image 3. Push to main ──► Forgejo automatically builds SD image
4. Image flashen & booten ──► SD-Karte beschreiben, Pi starten 4. Flash image & boot ──► Write SD card, start Pi
5. SOPS konfigurieren ──► Age-Key holen, Secrets erstellen 5. Configure SOPS ──► Retrieve age key, create secrets
6. Finales Deployment ──► Tailscale etc. aktivieren 6. Final deployment ──► Activate Tailscale etc.
``` ```
## Voraussetzungen ## Prerequisites
- SSH-Zugang zu cryodev-main (für Tailscale Auth-Key) - SSH access to cryodev-main (for Tailscale auth key)
- Entwicklungsrechner mit Repository-Zugriff - Development machine with repository access
- SD-Karte (mindestens 8 GB) - SD card (at least 8 GB)
--- ---
## Schritt 1: Tailscale Auth-Key generieren ## Step 1: Generate Tailscale Auth Key
**Auf cryodev-main** (per SSH): **On cryodev-main** (via SSH):
```bash ```bash
# User-ID ermitteln # Determine user ID
sudo headscale users list sudo headscale users list
# Preauth-Key erstellen (User-ID von "default" einsetzen) # Create preauth key (use user ID of "default")
sudo headscale preauthkeys create --expiration 99y --reusable --user <ID> sudo headscale preauthkeys create --expiration 99y --reusable --user <ID>
``` ```
**Ausgabe notieren!** (z.B. `tskey-preauth-abc123...`) **Take note of the output!** (e.g. `tskey-preauth-abc123...`)
--- ---
## Schritt 2: Host-Konfiguration erstellen ## Step 2: Create Host Configuration
### 2.1 Template kopieren ### 2.1 Copy Template
```bash ```bash
cp -r templates/raspberry-pi hosts/neuer-pi cp -r templates/raspberry-pi hosts/neuer-pi
``` ```
### 2.2 Hostname setzen ### 2.2 Set Hostname
`hosts/neuer-pi/networking.nix`: `hosts/neuer-pi/networking.nix`:
@ -64,58 +64,58 @@ cp -r templates/raspberry-pi hosts/neuer-pi
} }
``` ```
### 2.3 In flake.nix registrieren ### 2.3 Register in flake.nix
```nix ```nix
nixosConfigurations = { nixosConfigurations = {
# ... bestehende Hosts ... # ... existing hosts ...
neuer-pi = mkNixosConfiguration "aarch64-linux" [ ./hosts/neuer-pi ]; neuer-pi = mkNixosConfiguration "aarch64-linux" [ ./hosts/neuer-pi ];
}; };
``` ```
### 2.4 In constants.nix eintragen ### 2.4 Add to constants.nix
```nix ```nix
{ {
hosts = { hosts = {
# ... bestehende Hosts ... # ... existing hosts ...
neuer-pi = { neuer-pi = {
ip = "100.64.0.X"; # Wird von Headscale vergeben ip = "100.64.0.X"; # Assigned by Headscale
}; };
}; };
} }
``` ```
### 2.5 Placeholder secrets.yaml erstellen ### 2.5 Create Placeholder secrets.yaml
```bash ```bash
touch hosts/neuer-pi/secrets.yaml touch hosts/neuer-pi/secrets.yaml
``` ```
### 2.6 SOPS temporär deaktivieren ### 2.6 Temporarily Disable SOPS
In `hosts/neuer-pi/default.nix` die `sops.secrets.*` Referenzen auskommentieren, damit das Image ohne Secrets gebaut werden kann. In `hosts/neuer-pi/default.nix`, comment out the `sops.secrets.*` references so the image can be built without secrets.
--- ---
## Schritt 3: Zur Image-Pipeline hinzufügen ## Step 3: Add to Image Pipeline
Bearbeite `.forgejo/workflows/build-pi-image.yml`: Edit `.forgejo/workflows/build-pi-image.yml`:
```yaml ```yaml
jobs: jobs:
build-pi-images: build-pi-images:
strategy: strategy:
matrix: matrix:
# Neuen Host hier hinzufügen: # Add new host here:
host: [cryodev-pi, neuer-pi] host: [cryodev-pi, neuer-pi]
``` ```
--- ---
## Schritt 4: Push und Image bauen lassen ## Step 4: Push and Build Image
```bash ```bash
git add . git add .
@ -123,86 +123,86 @@ git commit -m "Add neuer-pi host configuration"
git push git push
``` ```
Der Forgejo Workflow baut jetzt automatisch ein SD-Image für `neuer-pi`. The Forgejo workflow will now automatically build an SD image for `neuer-pi`.
**Warten** bis der Workflow fertig ist (30-60 Minuten). Status prüfen unter: **Wait** until the workflow completes (30-60 minutes). Check the status at:
`https://git.cryodev.xyz/steffen/cryodev-server/actions` `https://git.cryodev.xyz/steffen/cryodev-server/actions`
--- ---
## Schritt 5: Image flashen ## Step 5: Flash Image
### 5.1 Image herunterladen ### 5.1 Download Image
Nach erfolgreichem Build unter **Releases**: After a successful build, find the image under **Releases**:
```bash ```bash
wget https://git.cryodev.xyz/steffen/cryodev-server/releases/latest/download/neuer-pi-sd-image.img.zst wget https://git.cryodev.xyz/steffen/cryodev-server/releases/latest/download/neuer-pi-sd-image.img.zst
``` ```
### 5.2 Dekomprimieren ### 5.2 Decompress
```bash ```bash
zstd -d neuer-pi-sd-image.img.zst -o neuer-pi.img zstd -d neuer-pi-sd-image.img.zst -o neuer-pi.img
``` ```
### 5.3 Auf SD-Karte schreiben ### 5.3 Write to SD Card
**Achtung:** `/dev/sdX` durch das richtige Gerät ersetzen! **Warning:** Replace `/dev/sdX` with the correct device!
```bash ```bash
lsblk # Richtiges Gerät finden lsblk # Identify the correct device
sudo dd if=neuer-pi.img of=/dev/sdX bs=4M conv=fsync status=progress sudo dd if=neuer-pi.img of=/dev/sdX bs=4M conv=fsync status=progress
``` ```
### 5.4 Booten ### 5.4 Boot
1. SD-Karte in den Raspberry Pi einlegen 1. Insert the SD card into the Raspberry Pi
2. Ethernet anschließen 2. Connect Ethernet
3. Strom anschließen 3. Connect power
4. Warten bis gebootet (ca. 2 Minuten) 4. Wait until booted (approximately 2 minutes)
--- ---
## Schritt 6: SOPS konfigurieren ## Step 6: Configure SOPS
### 6.1 IP-Adresse finden ### 6.1 Find IP Address
Der Pi sollte per DHCP eine IP bekommen. Prüfe deinen Router oder scanne das Netzwerk: The Pi should receive an IP address via DHCP. Check your router or scan the network:
```bash ```bash
nmap -sn 192.168.1.0/24 | grep -B2 "Raspberry" nmap -sn 192.168.1.0/24 | grep -B2 "Raspberry"
``` ```
### 6.2 SSH verbinden ### 6.2 Connect via SSH
```bash ```bash
ssh steffen@<IP> # oder der konfigurierte User ssh steffen@<IP> # or the configured user
``` ```
Standard-Passwort siehe `hosts/neuer-pi/users.nix`. For the default password, see `hosts/neuer-pi/users.nix`.
### 6.3 Age-Key ermitteln ### 6.3 Determine Age Key
Auf dem Pi: On the Pi:
```bash ```bash
nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age' nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
``` ```
**Ausgabe notieren!** (z.B. `age1xyz...`) **Take note of the output!** (e.g. `age1xyz...`)
### 6.4 .sops.yaml aktualisieren ### 6.4 Update .sops.yaml
Auf dem Entwicklungsrechner: On the development machine:
```yaml ```yaml
keys: keys:
- &steffen_key age1e8p35795htf7twrejyugpzw0qja2v33awcw76y4gp6acnxnkzq0s935t4t # steffen (local) - &steffen_key age1e8p35795htf7twrejyugpzw0qja2v33awcw76y4gp6acnxnkzq0s935t4t # steffen (local)
- &neuer_pi_key age1xyz... # Der neue Key - &neuer_pi_key age1xyz... # The new key
creation_rules: creation_rules:
# ... bestehende Regeln ... # ... existing rules ...
- path_regex: hosts/neuer-pi/secrets.yaml$ - path_regex: hosts/neuer-pi/secrets.yaml$
key_groups: key_groups:
@ -211,30 +211,30 @@ creation_rules:
- *neuer_pi_key - *neuer_pi_key
``` ```
### 6.5 Secrets erstellen ### 6.5 Create Secrets
```bash ```bash
sops hosts/neuer-pi/secrets.yaml sops hosts/neuer-pi/secrets.yaml
``` ```
Inhalt: Contents:
```yaml ```yaml
tailscale: tailscale:
auth-key: "tskey-preauth-abc123..." # Key aus Schritt 1 auth-key: "tskey-preauth-abc123..." # Key from Step 1
netdata: netdata:
stream: stream:
child-uuid: "..." # uuidgen child-uuid: "..." # uuidgen
``` ```
### 6.6 SOPS-Referenzen aktivieren ### 6.6 Activate SOPS References
Die in Schritt 2.6 auskommentierten `sops.secrets.*` Referenzen wieder aktivieren. Re-enable the `sops.secrets.*` references that were commented out in Step 2.6.
--- ---
## Schritt 7: Finales Deployment ## Step 7: Final Deployment
```bash ```bash
git add . git add .
@ -242,9 +242,9 @@ git commit -m "Configure SOPS secrets for neuer-pi"
git push git push
``` ```
Da Comin auf dem Pi läuft, wird er die neue Konfiguration automatisch pullen. Since Comin is running on the Pi, it will automatically pull the new configuration.
Alternativ manuell: Alternatively, deploy manually:
```bash ```bash
NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#neuer-pi \ NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#neuer-pi \
@ -253,34 +253,34 @@ NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#neuer-pi \
--- ---
## Schritt 8: Verifizieren ## Step 8: Verify
### Tailscale-Verbindung ### Tailscale Connection
```bash ```bash
# Auf dem Pi # On the Pi
tailscale status tailscale status
# Auf cryodev-main # On cryodev-main
sudo headscale nodes list sudo headscale nodes list
``` ```
### Netdata-Streaming ### Netdata Streaming
Prüfe ob der neue Client im Netdata-Dashboard erscheint: Check whether the new client appears in the Netdata dashboard:
`https://netdata.cryodev.xyz` `https://netdata.cryodev.xyz`
--- ---
## Checkliste ## Checklist
- [ ] Tailscale Auth-Key auf cryodev-main generiert - [ ] Tailscale auth key generated on cryodev-main
- [ ] Host-Konfiguration erstellt (Template, flake.nix, constants.nix) - [ ] Host configuration created (template, flake.nix, constants.nix)
- [ ] Host zur Workflow-Matrix hinzugefügt - [ ] Host added to workflow matrix
- [ ] Gepusht und auf Image-Build gewartet - [ ] Pushed and waited for image build
- [ ] SD-Karte geflasht und Pi gebootet - [ ] SD card flashed and Pi booted
- [ ] Age-Key ermittelt und in .sops.yaml eingetragen - [ ] Age key determined and added to .sops.yaml
- [ ] secrets.yaml erstellt (Tailscale-Key, Netdata-UUID) - [ ] secrets.yaml created (Tailscale key, Netdata UUID)
- [ ] SOPS-Referenzen aktiviert und deployed - [ ] SOPS references activated and deployed
- [ ] Tailscale-Verbindung funktioniert - [ ] Tailscale connection working
- [ ] Netdata-Streaming funktioniert - [ ] Netdata streaming working

View file

@ -1,70 +1,70 @@
# Neuinstallation (Reinstall) # Reinstallation
Diese Anleitung beschreibt die **Neuinstallation** eines bestehenden Hosts, z.B. nach Hardwarewechsel oder bei Problemen. This guide describes the **reinstallation** of an existing host, e.g. after a hardware change or in case of issues.
## Unterschied zur Erstinstallation ## Difference from Initial Installation
| Aspekt | Erstinstallation | Neuinstallation | | Aspect | Initial Installation | Reinstallation |
|--------|------------------|-----------------| |--------|----------------------|----------------|
| SOPS-Secrets | Noch nicht vorhanden | Bereits konfiguriert | | SOPS Secrets | Not yet present | Already configured |
| SSH-Host-Key | Neu generiert | **Muss wiederhergestellt werden!** | | SSH Host Key | Newly generated | **Must be restored!** |
| Disk-IDs | Neu ermitteln | Oft geändert (neue Hardware) | | Disk IDs | Newly determined | Often changed (new hardware) |
| secrets.yaml | Wird erstellt | Bereits vorhanden | | secrets.yaml | Will be created | Already exists |
## Wichtig: SSH-Host-Key Problem ## Important: SSH Host Key Issue
Bei einer Neuinstallation wird ein **neuer SSH-Host-Key** generiert. Dieser stimmt nicht mehr mit dem Age-Key in `.sops.yaml` überein! During a reinstallation, a **new SSH host key** is generated. This key will no longer match the age key in `.sops.yaml`!
### Lösungsmöglichkeiten ### Possible Solutions
**Option A: Alten Host-Key sichern und wiederherstellen** (empfohlen) **Option A: Back up and restore the old host key** (recommended)
**Option B: Neuen Key generieren und SOPS aktualisieren** **Option B: Generate a new key and update SOPS**
## Voraussetzungen ## Prerequisites
- Backup des alten SSH-Host-Keys (falls Option A) - Backup of the old SSH host key (if using Option A)
- Zugriff auf `.sops.yaml` und die Admin-Age-Keys - Access to `.sops.yaml` and the admin age keys
- Bootbares NixOS ISO - Bootable NixOS ISO
## Schritt 1: Vorbereitung (vor der Installation) ## Step 1: Preparation (before the installation)
### 1.1 Alten SSH-Host-Key sichern (Option A) ### 1.1 Back Up the Old SSH Host Key (Option A)
Falls der alte Host noch läuft: If the old host is still running:
```bash ```bash
# Auf dem alten Host # On the old host
sudo cat /etc/ssh/ssh_host_ed25519_key > ~/ssh_host_ed25519_key.backup sudo cat /etc/ssh/ssh_host_ed25519_key > ~/ssh_host_ed25519_key.backup
sudo cat /etc/ssh/ssh_host_ed25519_key.pub > ~/ssh_host_ed25519_key.pub.backup sudo cat /etc/ssh/ssh_host_ed25519_key.pub > ~/ssh_host_ed25519_key.pub.backup
``` ```
Dateien sicher auf den Entwicklungsrechner kopieren. Copy the files securely to the development machine.
### 1.2 Disk-IDs ermitteln ### 1.2 Determine Disk IDs
**Bei neuer Hardware** ändern sich die Disk-IDs! **With new hardware**, the disk IDs will change!
```bash ```bash
# Im NixOS Live-System # In the NixOS live system
lsblk -o NAME,SIZE,MODEL,SERIAL lsblk -o NAME,SIZE,MODEL,SERIAL
ls -la /dev/disk/by-id/ ls -la /dev/disk/by-id/
``` ```
Die neue Disk-ID in `hosts/<hostname>/disks.sh` oder `disks.nix` eintragen: Enter the new disk ID in `hosts/<hostname>/disks.sh` or `disks.nix`:
```bash ```bash
# Beispiel disks.sh # Example disks.sh
DISK="/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_XXXXX" DISK="/dev/disk/by-id/nvme-Samsung_SSD_970_EVO_Plus_XXXXX"
``` ```
## Schritt 2: Installation durchführen ## Step 2: Perform the Installation
### 2.1 NixOS ISO booten ### 2.1 Boot the NixOS ISO
Von USB/CD booten, Root-Passwort setzen, per SSH verbinden. Boot from USB/CD, set a root password, and connect via SSH.
### 2.2 Repository klonen ### 2.2 Clone the Repository
```bash ```bash
sudo -i sudo -i
@ -73,30 +73,30 @@ git clone <GIT_REPO_URL> /tmp/nixos
cd /tmp/nixos cd /tmp/nixos
``` ```
### 2.3 Disk-Konfiguration prüfen ### 2.3 Verify the Disk Configuration
```bash ```bash
# Aktuelle Disk-IDs anzeigen # Display current disk IDs
ls -la /dev/disk/by-id/ ls -la /dev/disk/by-id/
# Mit Konfiguration vergleichen # Compare with the configuration
cat hosts/<hostname>/disks.sh | grep DISK cat hosts/<hostname>/disks.sh | grep DISK
``` ```
**Falls nötig:** Disk-ID in der Konfiguration anpassen. **If necessary:** Update the disk ID in the configuration.
### 2.4 Install-Script ausführen ### 2.4 Run the Install Script
```bash ```bash
bash scripts/install.sh -n <hostname> bash scripts/install.sh -n <hostname>
``` ```
### 2.5 SSH-Host-Key wiederherstellen (Option A) ### 2.5 Restore the SSH Host Key (Option A)
**Vor dem Reboot!** **Before rebooting!**
```bash ```bash
# Host-Key vom Backup wiederherstellen # Restore the host key from backup
cp /path/to/ssh_host_ed25519_key.backup /mnt/etc/ssh/ssh_host_ed25519_key cp /path/to/ssh_host_ed25519_key.backup /mnt/etc/ssh/ssh_host_ed25519_key
cp /path/to/ssh_host_ed25519_key.pub.backup /mnt/etc/ssh/ssh_host_ed25519_key.pub cp /path/to/ssh_host_ed25519_key.pub.backup /mnt/etc/ssh/ssh_host_ed25519_key.pub
chmod 600 /mnt/etc/ssh/ssh_host_ed25519_key chmod 600 /mnt/etc/ssh/ssh_host_ed25519_key
@ -110,75 +110,75 @@ umount -Rl /mnt
reboot reboot
``` ```
## Schritt 3: Nach dem Reboot ## Step 3: After the Reboot
### Bei Option A (Key wiederhergestellt) ### Option A (Key Restored)
SOPS-Secrets sollten automatisch funktionieren. Testen: SOPS secrets should work automatically. Verify:
```bash ```bash
sudo cat /run/secrets/tailscale/auth-key sudo cat /run/secrets/tailscale/auth-key
``` ```
### Bei Option B (Neuer Key) ### Option B (New Key)
Der Host kann die Secrets nicht entschlüsseln. Neuen Key konfigurieren: The host cannot decrypt the secrets. Configure the new key:
```bash ```bash
# Neuen Age-Key ermitteln # Determine the new age key
nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age' nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
``` ```
Auf dem Entwicklungsrechner: On the development machine:
```bash ```bash
# .sops.yaml aktualisieren mit neuem Key # Update .sops.yaml with the new key
vim .sops.yaml vim .sops.yaml
# Secrets mit neuem Key neu verschlüsseln # Re-encrypt secrets with the new key
sops updatekeys hosts/<hostname>/secrets.yaml sops updatekeys hosts/<hostname>/secrets.yaml
``` ```
Dann Konfiguration neu deployen: Then redeploy the configuration:
```bash ```bash
NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#<hostname> \ NIX_SSHOPTS="-p 2299" nixos-rebuild switch --flake .#<hostname> \
--target-host <user>@<IP> --sudo --ask-sudo-password --target-host <user>@<IP> --sudo --ask-sudo-password
``` ```
## Häufige Probleme ## Common Issues
### "No secret key available" ### "No secret key available"
SOPS kann die Secrets nicht entschlüsseln. Ursache: SOPS cannot decrypt the secrets. Cause:
- SSH-Host-Key stimmt nicht mit Age-Key in `.sops.yaml` überein - SSH host key does not match the age key in `.sops.yaml`
Lösung: Option B durchführen (neuen Key konfigurieren). Solution: Follow Option B (configure the new key).
### "Device not found" beim Partitionieren ### "Device not found" during partitioning
Disk-ID in `disks.sh`/`disks.nix` ist falsch. The disk ID in `disks.sh`/`disks.nix` is incorrect.
```bash ```bash
# Richtige ID finden # Find the correct ID
ls -la /dev/disk/by-id/ ls -la /dev/disk/by-id/
``` ```
### Hardware-Config veraltet ### Outdated Hardware Config
Bei neuer Hardware muss `hardware.nix` neu generiert werden: With new hardware, `hardware.nix` must be regenerated:
```bash ```bash
# Install-Script generiert automatisch neu, falls Datei fehlt # The install script regenerates automatically if the file is missing
rm hosts/<hostname>/hardware.nix rm hosts/<hostname>/hardware.nix
bash scripts/install.sh -n <hostname> bash scripts/install.sh -n <hostname>
``` ```
## Checkliste ## Checklist
- [ ] Alten SSH-Host-Key gesichert (falls möglich) - [ ] Old SSH host key backed up (if possible)
- [ ] Disk-IDs in Konfiguration geprüft/aktualisiert - [ ] Disk IDs in configuration verified/updated
- [ ] Installation durchgeführt - [ ] Installation completed
- [ ] SSH-Host-Key wiederhergestellt ODER neuen Key in SOPS konfiguriert - [ ] SSH host key restored OR new key configured in SOPS
- [ ] Secrets funktionieren (`sudo cat /run/secrets/...`) - [ ] Secrets are functional (`sudo cat /run/secrets/...`)
- [ ] Tailscale verbunden (`tailscale status`) - [ ] Tailscale connected (`tailscale status`)

View file

@ -1,95 +1,95 @@
# SD-Karten-Images für Raspberry Pi # SD Card Images for Raspberry Pi
Das Repository baut automatisch SD-Karten-Images für alle konfigurierten Raspberry Pi Hosts. The repository automatically builds SD card images for all configured Raspberry Pi hosts.
## Automatischer Build ## Automatic Build
Bei Änderungen an `main` werden automatisch Images für alle Pi-Hosts gebaut und als Release veröffentlicht. When changes are pushed to `main`, images are automatically built for all Pi hosts and published as a release.
**Download:** [Releases auf Forgejo](https://git.cryodev.xyz/steffen/cryodev-server/releases) **Download:** [Releases on Forgejo](https://git.cryodev.xyz/steffen/cryodev-server/releases)
## Verfügbare Images ## Available Images
| Host | Image-Name | | Host | Image Name |
|------|------------| |------|------------|
| `cryodev-pi` | `cryodev-pi-sd-image.img.zst` | | `cryodev-pi` | `cryodev-pi-sd-image.img.zst` |
Neue Hosts werden automatisch gebaut, wenn sie zur Workflow-Matrix hinzugefügt werden. New hosts are built automatically once they are added to the workflow matrix.
## Image flashen ## Flashing the Image
### 1. Herunterladen ### 1. Download
```bash ```bash
wget https://git.cryodev.xyz/.../releases/latest/download/<hostname>-sd-image.img.zst wget https://git.cryodev.xyz/.../releases/latest/download/<hostname>-sd-image.img.zst
wget https://git.cryodev.xyz/.../releases/latest/download/<hostname>-sd-image.img.zst.sha256 wget https://git.cryodev.xyz/.../releases/latest/download/<hostname>-sd-image.img.zst.sha256
# Checksum prüfen # Verify checksum
sha256sum -c <hostname>-sd-image.img.zst.sha256 sha256sum -c <hostname>-sd-image.img.zst.sha256
``` ```
### 2. Dekomprimieren ### 2. Decompress
```bash ```bash
zstd -d <hostname>-sd-image.img.zst -o <hostname>.img zstd -d <hostname>-sd-image.img.zst -o <hostname>.img
``` ```
### 3. Auf SD-Karte schreiben ### 3. Write to SD Card
```bash ```bash
# Richtiges Gerät finden # Identify the correct device
lsblk lsblk
# Schreiben (ACHTUNG: richtiges Gerät wählen!) # Write (WARNING: make sure to select the correct device!)
sudo dd if=<hostname>.img of=/dev/sdX bs=4M conv=fsync status=progress sudo dd if=<hostname>.img of=/dev/sdX bs=4M conv=fsync status=progress
``` ```
Alternativ: `balenaEtcher` oder `Raspberry Pi Imager` verwenden. Alternatively, use `balenaEtcher` or `Raspberry Pi Imager`.
## Was ist im Image? ## What Is Included in the Image?
- Vollständige NixOS-Installation für den spezifischen Host - Complete NixOS installation for the specific host
- Alle konfigurierten Services (außer Secrets) - All configured services (except secrets)
- SSH-Server aktiviert - SSH server enabled
- Automatische Root-Partition-Erweiterung beim ersten Boot - Automatic root partition expansion on first boot
- Comin für automatische Updates - Comin for automatic updates
## Was fehlt? ## What Is Missing?
**SOPS-Secrets** können nicht im Image enthalten sein (Henne-Ei-Problem mit SSH-Host-Key). **SOPS secrets** cannot be included in the image (chicken-and-egg problem with the SSH host key).
Nach dem ersten Boot: After the first boot:
1. Age-Key vom Pi holen 1. Retrieve the age key from the Pi
2. `.sops.yaml` aktualisieren 2. Update `.sops.yaml`
3. `secrets.yaml` erstellen 3. Create `secrets.yaml`
4. Konfiguration deployen 4. Deploy the configuration
Siehe [Neuen Client hinzufügen](new-client.md) für die vollständige Anleitung. See [Adding a New Client](new-client.md) for the complete guide.
## Neuen Host zur Pipeline hinzufügen ## Adding a New Host to the Pipeline
1. Host-Konfiguration in `hosts/<hostname>/` erstellen 1. Create the host configuration in `hosts/<hostname>/`
2. In `.forgejo/workflows/build-pi-image.yml` zur Matrix hinzufügen: 2. Add it to the matrix in `.forgejo/workflows/build-pi-image.yml`:
```yaml ```yaml
matrix: matrix:
host: [cryodev-pi, neuer-host] # <- hier hinzufügen host: [cryodev-pi, new-host] # <- add here
``` ```
3. Push auf `main` → Image wird automatisch gebaut 3. Push to `main` -- the image will be built automatically
## Manuell bauen ## Building Manually
```bash ```bash
# Auf aarch64 (z.B. anderem Pi) # On aarch64 (e.g., another Pi)
nix build .#nixosConfigurations.<hostname>.config.system.build.sdImage nix build .#nixosConfigurations.<hostname>.config.system.build.sdImage
# Auf x86_64 mit QEMU-Emulation (langsam) # On x86_64 with QEMU emulation (slow)
nix build .#nixosConfigurations.<hostname>.config.system.build.sdImage \ nix build .#nixosConfigurations.<hostname>.config.system.build.sdImage \
--extra-platforms aarch64-linux --extra-platforms aarch64-linux
``` ```
Voraussetzung auf x86_64: Prerequisite on x86_64:
```nix ```nix
{ {
@ -99,18 +99,18 @@ Voraussetzung auf x86_64:
## Troubleshooting ## Troubleshooting
### Workflow schlägt fehl ### Workflow Fails
- Prüfe ob `sd-image.nix` in der Host-Konfiguration importiert wird - Check whether `sd-image.nix` is imported in the host configuration
- Prüfe ob binfmt auf cryodev-main aktiviert ist - Check whether binfmt is enabled on cryodev-main
### Image bootet nicht ### Image Does Not Boot
- SD-Karte korrekt beschrieben? - Was the SD card written correctly?
- Andere SD-Karte versuchen - Try a different SD card
- Stromversorgung prüfen (min. 3A für Pi 4) - Check the power supply (minimum 3A for Pi 4)
### Kein Netzwerk ### No Network
- Ethernet-Kabel prüfen - Check the Ethernet cable
- DHCP-Server im Netzwerk? - Is there a DHCP server on the network?

View file

@ -1,33 +1,33 @@
# Cryodev NixOS Configuration Documentation # Cryodev NixOS Configuration Documentation
Willkommen zur Dokumentation der **cryodev** NixOS-Infrastruktur. Welcome to the documentation for the **cryodev** NixOS infrastructure.
## Quick Links ## Quick Links
### Getting Started ### Getting Started
- [Voraussetzungen](getting-started/prerequisites.md) - Benötigte Tools - [Prerequisites](getting-started/prerequisites.md) - Required tools
- [Neuen Raspberry Pi hinzufügen](getting-started/new-client.md) - Kompletter Workflow für neue Clients - [Adding a New Raspberry Pi](getting-started/new-client.md) - Complete workflow for new clients
- [SD-Image Referenz](getting-started/sd-image.md) - Details zum Image-Build - [SD Image Reference](getting-started/sd-image.md) - Details on image building
- [Erstinstallation (Server)](getting-started/first-install.md) - Bootstrap für x86_64 Hosts - [First Installation (Server)](getting-started/first-install.md) - Bootstrap for x86_64 hosts
- [Neuinstallation](getting-started/reinstall.md) - Reinstall mit Hardware-Änderungen - [Reinstallation](getting-started/reinstall.md) - Reinstall with hardware changes
### Services ### Services
- [SOPS Secrets](services/sops.md) - Geheimnisverwaltung mit sops-nix - [SOPS Secrets](services/sops.md) - Secret management with sops-nix
- [Headscale](services/headscale.md) - Self-hosted Tailscale Server - [Headscale](services/headscale.md) - Self-hosted Tailscale server
- [Headplane](services/headplane.md) - Web-UI für Headscale - [Headplane](services/headplane.md) - Web UI for Headscale
- [Tailscale](services/tailscale.md) - Mesh-VPN Client - [Tailscale](services/tailscale.md) - Mesh VPN client
- [Mailserver](services/mailserver.md) - E-Mail Stack (Postfix/Dovecot) - [Mailserver](services/mailserver.md) - Email stack (Postfix/Dovecot)
- [Forgejo](services/forgejo.md) - Git-Hosting mit CI/CD - [Forgejo](services/forgejo.md) - Git hosting with CI/CD
- [Netdata](services/netdata.md) - Monitoring und Alerting - [Netdata](services/netdata.md) - Monitoring and alerting
### Deployment ### Deployment
- [Continuous Deployment](deployment/cd.md) - Push- und Pull-basiertes Deployment - [Continuous Deployment](deployment/cd.md) - Push- and pull-based deployment
- [DNS-Konfiguration](deployment/dns.md) - Benötigte DNS-Einträge - [DNS Configuration](deployment/dns.md) - Required DNS records
## Architektur ## Architecture
``` ```
Internet Internet
@ -57,38 +57,38 @@ Willkommen zur Dokumentation der **cryodev** NixOS-Infrastruktur.
+-------------------+ +-------------------+
``` ```
## Installations-Szenarien ## Installation Scenarios
| Szenario | Beschreibung | Anleitung | | Scenario | Description | Guide |
|----------|--------------|-----------| |----------|-------------|-------|
| **Neuer Raspberry Pi** | Config erstellen → Image bauen → Flashen | [new-client.md](getting-started/new-client.md) | | **New Raspberry Pi** | Create config, build image, flash | [new-client.md](getting-started/new-client.md) |
| **Erstinstallation (Server)** | x86_64 Host, manuelle Installation | [first-install.md](getting-started/first-install.md) | | **First Installation (Server)** | x86_64 host, manual installation | [first-install.md](getting-started/first-install.md) |
| **Neuinstallation** | Bestehender Host, neue Hardware | [reinstall.md](getting-started/reinstall.md) | | **Reinstallation** | Existing host, new hardware | [reinstall.md](getting-started/reinstall.md) |
Für Raspberry Pi: [SD-Image Referenz](getting-started/sd-image.md) For Raspberry Pi: [SD Image Reference](getting-started/sd-image.md)
## Verzeichnisstruktur ## Directory Structure
``` ```
. .
├── flake.nix # Entry point, inputs and outputs ├── flake.nix # Entry point, inputs and outputs
├── constants.nix # Zentrale Config (Domains, IPs, Ports) ├── constants.nix # Central configuration (domains, IPs, ports)
├── hosts/ # Host-spezifische Konfigurationen ├── hosts/ # Host-specific configurations
│ ├── cryodev-main/ │ ├── cryodev-main/
│ └── cryodev-pi/ │ └── cryodev-pi/
├── modules/ # Wiederverwendbare NixOS-Module ├── modules/ # Reusable NixOS modules
│ └── nixos/ │ └── nixos/
├── pkgs/ # Eigene Pakete ├── pkgs/ # Custom packages
├── overlays/ # Nixpkgs Overlays ├── overlays/ # Nixpkgs overlays
├── templates/ # Templates für neue Hosts ├── templates/ # Templates for new hosts
├── scripts/ # Helper-Scripts (install.sh) ├── scripts/ # Helper scripts (install.sh)
├── apps/ # Nix Apps (rebuild) ├── apps/ # Nix apps (rebuild)
└── lib/ # Helper-Funktionen (utils.nix) └── lib/ # Helper functions (utils.nix)
``` ```
## Deployment-Strategien ## Deployment Strategies
| Host | Strategie | Tool | Beschreibung | | Host | Strategy | Tool | Description |
|------|-----------|------|--------------| |------|----------|------|-------------|
| `cryodev-main` | Pull-basiert | Comin | Pollt Repository auf Aenderungen | | `cryodev-main` | Pull-based | Comin | Polls the repository for changes |
| `cryodev-pi` | Pull-basiert | Comin | Pollt Repository auf Aenderungen | | `cryodev-pi` | Pull-based | Comin | Polls the repository for changes |

View file

@ -89,9 +89,9 @@ See [CD documentation](../deployment/cd.md) for details.
```bash ```bash
forgejo admin user create \ forgejo admin user create \
--username <benutzername> \ --username <username> \
--email <email>@<domain> \ --email <email>@<domain> \
--password <passwort> \ --password <password> \
--admin --admin
``` ```

View file

@ -14,9 +14,9 @@ Tailscale clients connect to the self-hosted Headscale server to join the mesh V
On the Headscale server (cryodev-main): On the Headscale server (cryodev-main):
```bash ```bash
# User-ID ermitteln # Look up user ID
sudo headscale users list sudo headscale users list
# Preauth-Key erstellen (User-ID von "default" einsetzen) # Create preauth key (use the user ID for "default")
sudo headscale preauthkeys create --expiration 99y --reusable --user <ID> sudo headscale preauthkeys create --expiration 99y --reusable --user <ID>
``` ```