add aspects/hosts/ configurations

Host-specific NixOS configurations for:
- alexandria (server)
- io (desktop)
- rotterdam (desktop)
- trantor (server, aarch64)

Each host has a main config file and _hostname/ directory
with hardware-configuration and other host-specific modules.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
William 2026-02-06 22:36:50 -03:00
parent ad0aa14d14
commit 25c69e3c18
30 changed files with 1298 additions and 0 deletions

View file

@ -0,0 +1,6 @@
{
boot = {
initrd.systemd.enable = true;
loader.efi.efiSysMountPoint = "/boot/efi";
};
}

View file

@ -0,0 +1,64 @@
{ inputs, ... }:
{
imports = [ inputs.disko.nixosModules.default ];
disko.devices.disk.main = {
type = "disk";
device = "/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20";
content = {
type = "gpt";
partitions = {
ESP = {
priority = 1;
name = "ESP";
start = "1MiB";
end = "512MiB";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot/efi";
mountOptions = [
"noatime"
"fmask=0077"
"dmask=0077"
];
};
};
root = {
priority = 2;
name = "root";
size = "100%";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"@root" = {
mountpoint = "/";
mountOptions = [
"noatime"
"compress=zstd"
];
};
"@nix" = {
mountpoint = "/nix";
mountOptions = [
"noatime"
"compress=zstd"
];
};
"@persistent" = {
mountpoint = "/persistent";
mountOptions = [
"noatime"
"compress=zstd"
];
};
};
};
};
};
};
};
}

View file

@ -0,0 +1,23 @@
{ config, pkgs, ... }:
{
services.fail2ban = {
enable = true;
maxretry = 5;
ignoreIP = [
"127.0.0.0/8"
"::1"
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
"100.64.0.0/10"
];
bantime = "1h";
bantime-increment = {
enable = true;
multipliers = "1 2 4 8 16 32 64";
maxtime = "10000h";
overalljails = true;
};
};
}

View file

@ -0,0 +1,72 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services = {
forgejo = {
enable = true;
settings = {
session.COOKIE_SECURE = true;
server = {
PROTOCOL = "http+unix";
DOMAIN = "git.baduhai.dev";
ROOT_URL = "https://git.baduhai.dev";
OFFLINE_MODE = true; # disable use of CDNs
SSH_DOMAIN = "git.baduhai.dev";
};
log.LEVEL = "Warn";
mailer.ENABLED = false;
actions.ENABLED = false;
service.DISABLE_REGISTRATION = true;
oauth2_client = {
ENABLE_AUTO_REGISTRATION = true;
UPDATE_AVATAR = true;
ACCOUNT_LINKING = "login";
USERNAME = "preferred_username";
};
};
};
nginx.virtualHosts = mkNginxVHosts {
domains."git.baduhai.dev".locations."/".proxyPass =
"http://unix:${config.services.forgejo.settings.server.HTTP_ADDR}:/";
};
fail2ban.jails.forgejo = {
settings = {
enabled = true;
filter = "forgejo";
maxretry = 3;
findtime = "10m";
bantime = "1h";
};
};
};
environment = {
etc."fail2ban/filter.d/forgejo.conf".text = ''
[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =
journalmatch = _SYSTEMD_UNIT=forgejo.service
'';
persistence.main.directories = [
{
directory = config.services.forgejo.stateDir;
inherit (config.services.forgejo) user group;
mode = "0700";
}
];
};
# Disable PrivateMounts to allow LoadCredential to work with bind-mounted directories
systemd.services.forgejo.serviceConfig.PrivateMounts = lib.mkForce false;
}

View file

@ -0,0 +1,20 @@
{
lib,
modulesPath,
...
}:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.initrd.availableKernelModules = [
"xhci_pci"
"virtio_pci"
"virtio_scsi"
"usbhid"
];
networking.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
}

View file

@ -0,0 +1,8 @@
{
networking = {
firewall = {
allowedTCPPorts = [ 25566 ];
allowedUDPPorts = [ 25566 ];
};
};
}

View file

@ -0,0 +1,61 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts services;
# Get all unique domains from shared services on trantor (host = "trantor")
localDomains = lib.unique (
map (s: s.domain) (lib.filter (s: s.host == "trantor") services)
);
# Generate ACME cert configs for all local domains
acmeCerts = lib.genAttrs localDomains (domain: {
group = "nginx";
});
in
{
security.acme = {
acceptTerms = true;
defaults = {
email = "baduhai@proton.me";
dnsResolver = "1.1.1.1:53";
dnsProvider = "cloudflare";
credentialsFile = config.age.secrets.cloudflare.path;
};
certs = acmeCerts;
};
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts = {
"_" = {
default = true;
locations."/".return = "444";
};
};
};
users.users.nginx.extraGroups = [ "acme" ];
networking.firewall.allowedTCPPorts = [
80
443
];
age.secrets.cloudflare = {
file = ../../../secrets/cloudflare.age;
owner = "nginx";
group = "nginx";
};
}

View file

@ -0,0 +1,23 @@
{ ... }:
{
services = {
openssh = {
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
};
};
fail2ban.jails.sshd = {
settings = {
enabled = true;
port = "ssh";
filter = "sshd";
logpath = "/var/log/auth.log";
maxretry = 3;
findtime = "10m";
bantime = "1h";
};
};
};
}

View file

@ -0,0 +1,58 @@
{ inputs, lib, ... }:
let
utils = import ../../../utils.nix { inherit inputs lib; };
in
{
services.unbound = {
enable = true;
enableRootTrustAnchor = true;
settings = {
server = {
interface = [
"0.0.0.0"
"::"
];
access-control = [
"127.0.0.0/8 allow"
"100.64.0.0/10 allow" # Tailscale CGNAT range
"::1/128 allow"
"fd7a:115c:a1e0::/48 allow" # Tailscale IPv6
];
num-threads = 2;
msg-cache-size = "50m";
rrset-cache-size = "100m";
cache-min-ttl = 300;
cache-max-ttl = 86400;
prefetch = true;
prefetch-key = true;
hide-identity = true;
hide-version = true;
so-rcvbuf = "1m";
so-sndbuf = "1m";
# Tailnet DNS records from shared services
local-zone = ''"baduhai.dev." transparent'';
local-data = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') utils.services;
};
forward-zone = [
{
name = ".";
forward-addr = [
"1.1.1.1@853#cloudflare-dns.com"
"1.0.0.1@853#cloudflare-dns.com"
];
forward-tls-upstream = true;
}
];
};
};
networking.firewall = {
allowedTCPPorts = [ 53 ];
allowedUDPPorts = [ 53 ];
};
}