Add SD image pipeline, documentation overhaul, and fix module issues

- Add automatic SD image builds for Raspberry Pi via Forgejo Actions
- Enable binfmt emulation on cryodev-main for aarch64 cross-builds
- Add sd-image.nix module to cryodev-pi configuration
- Create comprehensive docs/ structure with installation guides
- Split installation docs into: first-install (server), reinstall, new-client (Pi)
- Add lib/utils.nix and apps/rebuild from synix
- Fix headplane module for new upstream API (tale/headplane)
- Fix various module issues (mailserver stateVersion, option conflicts)
- Add placeholder secrets.yaml files for both hosts
- Remove old INSTRUCTIONS.md (content moved to docs/)
This commit is contained in:
steffen 2026-03-11 08:41:58 +01:00
parent a5261d8ff0
commit 5ba78886d2
44 changed files with 3570 additions and 609 deletions

View file

@ -0,0 +1,4 @@
# Enable QEMU emulation for aarch64 to build Raspberry Pi images
{
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
}

View file

@ -1,11 +1,13 @@
{
inputs,
lib,
outputs,
...
}:
{
imports = [
./binfmt.nix
./boot.nix
./hardware.nix
./networking.nix
@ -17,5 +19,12 @@
outputs.nixosModules.nixvim
];
# Allow unfree packages (netdata has changed to gpl3Plus ncul1 license)
nixpkgs.config.allowUnfreePredicate =
pkg:
builtins.elem (lib.getName pkg) [
"netdata"
];
system.stateVersion = "25.11";
}

View file

@ -0,0 +1,18 @@
# SOPS encrypted secrets for cryodev-main
# This file should be encrypted with sops before committing
# See INSTRUCTIONS.md for setup instructions
# Placeholder - replace with actual encrypted secrets
forgejo-runner:
token: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
tailscale:
auth-key: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
headplane:
cookie_secret: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
agent_pre_authkey: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
mailserver:
accounts:
forgejo: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
admin: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
forgejo:
mail-pw: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]

View file

@ -1,6 +1,5 @@
{
config,
pkgs,
outputs,
constants,
...
@ -31,14 +30,17 @@
USER = "forgejo@${constants.domain}";
};
};
sops = true; # Enable sops integration for secrets
};
services.forgejo-runner = {
enable = true;
url = "https://${constants.services.forgejo.fqdn}";
# Token needs to be set up via sops/secrets
sops = true;
tokenFile = config.sops.secrets."forgejo-runner/token".path;
};
sops.secrets."forgejo-runner/token" = {
# gitea-runner user is created by gitea-actions-runner service
mode = "0400";
};
services.nginx.virtualHosts."${constants.services.forgejo.fqdn}" = {

View file

@ -1,6 +1,4 @@
{
config,
pkgs,
outputs,
constants,
...
@ -14,14 +12,11 @@
services.headplane = {
enable = true;
port = constants.services.headplane.port;
headscale = {
url = "http://127.0.0.1:${toString constants.services.headscale.port}";
public_url = "https://${constants.services.headscale.fqdn}";
};
# Secrets for headplane need to be configured via sops
sops.secrets = {
"headplane/cookie_secret" = { };
"headplane/agent_pre_authkey" = { };
settings = {
headscale = {
url = "http://127.0.0.1:${toString constants.services.headscale.port}";
public_url = "https://${constants.services.headscale.fqdn}";
};
};
};

View file

@ -1,6 +1,4 @@
{
config,
pkgs,
outputs,
constants,
...
@ -17,7 +15,9 @@
port = constants.services.headscale.port;
settings = {
server_url = "https://${constants.services.headscale.fqdn}";
dns_config.base_domain = constants.domain;
# dns.base_domain must be different from the server domain
# Using "tail" for internal Tailscale DNS (e.g., host.tail)
dns.base_domain = "tail";
};
};

View file

@ -1,6 +1,4 @@
{
config,
pkgs,
outputs,
constants,
...
@ -21,7 +19,9 @@
aliases = [ "postmaster" ];
};
};
certificateScheme = "acme-nginx";
sops = true;
x509.useACMEHost = constants.services.mail.fqdn;
};
# ACME certificate for mail server
security.acme.certs.${constants.services.mail.fqdn} = { };
}

View file

@ -1,5 +1,6 @@
{
inputs,
lib,
outputs,
...
}:
@ -10,12 +11,21 @@
./hardware.nix
./networking.nix
./packages.nix
./sd-image.nix
./services
./users.nix
outputs.nixosModules.common
outputs.nixosModules.nixvim
outputs.nixosModules.sops
];
# Allow unfree packages (netdata has changed to gpl3Plus ncul1 license)
nixpkgs.config.allowUnfreePredicate =
pkg:
builtins.elem (lib.getName pkg) [
"netdata"
];
system.stateVersion = "25.11";
}

View file

@ -0,0 +1,30 @@
# SD Card image configuration for Raspberry Pi
{
config,
modulesPath,
lib,
...
}:
{
imports = [
(modulesPath + "/installer/sd-card/sd-image-aarch64.nix")
];
sdImage = {
# Compress with zstd for smaller download
compressImage = true;
# Auto-expand root partition on first boot
expandOnBoot = true;
};
# Image filename based on hostname
image.fileName = "${config.networking.hostName}-sd-image.img";
# Disable ZFS to avoid build issues on SD image
boot.supportedFilesystems = lib.mkForce [
"vfat"
"ext4"
];
}

View file

@ -0,0 +1,11 @@
# SOPS encrypted secrets for cryodev-pi
# This file should be encrypted with sops before committing
# See INSTRUCTIONS.md for setup instructions
# Placeholder - replace with actual encrypted secrets
# Generate UUID with: uuidgen
netdata:
stream:
child-uuid: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]
tailscale:
auth-key: ENC[AES256_GCM,data:placeholder,tag:placeholder,type:str]

View file

@ -1,7 +1,5 @@
{
config,
pkgs,
outputs,
constants,
...
}:
@ -9,23 +7,48 @@
{
services.netdata = {
enable = true;
config = {
stream = {
enabled = "yes";
destination = "${constants.hosts.cryodev-main.ip}:${toString constants.services.netdata.port}";
"api key" = config.sops.placeholder."netdata/stream/child-uuid";
config.global = {
"debug log" = "syslog";
"access log" = "syslog";
"error log" = "syslog";
};
configDir = {
"stream.conf" = config.sops.templates."netdata/stream.conf".path;
};
};
sops =
let
owner = config.services.netdata.user;
group = config.services.netdata.group;
mode = "0400";
restartUnits = [ "netdata.service" ];
in
{
# generate with `uuidgen`
secrets."netdata/stream/child-uuid" = {
inherit
owner
group
mode
restartUnits
;
};
templates."netdata/stream.conf" = {
inherit
owner
group
mode
restartUnits
;
# child node
content = ''
[stream]
enabled = yes
destination = ${constants.hosts.cryodev-main.ip}:${builtins.toString constants.services.netdata.port}
api key = ${config.sops.placeholder."netdata/stream/child-uuid"}
'';
};
};
};
# Make sure sops is enabled/imported for this host to handle the secret
imports = [ outputs.nixosModules.sops ];
sops = {
defaultSopsFile = ../secrets.yaml;
secrets."netdata/stream/child-uuid" = {
owner = "netdata";
group = "netdata";
};
};
}