Merge pull request 'develop' (#2) from develop into main
Reviewed-on: #2
This commit is contained in:
commit
33bc9f5e33
11 changed files with 1682 additions and 1439 deletions
|
|
@ -46,7 +46,7 @@ jobs:
|
||||||
--extra-platforms aarch64-linux \
|
--extra-platforms aarch64-linux \
|
||||||
--out-link result-${{ matrix.host }}
|
--out-link result-${{ matrix.host }}
|
||||||
|
|
||||||
IMAGE_PATH=$(find result-${{ matrix.host }} -name "*.img.zst" -type f | head -1)
|
IMAGE_PATH=$(find -L result-${{ matrix.host }} -name "*.img.zst" | head -1)
|
||||||
if [ -z "$IMAGE_PATH" ]; then
|
if [ -z "$IMAGE_PATH" ]; then
|
||||||
echo "Error: No image found!"
|
echo "Error: No image found!"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
231
AGENTS.md
231
AGENTS.md
|
|
@ -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
2116
digest.txt
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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`)
|
||||||
|
|
|
||||||
|
|
@ -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?
|
||||||
|
|
|
||||||
|
|
@ -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 |
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue