Flake lock file updates:
• Updated input 'authentik':
'github:nix-community/authentik-nix/7e4730351fb6df479c46a1bf7e23d46a0b0c5d46?narHash=sha256-hcstQ1Z9aQSJM3AVCLb0/OPTicbME9nhP01GiPrOjZM%3D' (2026-03-07)
→ 'github:nix-community/authentik-nix/4370b561c8bafb59773ce3a518506bcf1161dbdb?narHash=sha256-JvvWVbXJYSY8qOReMbAOD4lxcN2cjKV6lg/jLz8CEuY%3D' (2026-04-13)
• Updated input 'authentik/authentik-src':
'github:goauthentik/authentik/0dccbd4193c45c581e9fb7cd89df0c1487510f1f?narHash=sha256-0Vpf1hj9C8r%2BrhrCgwoNazpQ%2BmwgjdjDhuoKCxYQFWw%3D' (2026-03-03)
→ 'github:goauthentik/authentik/5249546862986202b901c2afd860992ec48c6ef6?narHash=sha256-Xq7JGI/8ppIydIuWd9KRJKUrh7UpeniwvZ4NAtXbYJ4%3D' (2026-04-07)
• Updated input 'disko':
'github:nix-community/disko/7b9f7f88ab3b339f8142dc246445abb3c370d3d3?narHash=sha256-khlHllTsovXgT2GZ0WxT4%2BRvuMjNeR5OW0UYeEHPYQo%3D' (2026-03-09)
→ 'github:nix-community/disko/32f4236bfc141ae930b5ba2fb604f561fed5219d?narHash=sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI%3D' (2026-04-19)
• Updated input 'mailserver':
'git+https://gitlab.com/simple-nixos-mailserver/nixos-mailserver?ref=nixos-25.11&rev=9cdd6869e513df8153db4b920c8f15d394e150f7' (2026-03-12)
→ 'git+https://gitlab.com/simple-nixos-mailserver/nixos-mailserver?ref=nixos-25.11&rev=25e6dbb8fca3b6e779c5a46fd03bd760b2165bb5' (2026-03-19)
• Updated input 'mailserver/flake-compat':
'github:edolstra/flake-compat/f387cd2afec9419c8ee37694406ca490c3f34ee5?narHash=sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4%3D' (2025-10-27)
→ 'github:edolstra/flake-compat/5edf11c44bc78a0d334f6334cdaf7d60d732daab?narHash=sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns%3D' (2025-12-29)
• Updated input 'mailserver/git-hooks':
'github:cachix/git-hooks.nix/7275fa67fbbb75891c16d9dee7d88e58aea2d761?narHash=sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA%3D' (2025-11-16)
→ 'github:cachix/git-hooks.nix/8baab586afc9c9b57645a734c820e4ac0a604af9?narHash=sha256-JDqZMgxUTCq85ObSaFw0HhE%2BlvdOre1lx9iI6vYyOEs%3D' (2026-03-07)
• Updated input 'mailserver/nixpkgs':
'github:NixOS/nixpkgs/a320ce8e6e2cc6b4397eef214d202a50a4583829?narHash=sha256-6zddwDs2n%2Bn01l%2B1TG6PlyokDdXzu/oBmEejcH5L5%2BA%3D' (2025-11-24)
→ 'github:NixOS/nixpkgs/826430a188181a750ffa5948daff334039c5d741?narHash=sha256-JW2/QPyCVzmouqEp1H9kNa8JXd7xEhlam9sy3TYfhDY%3D' (2026-03-18)
• Updated input 'nixpkgs':
'github:nixos/nixpkgs/0590cd39f728e129122770c029970378a79d076a?narHash=sha256-BHoB/XpbqoZkVYZCfXJXfkR%2BGXFqwb/4zbWnOr2cRcU%3D' (2026-03-11)
→ 'github:nixos/nixpkgs/10e7ad5bbcb421fe07e3a4ad53a634b0cd57ffac?narHash=sha256-vl3dkhlE5gzsItuHoEMVe%2BDlonsK%2B0836LIRDnm6MXQ%3D' (2026-04-21)
• Updated input 'sops':
'github:Mic92/sops-nix/d1ff3b1034d5bab5d7d8086a7803c5a5968cd784?narHash=sha256-M3zEnq9OElB7zqc%2BmjgPlByPm1O5t2fbUrH3t/Hm5Ag%3D' (2026-03-09)
→ 'github:Mic92/sops-nix/bef289e2248991f7afeb95965c82fbcd8ff72598?narHash=sha256-DRFGPfFV6hbrfO9a1PH1FkCi7qR5FgjSqsQGGvk1rdI%3D' (2026-04-21)
|
||
|---|---|---|
| docs | ||
| hosts | ||
| keys | ||
| modules | ||
| .gitignore | ||
| .sops.yaml | ||
| default.nix | ||
| flake.lock | ||
| flake.nix | ||
| hardware-configuration.nix | ||
| hetzner-disk.nix | ||
| README.md | ||
StuRa HTW Dresden Infrastructure - NixOS Configuration
Declarative infrastructure management for StuRa HTW Dresden using NixOS and a flake-based configuration. This repository replaces the hand-configured FreeBSD relay system with a modern, reproducible infrastructure.
Architecture
Overview
This infrastructure uses a flake-based approach with automatic host discovery:
- Centralized reverse proxy: HAProxy at 141.56.51.1 routes all traffic via SNI inspection and HTTP host headers
- IPv6 gateway: Hetzner VPS at 2a01:4f8:1c19:96f8::1 forwards IPv6 traffic to the IPv4 proxy
- Automatic host discovery: Each subdirectory in
hosts/becomes a NixOS configuration viabuiltins.readDir - Global configuration: Settings in
default.nixare automatically applied to all hosts - ACME certificates: All services use Let's Encrypt certificates managed locally on each host
Network
- Network: 141.56.51.0/24
- Gateway: 141.56.51.254
- DNS: 141.56.1.1, 141.56.1.2 (HTW internal)
- Domain: htw.stura-dresden.de
Repository Structure
stura-infra/
├── flake.nix # Main flake configuration with auto-discovery
├── default.nix # Global settings applied to all hosts
├── hosts/ # Host-specific configurations
│ ├── proxy/ # Central reverse proxy (HAProxy)
│ │ ├── default.nix
│ │ ├── hardware-configuration.nix
│ │ ├── hetzner-disk.nix
│ │ └── README.md
│ ├── v6proxy/ # IPv6 gateway (Hetzner VPS)
│ │ ├── default.nix
│ │ ├── hardware-configuration.nix
│ │ ├── hetzner-disk.nix
│ │ └── README.md
│ ├── git/ # Forgejo git server
│ │ └── default.nix
│ ├── wiki/ # MediaWiki instance
│ │ └── default.nix
│ ├── nextcloud/ # Nextcloud instance
│ │ └── default.nix
│ └── redmine/ # Redmine project management
│ └── default.nix
└── README.md # This file
Host Overview
| Host | IP | Type | Services | Documentation |
|---|---|---|---|---|
| proxy | 141.56.51.1 | VM | HAProxy, SSH Jump | hosts/proxy/README.md |
| v6proxy | 178.104.18.93 (IPv4) 2a01:4f8:1c19:96f8::1 (IPv6) |
Hetzner VPS | HAProxy (IPv6 Gateway) | hosts/v6proxy/README.md |
| git | 141.56.51.7 | LXC | Forgejo, Nginx | hosts/git/README.md |
| wiki | 141.56.51.13 | LXC | MediaWiki, MariaDB, Apache | hosts/wiki/README.md |
| redmine | 141.56.51.15 | LXC | Redmine, Nginx | hosts/redmine/README.md |
| nextcloud | 141.56.51.16 | LXC | Nextcloud, PostgreSQL, Redis, Nginx | hosts/nextcloud/README.md |
Deployment Methods
Method 1: Initial Installation with nixos-anywhere (Recommended)
Use nixos-anywhere for initial system installation. This handles disk partitioning (via disko) and bootstrapping automatically.
For VM hosts (proxy):
nix run github:nix-community/nixos-anywhere -- --flake .#proxy --target-host root@141.56.51.1
For LXC containers (git, wiki, redmine, nextcloud):
nix run github:nix-community/nixos-anywhere -- --flake .#git --target-host root@141.56.51.7
This method is ideal for:
- First-time installation on bare metal or fresh VMs
- Complete system rebuilds
- Migration to new hardware
Method 2: Container Tarball Deployment to Proxmox
Build and deploy LXC container tarballs for git, wiki, redmine, and nextcloud hosts.
Step 1: Build container tarball locally
nix build .#containers-git
# Result will be in result/tarball/nixos-system-x86_64-linux.tar.xz
Step 2: Copy to Proxmox host
scp result/tarball/nixos-system-x86_64-linux.tar.xz root@proxmox-host:/var/lib/vz/template/cache/
Step 3: Create container on Proxmox
# Example for git host (container ID 107, adjust as needed)
pct create 107 /var/lib/vz/template/cache/nixos-system-x86_64-linux.tar.xz \
--hostname git \
--net0 name=eth0,bridge=vmbr0,ip=141.56.51.7/24,gw=141.56.51.254 \
--memory 2048 \
--cores 2 \
--rootfs local-lvm:8 \
--unprivileged 1 \
--features nesting=1
# Configure storage and settings via Proxmox web interface if needed
Step 4: Start container
pct start 107
Step 5: Post-deployment configuration
- Access container:
pct enter 107 - Follow host-specific post-deployment steps in each host's README.md
Available container tarballs:
nix build .#containers-gitnix build .#containers-wikinix build .#containers-redminenix build .#containers-nextcloud
Note: The proxy host is a full VM and does not have a container tarball. Use Method 1 or 3 for proxy deployment.
Method 3: ISO Installer
Build a bootable ISO installer for manual installation on VMs or bare metal.
Build ISO:
nix build .#installer-iso
# Result will be in result/iso/nixos-*.iso
Build VM for testing:
nix build .#installer-vm
Deployment:
- Upload ISO to Proxmox storage
- Create VM and attach ISO as boot device
- Boot VM and follow installation prompts
- Run installation commands manually
- Reboot and remove ISO
Method 4: Regular Updates
For already-deployed systems, apply configuration updates:
Option A: Using nixos-rebuild from your local machine
nixos-rebuild switch --flake .#<hostname> --target-host root@<ip>
Example:
nixos-rebuild switch --flake .#proxy --target-host root@141.56.51.1
Note: This requires an SSH config entry for the proxy (uses port 1005):
# ~/.ssh/config
Host 141.56.51.1
Port 1005
Option B: Using auto-generated update scripts
The flake generates convenience scripts for each host:
nix run .#git-update
nix run .#wiki-update
nix run .#redmine-update
nix run .#nextcloud-update
nix run .#proxy-update
These scripts automatically extract the target IP from the configuration.
Option C: Remote execution (no local Nix installation)
If Nix isn't installed locally, run the command on the target system:
ssh root@141.56.51.1 "nixos-rebuild switch --flake git+https://codeberg.org/stura-htw-dresden/stura-infra#proxy"
Replace proxy with the appropriate hostname and adjust the IP address.
Required DNS Records
The following DNS records must be configured for the current infrastructure:
| Name | Type | IP | Service |
|---|---|---|---|
| *.htw.stura-dresden.de | CNAME | proxy.htw.stura-dresden.de | Reverse proxy |
| proxy.htw.stura-dresden.de | A | 141.56.51.1 | Proxy IPv4 |
| proxy.htw.stura-dresden.de | AAAA | 2a01:4f8:1c19:96f8::1 | IPv6 Gateway (v6proxy) |
Note: All public services point to the proxy IPs. The IPv4 proxy (141.56.51.1) handles SNI-based routing to backend hosts. The IPv6 gateway (v6proxy at 2a01:4f8:1c19:96f8::1) forwards all IPv6 traffic to the IPv4 proxy. Backend IPs are internal and not exposed in DNS.
Additional services managed by the proxy (not in this repository):
- stura.htw-dresden.de → Plone
- tix.htw.stura-dresden.de → Pretix
- vot.htw.stura-dresden.de → OpenSlides
- mail.htw.stura-dresden.de → Mail server
Development
Code Formatting
Format all Nix files using the RFC-style formatter:
nix fmt
Testing Changes
Before deploying to production:
- Test flake evaluation:
nix flake check - Build configurations locally:
nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel - Review generated configurations
- Deploy to test systems first if available
Adding a New Host
-
Create host directory:
mkdir hosts/newhostname -
Create
hosts/newhostname/default.nix:{ config, lib, pkgs, modulesPath, ... }: { imports = [ "${modulesPath}/virtualisation/proxmox-lxc.nix" # For LXC containers # Or for VMs: # ./hardware-configuration.nix ]; networking = { hostName = "newhostname"; interfaces.eth0.ipv4.addresses = [{ # or ens18 for VMs address = "141.56.51.XXX"; prefixLength = 24; }]; defaultGateway.address = "141.56.51.254"; firewall.allowedTCPPorts = [ 80 443 ]; }; # Add your services here services.nginx.enable = true; # ... system.stateVersion = "25.11"; } -
The flake automatically discovers the new host via
builtins.readDir ./hosts -
If the host runs nginx, the proxy automatically adds forwarding rules (you still need to add DNS records)
-
Deploy:
nix run github:nix-community/nixos-anywhere -- --flake .#newhostname --target-host root@141.56.51.XXX
Repository Information
- Repository: https://codeberg.org/stura-htw-dresden/stura-infra
- ACME Email: cert@stura.htw-dresden.de
- NixOS Version: 25.11
- Architecture: x86_64-linux
Flake Inputs
nixpkgs: NixOS 25.11authentik: Identity provider (nix-community/authentik-nix)mailserver: Simple NixOS mailserver (nixos-25.11 branch)sops: Secret management (Mic92/sops-nix)disko: Declarative disk partitioning
Common Patterns
Network Configuration
All hosts follow this pattern:
networking = {
hostName = "<name>";
interfaces.<interface>.ipv4.addresses = [{
address = "<ip>";
prefixLength = 24;
}];
defaultGateway.address = "141.56.51.254";
};
- LXC containers use
eth0 - VMs/bare metal typically use
ens18
Nginx + ACME Pattern
For web services:
services.nginx = {
enable = true;
virtualHosts."<fqdn>" = {
forceSSL = true;
enableACME = true;
locations."/" = {
# service config
};
};
};
This automatically:
- Integrates with the proxy's ACME challenge forwarding
- Generates HAProxy backend configuration
- Requests Let's Encrypt certificates
Firewall Rules
Hosts only need to allow traffic from the proxy:
networking.firewall.allowedTCPPorts = [ 80 443 ];
SSH ports vary:
- Proxy: port 1005 (admin access)
- Other hosts: port 22 (default)