I tried going all in on dendritic, but I think I'm gonna go for a lighter approach

This commit is contained in:
William 2026-02-05 22:07:51 -03:00
parent a4698d2a62
commit 1a586c2d90
97 changed files with 240 additions and 3899 deletions

View file

@ -1,48 +0,0 @@
{ inputs, self, ... }:
{
flake.deploy = {
remoteBuild = true;
nodes = {
alexandria = {
hostname = "alexandria";
profiles.system = {
sshUser = "user";
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.alexandria;
user = "root";
};
};
trantor = {
hostname = "trantor";
profiles.system = {
sshUser = "user";
path = inputs.deploy-rs.lib.aarch64-linux.activate.nixos self.nixosConfigurations.trantor;
user = "root";
};
};
io = {
hostname = "io";
profiles = {
system = {
sshUser = "user";
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.io;
user = "root";
remoteBuild = false;
};
user = {
sshUser = "user";
path = inputs.deploy-rs.lib.x86_64-linux.activate.home-manager self.homeConfigurations."user@io";
user = "user";
remoteBuild = false;
};
};
};
};
};
perSystem =
{ system, ... }:
{
checks = inputs.deploy-rs.lib.${system}.deployChecks self.deploy;
};
}

View file

@ -1,16 +0,0 @@
{ inputs, ... }:
{
perSystem =
{ pkgs, system, ... }:
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
inputs.agenix.packages.${system}.default
deploy-rs
nil
nixfmt
];
};
};
}

View file

@ -24,8 +24,6 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
stylix.url = "github:danth/stylix";
nixos-cli.url = "github:nix-community/nixos-cli"; nixos-cli.url = "github:nix-community/nixos-cli";
nix-flatpak.url = "github:gmodena/nix-flatpak/main"; nix-flatpak.url = "github:gmodena/nix-flatpak/main";
@ -38,8 +36,6 @@
niri-flake.url = "github:sodiboo/niri-flake"; niri-flake.url = "github:sodiboo/niri-flake";
niri.url = "github:baduhai/niri/auto-center-when-space-available";
nix-index-database = { nix-index-database = {
url = "github:nix-community/nix-index-database"; url = "github:nix-community/nix-index-database";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";

View file

@ -1,43 +0,0 @@
{ inputs, ... }:
let
lib = inputs.nixpkgs.lib;
utils = import ./utils.nix { inherit inputs lib; };
inherit (utils) mkHome;
in
{
flake.homeConfigurations = {
"user@rotterdam" = mkHome {
username = "user";
hostname = "rotterdam";
tags = [
"desktop"
"btop"
"comma"
"direnv"
"gaming"
"helix"
"obs-studio"
"starship"
"stylix"
"tmux"
];
};
"user@io" = mkHome {
username = "user";
hostname = "io";
tags = [
"desktop"
"btop"
"comma"
"direnv"
"helix"
"starship"
"stylix"
"tmux"
];
};
};
}

View file

@ -1,49 +0,0 @@
{
config,
lib,
modulesPath,
...
}:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot = {
initrd = {
availableKernelModules = [
"xhci_pci"
"ahci"
"usbhid"
"usb_storage"
"sd_mod"
];
kernelModules = [ ];
};
kernelModules = [ "kvm-intel" ];
extraModulePackages = [ ];
};
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/31289617-1d84-4432-a833-680b52e88525";
fsType = "ext4";
};
"/boot" = {
device = "/dev/disk/by-uuid/4130-BE54";
fsType = "vfat";
};
};
swapDevices = [
{
device = "/swapfile";
size = 8192;
}
];
networking.useDHCP = lib.mkDefault true;
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -1,15 +0,0 @@
{ lib, inputs, ... }:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services.jellyfin = {
enable = true;
openFirewall = true;
};
services.nginx.virtualHosts = mkNginxVHosts {
domains."jellyfin.baduhai.dev".locations."/".proxyPass = "http://127.0.0.1:8096/";
};
}

View file

@ -1,83 +0,0 @@
{
config,
lib,
inputs,
pkgs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
kanidmCertDir = "/var/lib/kanidm/certs";
in
{
services.kanidm = {
enableServer = true;
enableClient = true;
package = pkgs.kanidm;
serverSettings = {
domain = "auth.baduhai.dev";
origin = "https://auth.baduhai.dev";
bindaddress = "127.0.0.1:8443";
ldapbindaddress = "127.0.0.1:636";
trust_x_forward_for = true;
# Use self-signed certificates for internal TLS
tls_chain = "${kanidmCertDir}/cert.pem";
tls_key = "${kanidmCertDir}/key.pem";
};
clientSettings = {
uri = "https://auth.baduhai.dev";
};
};
services.nginx.virtualHosts = mkNginxVHosts {
domains."auth.baduhai.dev" = {
locations."/" = {
proxyPass = "https://127.0.0.1:8443";
extraConfig = ''
proxy_ssl_verify off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
'';
};
};
};
networking.firewall.allowedTCPPorts = [ 636 ];
# Generate self-signed certificates for kanidm's internal TLS
systemd.services.kanidm-generate-certs = {
description = "Generate self-signed TLS certificates for Kanidm";
wantedBy = [ "multi-user.target" ];
before = [ "kanidm.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mkdir -p ${kanidmCertDir}
if [ ! -f ${kanidmCertDir}/key.pem ]; then
${pkgs.openssl}/bin/openssl req -x509 -newkey rsa:4096 \
-keyout ${kanidmCertDir}/key.pem \
-out ${kanidmCertDir}/cert.pem \
-days 3650 -nodes \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
chown -R kanidm:kanidm ${kanidmCertDir}
chmod 600 ${kanidmCertDir}/key.pem
chmod 644 ${kanidmCertDir}/cert.pem
fi
'';
};
# Ensure certificate generation runs before kanidm starts
systemd.services.kanidm = {
after = [ "kanidm-generate-certs.service" ];
wants = [ "kanidm-generate-certs.service" ];
};
}

View file

@ -1,97 +0,0 @@
{
lib,
config,
pkgs,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services = {
nextcloud = {
enable = true;
package = pkgs.nextcloud32;
datadir = "/data/nextcloud";
hostName = "cloud.baduhai.dev";
configureRedis = true;
https = true;
secretFile = config.age.secrets."nextcloud-secrets.json".path;
database.createLocally = true;
maxUploadSize = "16G";
extraApps = {
inherit (config.services.nextcloud.package.packages.apps)
calendar
contacts
notes
tasks
user_oidc
;
};
extraAppsEnable = true;
caching = {
apcu = true;
redis = true;
};
settings = {
trusted_proxies = [ "127.0.0.1" ];
default_phone_region = "BR";
maintenance_window_start = "4";
allow_local_remote_servers = true;
enabledPreviewProviders = [
"OC\\Preview\\BMP"
"OC\\Preview\\EMF"
"OC\\Preview\\Font"
"OC\\Preview\\GIF"
"OC\\Preview\\HEIC"
"OC\\Preview\\Illustrator"
"OC\\Preview\\JPEG"
"OC\\Preview\\Krita"
"OC\\Preview\\MarkDown"
"OC\\Preview\\Movie"
"OC\\Preview\\MP3"
"OC\\Preview\\MSOffice2003"
"OC\\Preview\\MSOffice2007"
"OC\\Preview\\MSOfficeDoc"
"OC\\Preview\\OpenDocument"
"OC\\Preview\\PDF"
"OC\\Preview\\Photoshop"
"OC\\Preview\\PNG"
"OC\\Preview\\Postscript"
"OC\\Preview\\SVG"
"OC\\Preview\\TIFF"
"OC\\Preview\\TXT"
"OC\\Preview\\XBitmap"
];
};
config = {
dbtype = "pgsql";
adminpassFile = config.age.secrets.nextcloud-adminpass.path;
};
phpOptions = {
"opcache.interned_strings_buffer" = "16";
};
};
nginx.virtualHosts = mkNginxVHosts {
domains."cloud.baduhai.dev" = { };
};
};
age.secrets = {
"nextcloud-secrets.json" = {
file = ../../secrets/nextcloud-secrets.json.age;
owner = "nextcloud";
group = "nextcloud";
};
nextcloud-adminpass = {
file = ../../secrets/nextcloud-adminpass.age;
owner = "nextcloud";
group = "nextcloud";
};
};
}

View file

@ -1,59 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts services;
# Get all unique domains from shared services that have LAN IPs (served by this host)
localDomains = lib.unique (map (s: s.domain) (lib.filter (s: s.host == "alexandria") 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

@ -1,58 +0,0 @@
{ 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"
"192.168.0.0/16 allow"
"::1/128 allow"
];
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";
# LAN-only DNS records
local-zone = ''"baduhai.dev." transparent'';
local-data = map (e: ''"${e.domain}. IN A ${e.lanIP}"'')
(lib.filter (e: e ? lanIP) 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 ];
};
}

View file

@ -1,26 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
utils = import ../../utils.nix { inherit inputs lib; };
inherit (utils) mkNginxVHosts;
in
{
services.vaultwarden = {
enable = true;
config = {
DOMAIN = "https://pass.baduhai.dev";
SIGNUPS_ALLOWED = false;
ROCKET_ADDRESS = "127.0.0.1";
ROCKET_PORT = 58222;
};
};
services.nginx.virtualHosts = mkNginxVHosts {
domains."pass.baduhai.dev".locations."/".proxyPass =
"http://${config.services.vaultwarden.config.ROCKET_ADDRESS}:${toString config.services.vaultwarden.config.ROCKET_PORT}/";
};
}

View file

@ -1,14 +0,0 @@
{
boot = {
# TODO check if future kernel versions fix boot issue with systemd initrd with tpm
initrd.systemd.tpm2.enable = false;
kernelParams = [
"nosgx"
"i915.fastboot=1"
"mem_sleep_default=deep"
];
extraModprobeConfig = ''
options snd-intel-dspcfg dsp_driver=3
'';
};
}

View file

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

View file

@ -1,37 +0,0 @@
{
config,
lib,
modulesPath,
inputs,
...
}:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot = {
initrd = {
availableKernelModules = [
"xhci_pci"
"ahci"
"usb_storage"
"sd_mod"
"sdhci_pci"
];
};
kernelModules = [ "kvm-intel" ];
};
zramSwap = {
enable = true;
memoryPercent = 100;
};
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
networking.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -1,27 +0,0 @@
{ pkgs, ... }:
let
cml-ucm-conf = pkgs.alsa-ucm-conf.overrideAttrs {
wttsrc = pkgs.fetchFromGitHub {
owner = "WeirdTreeThing";
repo = "chromebook-ucm-conf";
rev = "b6ce2a7";
hash = "sha256-QRUKHd3RQmg1tnZU8KCW0AmDtfw/daOJ/H3XU5qWTCc=";
};
postInstall = ''
echo "v0.4.1" > $out/chromebook.patched
cp -R $wttsrc/{common,codecs,platforms} $out/share/alsa/ucm2
cp -R $wttsrc/{cml,sof-rt5682} $out/share/alsa/ucm2/conf.d
'';
};
in
{
environment = {
systemPackages = with pkgs; [
maliit-keyboard
sof-firmware
];
sessionVariables.ALSA_CONFIG_UCM2 = "${cml-ucm-conf}/share/alsa/ucm2";
};
}

View file

@ -1,61 +0,0 @@
{ pkgs, ... }:
{
services = {
keyd = {
enable = true;
keyboards.main = {
ids = [ "0001:0001" ];
settings = {
main = {
meta = "overload(meta, esc)";
f1 = "back";
f2 = "forward";
f3 = "refresh";
f4 = "M-f11";
f5 = "M-w";
f6 = "brightnessdown";
f7 = "brightnessup";
f8 = "timeout(mute, 200, micmute)";
f9 = "play";
f10 = "timeout(nextsong, 200, previoussong)";
f13 = "delete";
"102nd" = "layer(function)";
};
shift = {
leftshift = "capslock";
rightshift = "capslock";
};
function = {
escape = "f1";
f1 = "f2";
f2 = "f3";
f3 = "f4";
f4 = "f5";
f5 = "f6";
f6 = "f7";
f7 = "f8";
f8 = "f9";
f9 = "f10";
f10 = "f11";
f13 = "f12";
y = "sysrq";
k = "home";
l = "pageup";
"," = "end";
"." = "pagedown";
};
};
};
};
upower.enable = true;
power-profiles-daemon.enable = true;
};
# TODO: remove once gmodena/nix-flatpak/issues/45 fixed
systemd.services."flatpak-managed-install" = {
serviceConfig = {
ExecStartPre = "${pkgs.coreutils}/bin/sleep 5";
};
};
}

View file

@ -1,11 +0,0 @@
{ inputs, pkgs, ... }:
{
environment.systemPackages =
(with pkgs; [claude-desktop]) ++
(with inputs.nix-ai-tools.packages.${pkgs.system}; [
claude-code
claudebox
opencode
]);
}

View file

@ -1,5 +0,0 @@
{ ... }:
{
hardware.bluetooth.enable = true;
}

View file

@ -1,20 +0,0 @@
{ pkgs, ... }:
{
boot = {
loader = {
timeout = 1;
efi.canTouchEfiVariables = true;
systemd-boot = {
enable = true;
editor = false;
consoleMode = "max";
sortKey = "aa";
netbootxyz = {
enable = true;
sortKey = "zz";
};
};
};
};
}

View file

@ -1,8 +0,0 @@
{ ... }:
{
console = {
useXkbConfig = true;
earlySetup = true;
};
}

View file

@ -1,8 +0,0 @@
{ ... }:
{
networking = {
firewall.enable = true;
nftables.enable = true;
};
}

View file

@ -1,21 +0,0 @@
{ ... }:
{
time.timeZone = "America/Bahia";
i18n = {
defaultLocale = "en_US.UTF-8";
extraLocaleSettings = {
LC_ADDRESS = "pt_BR.utf8";
LC_COLLATE = "pt_BR.utf8";
LC_IDENTIFICATION = "pt_BR.utf8";
LC_MEASUREMENT = "pt_BR.utf8";
LC_MONETARY = "pt_BR.utf8";
LC_NAME = "pt_BR.utf8";
LC_NUMERIC = "pt_BR.utf8";
LC_PAPER = "pt_BR.utf8";
LC_TELEPHONE = "pt_BR.utf8";
LC_TIME = "en_IE.utf8";
};
};
}

View file

@ -1,38 +0,0 @@
{ inputs, ... }:
{
imports = [ inputs.nixos-cli.nixosModules.nixos-cli ];
nix = {
settings = {
auto-optimise-store = true;
connect-timeout = 10;
log-lines = 25;
min-free = 128000000;
max-free = 1000000000;
trusted-users = [ "@wheel" ];
};
extraOptions = "experimental-features = nix-command flakes";
gc = {
automatic = true;
options = "--delete-older-than 8d";
};
};
nixpkgs.config = {
allowUnfree = true;
enableParallelBuilding = true;
buildManPages = false;
buildDocs = false;
};
services.nixos-cli = {
enable = true;
config = {
use_nvd = true;
ignore_dirty_tree = true;
};
};
system.stateVersion = "22.11";
}

View file

@ -1,11 +0,0 @@
{ ... }:
{
services.openssh = {
enable = true;
settings.PermitRootLogin = "no";
extraConfig = ''
PrintLastLog no
'';
};
}

View file

@ -1,40 +0,0 @@
{ lib, pkgs, ... }:
{
environment = {
systemPackages = with pkgs; [
### Dev Tools ###
git
### System Utilities ###
btop
fastfetch
helix
nixos-firewall-tool
nvd
sysz
tmux
wget
yazi
];
shellAliases = {
cat = "${lib.getExe pkgs.bat} --paging=never --style=plain";
ls = "${lib.getExe pkgs.eza} --icons --group-directories-first";
tree = "ls --tree";
};
};
programs = {
command-not-found.enable = false;
fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting
if set -q SSH_CONNECTION
export TERM=xterm-256color
clear
fastfetch
end
'';
};
};
}

View file

@ -1,13 +0,0 @@
{ ... }:
{
security = {
unprivilegedUsernsClone = true; # Needed for rootless podman
sudo = {
wheelNeedsPassword = false;
extraConfig = ''
Defaults lecture = never
'';
};
};
}

View file

@ -1,9 +0,0 @@
{ ... }:
{
services = {
dbus.implementation = "broker";
irqbalance.enable = true;
fstrim.enable = true;
};
}

View file

@ -1,8 +0,0 @@
{ ... }:
{
services.tailscale = {
enable = true;
extraUpFlags = [ "--operator=user" ];
};
}

View file

@ -1,24 +0,0 @@
{ pkgs, ... }:
{
users.users = {
user = {
isNormalUser = true;
shell = pkgs.fish;
extraGroups = [
"networkmanager"
"wheel"
];
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
];
hashedPassword = "$6$Pj7v/CpstyuWQQV0$cNujVDhfMBdwlGVEnnd8t71.kZPixbo0u25cd.874iaqLTH4V5fa1f98V5zGapjQCz5JyZmsR94xi00sUrntT0";
};
root = {
shell = pkgs.fish;
hashedPassword = "!";
};
};
}

View file

@ -1,26 +0,0 @@
{ pkgs, ... }:
{
boot = {
plymouth.enable = true;
initrd.systemd.enable = true;
loader.efi.efiSysMountPoint = "/boot/efi";
kernelPackages = pkgs.linuxPackages_xanmod_latest;
extraModprobeConfig = ''
options bluetooth disable_ertm=1
'';
kernel.sysctl = {
"net.ipv4.tcp_mtu_probing" = 1;
};
kernelParams = [
"quiet"
"splash"
"i2c-dev"
"i2c-piix4"
"loglevel=3"
"udev.log_priority=3"
"rd.udev.log_level=3"
"rd.systemd.show_status=false"
];
};
}

View file

@ -1,163 +0,0 @@
{
config,
inputs,
lib,
pkgs,
...
}:
{
imports = [
inputs.niri-flake.nixosModules.niri
inputs.nix-flatpak.nixosModules.nix-flatpak
];
environment = {
sessionVariables = {
KDEHOME = "$XDG_CONFIG_HOME/kde4"; # Stops kde from placing a .kde4 folder in the home dir
NIXOS_OZONE_WL = "1"; # Forces chromium and most electron apps to run in wayland
};
systemPackages = with pkgs; [
### Web ###
bitwarden-desktop
fragments
nextcloud-client
tor-browser
vesktop
inputs.zen-browser.packages."${system}".default
### Office & Productivity ###
aspell
aspellDicts.de
aspellDicts.en
aspellDicts.en-computers
aspellDicts.pt_BR
papers
presenterm
rnote
### Graphics & Design ###
gimp
inkscape
plasticity
### System Utilities ###
adwaita-icon-theme
ghostty
gnome-disk-utility
junction
libfido2
mission-center
nautilus
p7zip
rclone
toggleaudiosink
unrar
### Media ###
decibels
loupe
obs-studio
showtime
];
};
services = {
pipewire = {
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
jack.enable = true;
wireplumber.enable = true;
};
greetd = {
enable = true;
settings = {
default_session = {
command = "${lib.getExe pkgs.tuigreet} --user-menu --time --remember --asterisks --cmd ${config.programs.niri.package}/bin/niri-session";
user = "greeter";
};
}
// lib.optionalAttrs (config.networking.hostName == "io") {
initial_session = {
command = "${config.programs.niri.package}/bin/niri-session";
user = "user";
};
};
};
flatpak = {
enable = true;
packages = [
### Office & Productivity ###
"com.collabora.Office"
### Graphics & Design ###
"com.boxy_svg.BoxySVG"
rec {
appId = "io.github.softfever.OrcaSlicer";
sha256 = "0hdx5sg6fknj1pfnfxvlfwb5h6y1vjr6fyajbsnjph5gkp97c6p1";
bundle = "${pkgs.fetchurl {
url = "https://github.com/SoftFever/OrcaSlicer/releases/download/v2.3.0/OrcaSlicer-Linux-flatpak_V2.3.0_x86_64.flatpak";
inherit sha256;
}}";
}
### System Utilities ###
"com.github.tchx84.Flatseal"
"com.rustdesk.RustDesk"
];
uninstallUnmanaged = true;
update.auto.enable = true;
};
gvfs.enable = true;
};
security.rtkit.enable = true; # Needed for pipewire to acquire realtime priority
users = {
users.greeter = {
isSystemUser = true;
group = "greeter";
};
groups.greeter = { };
};
programs = {
niri = {
enable = true;
package = inputs.niri.packages.${pkgs.system}.niri;
};
kdeconnect = {
enable = true;
package = pkgs.valent;
};
dconf.enable = true;
appimage = {
enable = true;
binfmt = true;
};
};
niri-flake.cache.enable = false;
fonts = {
fontDir.enable = true;
packages = with pkgs; [
corefonts
inter
nerd-fonts.fira-code
noto-fonts-cjk-sans
noto-fonts-color-emoji
roboto
];
};
xdg.portal = {
extraPortals = with pkgs; [
xdg-desktop-portal-gnome
xdg-desktop-portal-gtk
];
config = {
common.default = "*";
niri.default = [
"gtk"
"gnome"
];
};
};
}

View file

@ -1,13 +0,0 @@
{ inputs, ... }:
{
environment.etc."channels/nixpkgs".source = inputs.nixpkgs.outPath;
nix = {
registry.nixpkgs.flake = inputs.nixpkgs;
nixPath = [
"nixpkgs=${inputs.nixpkgs}"
"/nix/var/nix/profiles/per-user/root/channels"
];
};
}

View file

@ -1,15 +0,0 @@
{ pkgs, ... }:
{
services = {
printing.enable = true;
udev.packages = with pkgs; [ yubikey-personalization ];
keyd = {
enable = true;
keyboards.all = {
ids = [ "*" ];
settings.main.capslock = "overload(meta, esc)";
};
};
};
}

View file

@ -1,18 +0,0 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
android-tools
bat
lazygit
fd
fzf
glow
nixfmt
nix-init
nix-output-monitor
ripgrep
];
users.users.user.extraGroups = [ "adbusers" ];
}

View file

@ -1,43 +0,0 @@
{ config, inputs, ... }:
{
imports = [
inputs.impermanence.nixosModules.impermanence
inputs.self.nixosModules.ephemeral
];
ephemeral = {
enable = true;
rootDevice =
if config.networking.hostName == "trantor" then
"/dev/disk/by-id/scsi-360b207ed25d84372a95d1ecf842f8e20-part2"
else
"/dev/mapper/cryptroot";
rootSubvolume = "@root";
};
fileSystems."/persistent".neededForBoot = true;
environment.persistence.main = {
persistentStoragePath = "/persistent";
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
];
directories = [
"/etc/NetworkManager/system-connections"
"/etc/nixos"
"/var/lib/bluetooth"
"/var/lib/flatpak"
"/var/lib/lxd"
"/var/lib/nixos"
"/var/lib/systemd/coredump"
"/var/lib/systemd/timers"
"/var/lib/tailscale"
"/var/log"
];
};
}

View file

@ -1,5 +0,0 @@
{ ... }:
{
services.fwupd.enable = true;
}

View file

@ -1,43 +0,0 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
clonehero
heroic
mangohud
prismlauncher
steam-run
];
programs = {
steam = {
enable = true;
extraCompatPackages = [ pkgs.proton-ge-bin ];
};
gamemode.enable = true;
};
hardware = {
xpadneo.enable = true;
steam-hardware.enable = true; # Allow steam client to manage controllers
graphics.enable32Bit = true; # For OpenGL games
};
services.flatpak.packages = [
"com.github.k4zmu2a.spacecadetpinball"
"com.steamgriddb.SGDBoop"
"io.github.Foldex.AdwSteamGtk"
"io.itch.itch"
"io.mrarm.mcpelauncher"
"net.retrodeck.retrodeck"
"org.freedesktop.Platform.VulkanLayer.MangoHud/x86_64/25.08"
rec {
appId = "com.hypixel.HytaleLauncher";
sha256 = "01307s44bklc1ldcigcn9n4lm8hf8q793v9fv7w4w04xd5zyh4rv";
bundle = "${pkgs.fetchurl {
url = "https://launcher.hytale.com/builds/release/linux/amd64/hytale-launcher-latest.flatpak";
inherit sha256;
}}";
}
];
}

View file

@ -1,17 +0,0 @@
{ ... }:
{
virtualisation = {
libvirtd.enable = true;
spiceUSBRedirection.enable = true;
};
programs.virt-manager.enable = true;
networking.firewall.trustedInterfaces = [ "virbr0" ];
users.users.user.extraGroups = [
"libvirt"
"libvirtd"
];
}

View file

@ -1,10 +0,0 @@
{ ... }:
{
networking.networkmanager = {
enable = true;
wifi.backend = "iwd";
};
users.users.user.extraGroups = [ "networkmanager" ];
}

View file

@ -1,14 +0,0 @@
{ pkgs, ... }:
{
virtualisation.podman = {
enable = true;
autoPrune.enable = true;
extraPackages = [ pkgs.podman-compose ];
};
systemd = {
services.podman-auto-update.enable = true;
timers.podman-auto-update.enable = true;
};
}

View file

@ -1,5 +0,0 @@
{ pkgs, ... }:
{
boot.kernelPackages = pkgs.linuxPackages_hardened;
}

View file

@ -1,13 +0,0 @@
{ inputs, ... }:
{
environment.etc."channels/nixpkgs".source = inputs.nixpkgs-stable.outPath;
nix = {
registry.nixpkgs.flake = inputs.nixpkgs-stable;
nixPath = [
"nixpkgs=/etc/channels/nixpkgs"
"/nix/var/nix/profiles/per-user/root/channels"
];
};
}

View file

@ -1,13 +0,0 @@
{ ... }:
{
services.tailscale = {
extraSetFlags = [ "--advertise-exit-node" ];
useRoutingFeatures = "server";
};
boot.kernel.sysctl = {
"net.ipv4.ip_forward" = 1;
"net.ipv6.conf.all.forwarding" = 1;
};
}

View file

@ -1,31 +0,0 @@
{ pkgs, ... }:
let
qubesnsh = pkgs.writeTextFile {
name = "qubes.nsh";
text = "HD1f65535a1:EFI\\qubes\\grubx64.efi";
};
in
{
boot = {
kernelParams = [
"processor.max_cstate=1" # Fixes bug where ryzen cpus freeze when in highest C state
"clearcpuid=514"
"amdgpu.ppfeaturemask=0xfffd3fff" # Fixes amdgpu freezing
];
# QubesOS boot entry
loader.systemd-boot = {
extraFiles = {
"efi/edk2-shell/shell.efi" = "${pkgs.edk2-uefi-shell}/shell.efi";
"qubes.nsh" = qubesnsh;
};
extraEntries."qubes.conf" = ''
title Qubes OS
efi /efi/edk2-shell/shell.efi
options -nointerrupt qubes.nsh
sort-key ab
'';
};
};
}

View file

@ -1,82 +0,0 @@
{
config,
lib,
modulesPath,
...
}:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot = {
initrd = {
availableKernelModules = [
"amdgpu"
"nvme"
"xhci_pci"
"ahci"
"usbhid"
"sd_mod"
];
luks.devices."cryptroot" = {
device = "/dev/disk/by-uuid/f7dd4142-7109-4493-834d-4a831777f08d";
keyFile = "/dev/disk/by-partuuid/add5fc14-e20f-48be-8b2a-0799ef04d3cb";
};
};
kernelModules = [ "kvm-amd" ];
};
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8";
fsType = "btrfs";
options = [
"subvol=@root"
"noatime"
"compress=zstd"
];
};
"/home" = {
device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8";
fsType = "btrfs";
options = [
"subvol=@home"
"noatime"
"compress=zstd"
];
};
"/boot/efi" = {
device = "/dev/disk/by-uuid/F2A2-CF5A";
fsType = "vfat";
options = [
"noatime"
"fmask=0077"
"dmask=0077"
];
};
"/nix" = {
device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8";
fsType = "btrfs";
options = [
"subvol=@nix"
"noatime"
"compress=zstd"
];
};
"/persistent" = {
device = "/dev/disk/by-uuid/3287dbc3-c0fa-4096-a0b3-59b017cfecc8";
fsType = "btrfs";
options = [
"subvol=@persistent"
"noatime"
"compress=zstd"
];
};
};
networking.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -1,8 +0,0 @@
{ pkgs, ... }:
{
hardware = {
amdgpu.opencl.enable = true;
graphics.extraPackages = with pkgs; [ rocmPackages.clr.icd ];
};
}

View file

@ -1,31 +0,0 @@
{ pkgs, ... }:
let
reboot-into-qubes = pkgs.makeDesktopItem {
name = "reboot-into-qubes";
icon = pkgs.fetchurl {
url = "https://raw.githubusercontent.com/vinceliuice/Qogir-icon-theme/31f267e1f5fd4e9596bfd78dfb41a03d3a9f33ee/src/scalable/apps/distributor-logo-qubes.svg";
sha256 = "sha256-QbHr7s5Wcs7uFtfqZctMyS0iDbMfiiZOKy2nHhDOfn0=";
};
desktopName = "Qubes OS";
genericName = "Reboot into Qubes OS";
categories = [ "System" ];
startupNotify = true;
exec = pkgs.writeShellScript "reboot-into-qubes" ''
${pkgs.yad}/bin/yad --form \
--title="Qubes OS" \
--image distributor-logo-qubes \
--text "Are you sure you want to reboot into Qubes OS?" \
--button="Yes:0" --button="Cancel:1"
if [ $? -eq 0 ]; then
systemctl reboot --boot-loader-entry=qubes.conf
fi
'';
};
in
{
environment.systemPackages = [ reboot-into-qubes ];
programs.steam.dedicatedServer.openFirewall = true;
}

View file

@ -1,11 +0,0 @@
{
services.keyd = {
enable = true;
keyboards.main = {
ids = [ "5653:0001" ];
settings.main = {
esc = "overload(meta, esc)";
};
};
};
}

View file

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

View file

@ -1,64 +0,0 @@
{ 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

@ -1,23 +0,0 @@
{ 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

@ -1,72 +0,0 @@
{
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

@ -1,20 +0,0 @@
{
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

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

View file

@ -1,61 +0,0 @@
{
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

@ -1,23 +0,0 @@
{ ... }:
{
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

@ -1,58 +0,0 @@
{ 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 ];
};
}

View file

@ -1,84 +0,0 @@
{ lib, config, ... }:
let
cfg = config.ephemeral;
in
{
options.ephemeral = {
enable = lib.mkEnableOption "ephemeral root with automatic rollback";
rootDevice = lib.mkOption {
type = lib.types.str;
example = "/dev/mapper/cryptroot";
description = "Device path for the root btrfs filesystem";
};
rootSubvolume = lib.mkOption {
type = lib.types.str;
example = "@root";
description = "Name of the root btrfs subvolume";
};
oldRootRetentionDays = lib.mkOption {
type = lib.types.int;
default = 30;
description = "Number of days to keep old root snapshots before deletion";
};
};
config = lib.mkIf cfg.enable {
boot.initrd.systemd.services.recreate-root = {
description = "Rolling over and creating new filesystem root";
requires = [ "initrd-root-device.target" ];
after = [
"local-fs-pre.target"
"initrd-root-device.target"
];
requiredBy = [ "initrd-root-fs.target" ];
before = [ "sysroot.mount" ];
unitConfig = {
AssertPathExists = "/etc/initrd-release";
DefaultDependencies = false;
};
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
set -euo pipefail
mkdir /btrfs_tmp
if ! mount ${cfg.rootDevice} /btrfs_tmp; then
echo "ERROR: Failed to mount ${cfg.rootDevice}"
exit 1
fi
if [[ -e /btrfs_tmp/${cfg.rootSubvolume} ]]; then
mkdir -p /btrfs_tmp/old_roots
timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/${cfg.rootSubvolume})" "+%Y-%m-%-d_%H:%M:%S")
mv /btrfs_tmp/${cfg.rootSubvolume} "/btrfs_tmp/old_roots/$timestamp"
fi
delete_subvolume_recursively() {
IFS=$'\n'
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
delete_subvolume_recursively "/btrfs_tmp/$i"
done
btrfs subvolume delete "$1"
}
for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +${toString cfg.oldRootRetentionDays}); do
delete_subvolume_recursively "$i"
done
if ! btrfs subvolume create /btrfs_tmp/${cfg.rootSubvolume}; then
echo "ERROR: Failed to create subvolume ${cfg.rootSubvolume}"
umount /btrfs_tmp
exit 1
fi
umount /btrfs_tmp
'';
};
};
}

37
modules/nix/agenix.nix Normal file
View file

@ -0,0 +1,37 @@
{
self,
inputs,
...
}:
{
flake-file.inputs = {
agenix = {
url = "github:ryantm/agenix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
};
secrets = {
url = "path:./secrets";
flake = false;
};
};
flake.modules = {
nixos.secrets =
{ pkgs, ... }:
{
imports = [
inputs.agenix.nixosModules.default
];
environment.systemPackages = [ inputs.agenix.packages.${pkgs.stdenv.hostPlatform.system}.default ];
};
# homeManager.secrets =
# { pkgs, ... }:
# {
# imports = [
# inputs.agenix.homeManagerModules.default
# ];
# };
};
}

View file

@ -0,0 +1,25 @@
{
inputs,
...
}:
{
flake-file.inputs = {
flake-parts.url = "github:hercules-ci/flake-parts";
flake-file.url = "github:vic/flake-file";
import-tree.url = "github:vic/import-tree";
};
imports = [
inputs.flake-parts.flakeModules.modules
inputs.flake-file.flakeModules.default
];
flake-file.outputs = ''
inputs: inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)
'';
systems = [
"aarch64-linux"
"x86_64-linux"
];
}

12
modules/nix/factory.nix Normal file
View file

@ -0,0 +1,12 @@
{
lib,
...
}:
{
# factory: storage for factory aspect functions
options.flake.factory = lib.mkOption {
type = lib.types.attrsOf lib.types.unspecified;
default = { };
};
}

View file

@ -0,0 +1,36 @@
{
inputs,
config,
...
}:
let
home-manager-config =
{ lib, ... }:
{
home-manager = {
verbose = false;
useUserPackages = true;
useGlobalPkgs = true;
backupFileExtension = "backup";
backupCommand = "rm";
overwriteBackup = true;
};
};
in
{
flake-file.inputs = {
home-manager = {
url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs";
};
};
flake.modules.nixos.home-manager = {
imports = [
inputs.home-manager.nixosModules.home-manager
home-manager-config
];
};
}

View file

@ -0,0 +1,54 @@
{ inputs, ... }:
{
flake-file.inputs = {
impermanence.url = "github:nix-community/impermanence";
};
# convenience function to set persistence settings only, if impermanence module was imported
flake.lib = {
mkIfPersistence =
config: settings:
if config ? home then
(if config.home ? persistence then settings else { })
else
(if config.environment ? persistence then settings else { });
};
flake.modules.nixos.impermanence =
{ config, ... }:
{
imports = [
inputs.impermanence.nixosModules.impermanence
];
environment.persistence."/persistent" = {
hideMounts = true;
directories = [
"/var/log"
"/var/lib/nixos"
"/var/lib/systemd/coredump"
"/etc/NetworkManager/system-connections"
];
files = [
"/etc/machine-id"
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
];
};
# home-manager.sharedModules = [
# {
# home.persistence."/persistent" = {
# };
# }
# ];
fileSystems."/persistent".neededForBoot = true;
programs.fuse.userAllowOther = true;
};
}

34
modules/nix/lib.nix Normal file
View file

@ -0,0 +1,34 @@
{
inputs,
lib,
...
}:
{
# Helper functions for creating system & home-manager configurations
options.flake.lib = lib.mkOption {
type = lib.types.attrsOf lib.types.unspecified;
default = { };
};
config.flake.lib = {
mkNixos = system: name: {
${name} = inputs.nixpkgs.lib.nixosSystem {
modules = [
inputs.self.modules.nixos.${name}
{ nixpkgs.hostPlatform = lib.mkDefault system; }
];
};
};
mkHomeManager = system: name: {
${name} = inputs.home-manager.lib.homeManagerConfiguration {
pkgs = inputs.nixpkgs.legacyPackages.${system};
modules = [
inputs.self.modules.homeManager.${name}
{ nixpkgs.config.allowUnfree = true; }
];
};
};
};
}

View file

@ -0,0 +1,42 @@
{
inputs,
withSystem,
...
}:
{
flake-file.inputs = {
pkgs-by-name-for-flake-parts.url = "github:drupol/pkgs-by-name-for-flake-parts";
packages = {
url = "path:./packages";
flake = false;
};
};
imports = [
inputs.pkgs-by-name-for-flake-parts.flakeModule
];
perSystem =
{ system, ... }:
{
pkgsDirectory = inputs.packages;
};
flake = {
overlays.default = _final: prev: {
local = withSystem prev.stdenv.hostPlatform.system ({ config, ... }: config.packages);
};
modules.generic.pkgs-by-name =
{ pkgs, ... }:
{
nixpkgs.overlays = [
inputs.self.overlays.default
];
nixpkgs-stable.overlays = [
inputs.self.overlays.default
];
};
};
}

View file

@ -1,56 +0,0 @@
{ inputs, ... }:
let
lib = inputs.nixpkgs.lib;
utils = import ./utils.nix { inherit inputs lib; };
inherit (utils) mkHost;
in
{
flake.nixosConfigurations = {
rotterdam = mkHost {
hostname = "rotterdam";
tags = [
"desktop"
"ai"
"bluetooth"
"dev"
"ephemeral"
"fwupd"
"gaming"
"libvirtd"
"networkmanager"
"podman"
];
};
io = mkHost {
hostname = "io";
tags = [
"desktop"
"ai"
"bluetooth"
"dev"
"ephemeral"
"libvirtd"
"networkmanager"
"podman"
];
};
alexandria = mkHost {
hostname = "alexandria";
tags = [
"server"
"fwupd"
];
};
trantor = mkHost {
hostname = "trantor";
system = "aarch64-linux";
tags = [
"server"
"ephemeral"
];
};
};
}

View file

@ -1,7 +0,0 @@
{ ... }:
{
flake.nixosModules = {
ephemeral = import ./modules/ephemeral.nix;
};
}

View file

@ -1,14 +0,0 @@
{ inputs, ... }:
{
flake.overlays = {
default = final: prev: {
base16-schemes = inputs.self.packages.${final.system}.base16-schemes;
claude-desktop = inputs.self.packages.${final.system}.claude-desktop;
fastfetch = inputs.self.packages.${final.system}.fastfetch;
hm-cli = inputs.self.packages.${final.system}.hm-cli;
kwrite = inputs.self.packages.${final.system}.kwrite;
toggleaudiosink = inputs.self.packages.${final.system}.toggleaudiosink;
};
};
}

View file

@ -1,22 +0,0 @@
{ inputs, ... }:
{
perSystem =
{ system, ... }:
let
pkgs = import inputs.nixpkgs {
inherit system;
config.allowUnfree = true;
};
in
{
packages = {
base16-schemes = pkgs.callPackage ./packages/base16-schemes.nix { };
claude-desktop = pkgs.callPackage ./packages/claude-desktop.nix { };
fastfetch = pkgs.callPackage ./packages/fastfetch.nix { };
hm-cli = pkgs.callPackage ./packages/hm-cli.nix { };
kwrite = pkgs.callPackage ./packages/kwrite.nix { };
toggleaudiosink = pkgs.callPackage ./packages/toggleaudiosink.nix { };
};
};
}

View file

@ -1,32 +0,0 @@
{
lib,
stdenv,
fetchFromGitHub,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "base16-schemes";
version = "0-unstable-2025-06-04";
src = fetchFromGitHub {
owner = "tinted-theming";
repo = "schemes";
rev = "317a5e10c35825a6c905d912e480dfe8e71c7559";
hash = "sha256-d4km8W7w2zCUEmPAPUoLk1NlYrGODuVa3P7St+UrqkM=";
};
installPhase = ''
runHook preInstall
mkdir -p $out/share/themes/
install base16/*.yaml $out/share/themes/
runHook postInstall
'';
meta = {
description = "All the color schemes for use in base16 packages";
homepage = "https://github.com/tinted-theming/schemes";
maintainers = [ lib.maintainers.DamienCassou ];
license = lib.licenses.mit;
};
})

View file

@ -1,221 +0,0 @@
{
lib,
stdenv,
fetchurl,
makeWrapper,
makeDesktopItem,
copyDesktopItems,
p7zip,
unzip,
electron,
nodejs,
asar,
graphicsmagick,
}:
let
pname = "claude-desktop";
version = "1.0.1768"; # Updated based on extracted nupkg
srcs.x86_64-linux = fetchurl {
url = "https://downloads.claude.ai/releases/win32/x64/1.0.1768/Claude-67d01376d0e9d08b328455f6db9e63b0d603506a.exe";
hash = "sha256-x76Qav38ya3ObpWIq3dDowo79LgvVquMfaZeH8M1LUk=;";
};
src =
srcs.${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}");
# Stub implementation for claude-native module
claudeNativeStub = ''
// Stub implementation of claude-native using KeyboardKey enum values
const KeyboardKey = {
Backspace: 43, Tab: 280, Enter: 261, Shift: 272, Control: 61, Alt: 40,
CapsLock: 56, Escape: 85, Space: 276, PageUp: 251, PageDown: 250,
End: 83, Home: 154, LeftArrow: 175, UpArrow: 282, RightArrow: 262,
DownArrow: 81, Delete: 79, Meta: 187
};
Object.freeze(KeyboardKey);
module.exports = {
getWindowsVersion: () => "10.0.0",
setWindowEffect: () => {},
removeWindowEffect: () => {},
getIsMaximized: () => false,
flashFrame: () => {},
clearFlashFrame: () => {},
showNotification: () => {},
setProgressBar: () => {},
clearProgressBar: () => {},
setOverlayIcon: () => {},
clearOverlayIcon: () => {},
KeyboardKey
};
'';
in
stdenv.mkDerivation rec {
inherit pname version src;
nativeBuildInputs = [
makeWrapper
copyDesktopItems
p7zip
unzip
nodejs
graphicsmagick
];
buildInputs = [
electron
];
desktopItems = [
(makeDesktopItem {
name = "claude-desktop";
desktopName = "Claude";
comment = "AI assistant from Anthropic";
exec = "claude-desktop %u";
icon = "claude-desktop";
categories = [
"Network"
"Chat"
"Office"
];
mimeTypes = [ "x-scheme-handler/claude" ];
startupNotify = true;
startupWMClass = "Claude";
})
];
unpackPhase = ''
runHook preUnpack
# Extract the Windows installer - use -y to auto-overwrite
7z x -y $src -o./extracted
# The installer contains a NuGet package
if [ -f ./extracted/AnthropicClaude-*-full.nupkg ]; then
echo "Found NuGet package, extracting..."
# NuGet packages are just zip files
unzip -q ./extracted/AnthropicClaude-*-full.nupkg -d ./nupkg
# Extract app.asar to modify it
if [ -f ./nupkg/lib/net45/resources/app.asar ]; then
echo "Extracting app.asar..."
${asar}/bin/asar extract ./nupkg/lib/net45/resources/app.asar ./app
# Also copy the unpacked resources
if [ -d ./nupkg/lib/net45/resources/app.asar.unpacked ]; then
cp -r ./nupkg/lib/net45/resources/app.asar.unpacked/* ./app/
fi
# Copy additional resources
mkdir -p ./app/resources
mkdir -p ./app/resources/i18n
cp ./nupkg/lib/net45/resources/Tray* ./app/resources/ || true
cp ./nupkg/lib/net45/resources/*-*.json ./app/resources/i18n/ || true
fi
else
echo "NuGet package not found"
ls -la ./extracted/
exit 1
fi
runHook postUnpack
'';
buildPhase = ''
runHook preBuild
# Replace the Windows-specific claude-native module with a stub
if [ -d ./app/node_modules/claude-native ]; then
echo "Replacing claude-native module with Linux stub..."
rm -rf ./app/node_modules/claude-native/*.node
cat > ./app/node_modules/claude-native/index.js << 'EOF'
${claudeNativeStub}
EOF
fi
# Fix the title bar detection (from aaddrick script)
echo "Fixing title bar detection..."
SEARCH_BASE="./app/.vite/renderer/main_window/assets"
if [ -d "$SEARCH_BASE" ]; then
TARGET_FILE=$(find "$SEARCH_BASE" -type f -name "MainWindowPage-*.js" | head -1)
if [ -n "$TARGET_FILE" ]; then
echo "Found target file: $TARGET_FILE"
# Replace patterns like 'if(!VAR1 && VAR2)' with 'if(VAR1 && VAR2)'
sed -i -E 's/if\(!([a-zA-Z]+)[[:space:]]*&&[[:space:]]*([a-zA-Z]+)\)/if(\1 \&\& \2)/g' "$TARGET_FILE"
echo "Title bar fix applied"
fi
fi
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/lib/claude-desktop
# Repack the modified app as app.asar
cd ./app
${asar}/bin/asar pack . ../app.asar
cd ..
# Copy resources
mkdir -p $out/lib/claude-desktop/resources
cp ./app.asar $out/lib/claude-desktop/resources/
# Create app.asar.unpacked directory with the stub
mkdir -p $out/lib/claude-desktop/resources/app.asar.unpacked/node_modules/claude-native
cat > $out/lib/claude-desktop/resources/app.asar.unpacked/node_modules/claude-native/index.js << 'EOF'
${claudeNativeStub}
EOF
# Copy other resources
if [ -d ./nupkg/lib/net45/resources ]; then
cp ./nupkg/lib/net45/resources/*.png $out/lib/claude-desktop/resources/ 2>/dev/null || true
cp ./nupkg/lib/net45/resources/*.ico $out/lib/claude-desktop/resources/ 2>/dev/null || true
cp ./nupkg/lib/net45/resources/*.json $out/lib/claude-desktop/resources/ 2>/dev/null || true
fi
# Create wrapper script
makeWrapper ${electron}/bin/electron $out/bin/claude-desktop \
--add-flags "$out/lib/claude-desktop/resources/app.asar" \
--set DISABLE_AUTOUPDATER 1 \
--set NODE_ENV production
# Extract and install icons in multiple sizes
if [ -f ./extracted/setupIcon.ico ]; then
echo "Converting and installing icons..."
# Count frames in the ICO file and extract each one
frame_count=$(gm identify ./extracted/setupIcon.ico | wc -l)
for i in $(seq 0 $((frame_count - 1))); do
gm convert "./extracted/setupIcon.ico[$i]" "./extracted/setupIcon-$i.png" 2>/dev/null || true
done
# Loop through converted icons and install them by size
for img in ./extracted/setupIcon-*.png; do
if [ -f "$img" ]; then
size=$(gm identify -format "%wx%h" "$img")
# Skip smallest icons (16x16 and 32x32) as they're too low quality
if [ "$size" != "16x16" ] && [ "$size" != "32x32" ]; then
mkdir -p "$out/share/icons/hicolor/$size/apps"
cp "$img" "$out/share/icons/hicolor/$size/apps/claude-desktop.png"
fi
fi
done
fi
runHook postInstall
'';
meta = with lib; {
description = "Claude Desktop - AI assistant from Anthropic";
homepage = "https://claude.ai";
license = licenses.unfree;
sourceProvenance = with lib.sourceTypes; [ binaryNativeCode ];
maintainers = with maintainers; [ ];
platforms = [ "x86_64-linux" ];
mainProgram = "claude-desktop";
};
}

View file

@ -1,81 +0,0 @@
{
lib,
pkgs ? import <nixpkgs> { },
}:
let
fastfetch-logo = pkgs.fetchurl {
url = "https://discourse.nixos.org/uploads/default/original/3X/3/6/36954e6d6aa32c8b00f50ca43f142d898c1ff535.png";
hash = "sha256-aLHz8jSAFocrn+Pb4vRq0wtkYFJpBpZRevd+VoZC/PQ=";
};
fastfetch-config = pkgs.writeText "fastfetch-config.json" (
builtins.toJSON {
"$schema" = "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json";
modules = [
"title"
"separator"
{
type = "os";
keyWidth = 9;
}
{
type = "kernel";
keyWidth = 9;
}
{
type = "uptime";
keyWidth = 9;
}
{
type = "shell";
keyWidth = 9;
}
"break"
{
type = "cpu";
keyWidth = 11;
}
{
type = "memory";
keyWidth = 11;
}
{
type = "swap";
keyWidth = 11;
}
{
type = "disk";
folders = "/";
keyWidth = 11;
}
{
type = "command";
key = "Systemd";
keyWidth = 11;
text = "echo \"$(systemctl list-units --state=failed --no-legend | wc -l) failed units, $(systemctl list-jobs --no-legend | wc -l) queued jobs\"";
}
"break"
{
type = "command";
key = "Public IP";
keyWidth = 15;
text = "curl -s -4 ifconfig.me 2>/dev/null || echo 'N/A'";
}
{
type = "command";
key = "Tailscale IP";
keyWidth = 15;
text = "tailscale ip -4 2>/dev/null || echo 'N/A'";
}
{
type = "command";
key = "Local IP";
keyWidth = 15;
text = "ip -4 addr show scope global | grep inet | head -n1 | awk '{print $2}' | cut -d/ -f1";
}
];
}
);
in
pkgs.writeShellScriptBin "fastfetch" ''exec ${lib.getExe pkgs.fastfetch} --config ${fastfetch-config} --logo-type kitty --logo ${fastfetch-logo} --logo-padding-right 1 --logo-width 36 "$@" ''

View file

@ -1,105 +0,0 @@
{
pkgs ? import <nixpkgs> { },
}:
pkgs.writeShellScriptBin "hm" ''
set -e
HM="${pkgs.lib.getExe pkgs.home-manager}"
FLAKE_PATH="''${HM_PATH:-$HOME/.config/home-manager}"
FLAKE_OUTPUT="''${HM_USER:-$(whoami)@$(hostname)}"
show_usage() {
cat <<EOF
Usage: hm <command> [args]
Commands:
apply Switch to a new generation
generation list List all generations
generation delete ID... Delete specified generation(s)
generation rollback Rollback to the previous generation
generation switch ID Switch to the specified generation
generation cleanup Delete all but the current generation
Environment Variables:
HM_PATH Override default flake path (~/.config/home-manager)
Currently set to "''${HM_PATH:-<not set>}"
HM_USER Override default user output ("$(whoami)@$(hostname)")
Currently set to "''${HM_USER:-<not set>}"
EOF
}
if [[ $# -eq 0 ]]; then
show_usage
exit 1
fi
case "$1" in
apply)
"$HM" switch --flake "$FLAKE_PATH#$FLAKE_OUTPUT" -b bkp
;;
generation)
if [[ $# -lt 2 ]]; then
echo "Error: generation command requires a subcommand"
show_usage
exit 1
fi
case "$2" in
list)
"$HM" generations
;;
delete)
if [[ $# -lt 3 ]]; then
echo "Error: delete requires at least one generation ID"
exit 1
fi
shift 2
"$HM" remove-generations "$@"
;;
rollback)
PREV_GEN=$("$HM" generations | \
sed -n 's/^[[:space:]]*id \([0-9]\+\).*/\1/p' | \
head -n 2 | tail -n 1)
if [[ -z "$PREV_GEN" ]]; then
echo "Error: could not determine previous generation (possibly only one generation exists)"
exit 1
fi
"$HM" switch --flake "$FLAKE_PATH" --switch-generation "$PREV_GEN" -b bkp
;;
switch)
if [[ $# -ne 3 ]]; then
echo "Error: switch requires exactly one generation ID"
exit 1
fi
"$HM" switch --flake "$FLAKE_PATH" --switch-generation "$3" -b bkp
;;
cleanup)
CURRENT_GEN=$("$HM" generations | sed -n 's/^.*id \([0-9]\+\) .* (current)$/\1/p')
if [[ -z "$CURRENT_GEN" ]]; then
echo "Error: could not determine current generation"
exit 1
fi
OLD_GENS=$("$HM" generations | sed -n 's/^.*id \([0-9]\+\) .*/\1/p' | grep -v "^$CURRENT_GEN$")
if [[ -z "$OLD_GENS" ]]; then
echo "No old generations to delete"
else
echo "Deleting generations: $(echo $OLD_GENS | tr '\n' ' ')"
echo "$OLD_GENS" | xargs "$HM" remove-generations
echo "Cleanup complete. Current generation $CURRENT_GEN preserved."
fi
;;
*)
echo "Error: unknown generation subcommand '$2'"
show_usage
exit 1
;;
esac
;;
*)
echo "Error: unknown command '$1'"
show_usage
exit 1
;;
esac
''

View file

@ -1,87 +0,0 @@
# Nix Configuration
My personal Nix configuration for multiple NixOS hosts, home-manager users, miscellaneous resources... too many things to list. If I could put my life in a flake I would.
## Hosts
### Desktop Systems
- **rotterdam** - Main desktop workstation (x86_64)
- Features: Desktop, AI tools, Bluetooth, Dev environment, Gaming, Virtualization (libvirtd), Podman
- Storage: Ephemeral root with LUKS encryption
- **io** - Laptop workstation (x86_64)
- Features: Desktop, AI tools, Bluetooth, Dev environment, Podman
- Storage: Ephemeral root with LUKS encryption
### Servers
- **alexandria** - Home server (x86_64)
- Hosts: Nextcloud, Vaultwarden, Jellyfin, Kanidm
- **trantor** - Cloud server (aarch64)
- Hosts: Forgejo
- Cloud provider: Oracle Cloud Infrastructure
- Storage: Ephemeral root with btrfs
## Home Manager Configurations
- **user@rotterdam** - Full desktop setup with gaming, OBS, and complete development environment
- **user@io** - Lightweight desktop setup
Both configurations include:
- btop, direnv, helix, starship, tmux
- Stylix theme management
- Fish shell with custom configurations
## Terranix Configurations
Infrastructure as code using Terranix (NixOS + Terraform/OpenTofu):
- **oci-trantor** - Oracle Cloud Infrastructure provisioning for Trantor server
- **cloudflare-baduhaidev** - DNS and CDN configuration for baduhai.dev domain
- **tailscale-tailnet** - Tailscale network ACL and device management
## Services
All services are accessible via custom domains under baduhai.dev:
- **Kanidm** (auth.baduhai.dev) - Identity and access management
- **Vaultwarden** (pass.baduhai.dev) - Password manager
- **Forgejo** (git.baduhai.dev) - Git forge (publicly accessible)
- **Nextcloud** (cloud.baduhai.dev) - File sync and collaboration
- **Jellyfin** (jellyfin.baduhai.dev) - Media server
Services are accessible via:
- LAN for alexandria-hosted services
- Tailscale VPN for all services
- Public internet for Forgejo only
## Notable Features
### Ephemeral Root
Rotterdam, io, and trantor use an ephemeral root filesystem that resets on every boot:
- Root filesystem is automatically rolled back using btrfs snapshots
- Old snapshots retained for 30 days
- Persistent data stored in dedicated subvolumes
- Implements truly stateless systems
### Custom DNS Architecture
- Unbound DNS servers on both alexandria and trantor
- Service routing based on visibility flags (public/LAN/Tailscale)
- Split-horizon DNS for optimal access paths
### Security
- LUKS full-disk encryption on desktop systems
- Fail2ban on public-facing servers
- agenix for secrets management
- Tailscale for secure remote access
### Desktop Environment
- Custom Niri window manager (Wayland compositor)
- Using forked version with auto-centering feature
- Stylix for consistent theming
### Development Setup
- Nix flakes for reproducible builds
- deploy-rs for automated deployments
- Podman for containerization
- Complete AI tooling integration

View file

@ -1,43 +0,0 @@
# Shared service definitions for cross-host configuration
{
# Host IP definitions
hosts = {
alexandria = {
lanIP = "192.168.15.142";
tailscaleIP = "100.76.19.50";
};
trantor = {
tailscaleIP = "100.108.5.90";
};
};
# Service definitions - IPs are inherited from host
services = [
{
name = "kanidm";
domain = "auth.baduhai.dev";
host = "alexandria";
}
{
name = "vaultwarden";
domain = "pass.baduhai.dev";
host = "alexandria";
}
{
name = "forgejo";
domain = "git.baduhai.dev";
host = "trantor";
public = true;
}
{
name = "nextcloud";
domain = "cloud.baduhai.dev";
host = "alexandria";
}
{
name = "jellyfin";
domain = "jellyfin.baduhai.dev";
host = "alexandria";
}
];
}

View file

@ -1,86 +0,0 @@
# Required environment variables:
# CLOUDFLARE_API_TOKEN - API token with "Edit zone DNS" permissions
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ config, lib, ... }:
let
inherit (import ../../shared/services.nix) services;
# Helper to extract subdomain from full domain (e.g., "git.baduhai.dev" -> "git")
getSubdomain = domain: lib.head (lib.splitString "." domain);
# Generate DNS records for services
# Public services point to trantor's public IP
# Private services point to their tailscale IP
mkServiceRecords = lib.listToAttrs (
lib.imap0 (
i: svc:
let
subdomain = getSubdomain svc.domain;
targetIP =
if svc.public or false then
config.data.terraform_remote_state.trantor "outputs.instance_public_ip"
else
svc.tailscaleIP;
in
{
name = "service_${toString i}";
value = {
zone_id = config.variable.zone_id.default;
name = subdomain;
type = "A";
content = targetIP;
proxied = false;
ttl = 3600;
};
}
) services
);
in
{
terraform.required_providers.cloudflare = {
source = "cloudflare/cloudflare";
version = "~> 5.0";
};
terraform.backend.s3 = {
bucket = "terraform-state";
key = "cloudflare/baduhai.dev.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
zone_id = {
default = "c63a8332fdddc4a8e5612ddc54557044";
type = "string";
};
};
data = {
terraform_remote_state.trantor = {
backend = "s3";
config = {
bucket = "terraform-state";
key = "oci/trantor.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
};
};
resource.cloudflare_dns_record = mkServiceRecords;
}

View file

@ -1,258 +0,0 @@
# Required environment variables:
# instead of OCI variables, ~/.oci/config may also be used
# OCI_TENANCY_OCID - Oracle tenancy OCID (or use TF_VAR_* to override variables)
# OCI_USER_OCID - Oracle user OCID
# OCI_FINGERPRINT - API key fingerprint
# OCI_PRIVATE_KEY_PATH - Path to OCI API private key
# AWS variables are required
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ config, ... }:
{
terraform.required_providers.oci = {
source = "oracle/oci";
version = "~> 7.0";
};
provider.oci.region = "sa-saopaulo-1";
terraform.backend.s3 = {
bucket = "terraform-state";
key = "oci/trantor.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
tenancy_ocid = {
default = "ocid1.tenancy.oc1..aaaaaaaap3vfdz4piygqza6e6zqunbcuso43ddqfo3ydmpmnomidyghh7rvq";
type = "string";
};
compartment_name = {
default = "trantor";
type = "string";
};
vcn_cidr = {
default = "10.0.0.0/24";
type = "string";
};
instance_name = {
default = "trantor";
type = "string";
};
ssh_public_keys = {
default = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQPkAyy+Du9Omc2WtnUF2TV8jFAF4H6mJi2D4IZ1nzg user@himalia"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO3Y0PVpGfJHonqDS7qoCFhqzUvqGq9I9sax+F9e/5cs user@io"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA1v3+q3EaruiiStWjubEJWvtejam/r41uoOpCdwJtLL user@rotterdam"
];
type = "list(string)";
};
};
data = {
oci_identity_availability_domains.ads = {
compartment_id = config.variable.tenancy_ocid.default;
};
oci_core_images.ubuntu_arm = {
compartment_id = config.variable.tenancy_ocid.default;
operating_system = "Canonical Ubuntu";
operating_system_version = "24.04";
shape = "VM.Standard.A1.Flex";
sort_by = "TIMECREATED";
sort_order = "DESC";
};
};
resource = {
oci_identity_compartment.trantor = {
compartment_id = config.variable.tenancy_ocid.default;
description = "trantor infrastructure compartment";
name = config.variable.compartment_name.default;
};
oci_core_vcn.vcn = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
cidr_blocks = [ config.variable.vcn_cidr.default ];
display_name = "trantor-vcn";
dns_label = "trantor";
};
oci_core_internet_gateway.ig = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-ig";
enabled = true;
};
oci_core_route_table.rt = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-rt";
route_rules = [
{
network_entity_id = config.resource.oci_core_internet_gateway.ig "id";
destination = "0.0.0.0/0";
destination_type = "CIDR_BLOCK";
}
];
};
oci_core_security_list.sl = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
display_name = "trantor-sl";
egress_security_rules = [
{
destination = "0.0.0.0/0";
protocol = "all";
stateless = false;
}
];
ingress_security_rules = [
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 22;
max = 22;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 80;
max = 80;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 443;
max = 443;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 25565;
max = 25565;
};
}
{
protocol = "6"; # TCP
source = "0.0.0.0/0";
stateless = false;
tcp_options = {
min = 19132;
max = 19133;
};
}
{
protocol = "17"; # UDP
source = "0.0.0.0/0";
stateless = false;
udp_options = {
min = 19132;
max = 19133;
};
}
];
};
oci_core_subnet.subnet = {
compartment_id = config.resource.oci_identity_compartment.trantor "id";
vcn_id = config.resource.oci_core_vcn.vcn "id";
cidr_block = config.variable.vcn_cidr.default;
display_name = "trantor-subnet";
dns_label = "subnet";
route_table_id = config.resource.oci_core_route_table.rt "id";
security_list_ids = [ (config.resource.oci_core_security_list.sl "id") ];
prohibit_public_ip_on_vnic = false;
};
oci_core_instance.trantor = {
availability_domain = config.data.oci_identity_availability_domains.ads "availability_domains[0].name";
compartment_id = config.resource.oci_identity_compartment.trantor "id";
display_name = config.variable.instance_name.default;
shape = "VM.Standard.A1.Flex";
shape_config = {
ocpus = 2;
memory_in_gbs = 12;
};
source_details = {
source_type = "image";
source_id = config.data.oci_core_images.ubuntu_arm "images[0].id";
boot_volume_size_in_gbs = 100;
};
create_vnic_details = {
subnet_id = config.resource.oci_core_subnet.subnet "id";
display_name = "trantor-vnic";
assign_public_ip = true;
hostname_label = config.variable.instance_name.default;
};
metadata = {
ssh_authorized_keys = builtins.concatStringsSep "\n" config.variable.ssh_public_keys.default;
};
preserve_boot_volume = false;
};
oci_budget_budget.trantor_budget = {
compartment_id = config.variable.tenancy_ocid.default;
targets = [ (config.resource.oci_identity_compartment.trantor "id") ];
amount = 1;
reset_period = "MONTHLY";
display_name = "trantor-budget";
description = "Monthly budget for trantor compartment";
target_type = "COMPARTMENT";
};
oci_budget_alert_rule.daily_spend_alert = {
budget_id = config.resource.oci_budget_budget.trantor_budget "id";
type = "ACTUAL";
threshold = 5;
threshold_type = "PERCENTAGE";
display_name = "daily-spend-alert";
recipients = "baduhai@proton.me";
description = "Alert when daily spending exceeds $0.05";
message = "Daily spending has exceeded $0.05 in the trantor compartment";
};
};
output = {
compartment_id = {
value = config.resource.oci_identity_compartment.trantor "id";
};
instance_public_ip = {
value = config.resource.oci_core_instance.trantor "public_ip";
};
};
}

View file

@ -1,43 +0,0 @@
# Required environment variables:
# TAILSCALE_API_KEY - Tailscale API key with appropriate permissions
# TAILSCALE_TAILNET - Your tailnet name (e.g., "user@example.com" or "example.org.github")
# AWS_ACCESS_KEY_ID - Cloudflare R2 access key for state storage
# AWS_SECRET_ACCESS_KEY - Cloudflare R2 secret key for state storage
{ config, ... }:
{
terraform.required_providers.tailscale = {
source = "tailscale/tailscale";
version = "~> 0.17";
};
terraform.backend.s3 = {
bucket = "terraform-state";
key = "tailscale/tailnet.tfstate";
region = "auto";
endpoint = "https://fcdf920bde00c3d013ee541f984da70e.r2.cloudflarestorage.com";
skip_credentials_validation = true;
skip_metadata_api_check = true;
skip_region_validation = true;
skip_requesting_account_id = true;
use_path_style = true;
};
variable = {
trantor_tailscale_ip = {
default = "100.108.5.90";
type = "string";
};
};
resource = {
tailscale_dns_nameservers.global = {
nameservers = [
config.variable.trantor_tailscale_ip.default
"1.1.1.1"
"1.0.0.1"
];
};
};
}

View file

@ -1,27 +0,0 @@
{ inputs, ... }:
{
imports = [
inputs.terranix.flakeModule
];
perSystem =
{ pkgs, ... }:
{
terranix.terranixConfigurations = {
oci-trantor = {
modules = [ ./terranix/oci/trantor.nix ];
terraformWrapper.package = pkgs.opentofu;
};
cloudflare-baduhaidev = {
modules = [ ./terranix/cloudflare/baduhai.dev.nix ];
terraformWrapper.package = pkgs.opentofu;
};
tailscale-tailnet = {
modules = [ ./terranix/tailscale/tailnet.nix ];
terraformWrapper.package = pkgs.opentofu;
};
};
};
}

View file

@ -1,12 +0,0 @@
{ pkgs, ... }:
{
programs.btop = {
enable = true;
settings = {
theme_background = false;
proc_sorting = "cpu direct";
update_ms = 500;
};
};
}

View file

@ -1,7 +0,0 @@
{ inputs, ... }:
{
imports = [ inputs.nix-index-database.homeModules.nix-index ];
programs.nix-index-database.comma.enable = true;
}

View file

@ -1,8 +0,0 @@
{ pkgs, ... }:
{
programs.bash = {
enable = true;
historyFile = "~/.cache/bash_history";
};
}

View file

@ -1,32 +0,0 @@
{ pkgs, lib, ... }:
{
programs.fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting
${lib.getExe pkgs.nix-your-shell} fish | source
'';
loginShellInit = "${lib.getExe pkgs.nix-your-shell} fish | source";
plugins = [
{
name = "bang-bang";
src = pkgs.fetchFromGitHub {
owner = "oh-my-fish";
repo = "plugin-bang-bang";
rev = "f969c618301163273d0a03d002614d9a81952c1e";
sha256 = "sha256-A8ydBX4LORk+nutjHurqNNWFmW6LIiBPQcxS3x4nbeQ=";
};
}
{
name = "z";
src = pkgs.fetchFromGitHub {
owner = "jethrokuan";
repo = "z";
rev = "067e867debee59aee231e789fc4631f80fa5788e";
sha256 = "sha256-emmjTsqt8bdI5qpx1bAzhVACkg0MNB/uffaRjjeuFxU=";
};
}
];
};
}

View file

@ -1,10 +0,0 @@
{ pkgs, ... }:
{
home = {
packages = with pkgs; [ hm-cli ];
sessionVariables = {
HM_PATH = "/etc/nixos";
};
};
}

View file

@ -1,134 +0,0 @@
{
inputs,
pkgs,
...
}:
{
imports = [ inputs.vicinae.homeManagerModules.default ];
fonts.fontconfig.enable = true;
home.packages = with pkgs; [ xwayland-satellite ];
services.vicinae = {
enable = true;
systemd = {
enable = true;
autoStart = true;
};
};
programs = {
ghostty = {
enable = true;
settings = {
cursor-style = "block";
shell-integration-features = "no-cursor";
cursor-style-blink = false;
custom-shader = "${builtins.fetchurl {
url = "https://raw.githubusercontent.com/hackr-sh/ghostty-shaders/cb6eb4b0d1a3101c869c62e458b25a826f9dcde3/cursor_blaze.glsl";
sha256 = "sha256:0g2lgqjdrn3c51glry7x2z30y7ml0y61arl5ykmf4yj0p85s5f41";
}}";
bell-features = "";
gtk-titlebar-style = "tabs";
keybind = [ "shift+enter=text:\\x1b\\r" ];
};
};
password-store = {
enable = true;
package = pkgs.pass-wayland;
};
};
xdg = {
enable = true;
userDirs.enable = true;
mimeApps = {
enable = true;
defaultApplications = {
"text/html" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/http" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/https" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/about" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"x-scheme-handler/unknown" = [
"re.sonny.Junction.desktop"
"zen-browser.desktop"
"torbrowser.desktop"
];
"image/jpeg" = "org.gnome.Loupe.desktop";
"image/png" = "org.gnome.Loupe.desktop";
"image/gif" = "org.gnome.Loupe.desktop";
"image/webp" = "org.gnome.Loupe.desktop";
"image/bmp" = "org.gnome.Loupe.desktop";
"image/svg+xml" = "org.gnome.Loupe.desktop";
"image/tiff" = "org.gnome.Loupe.desktop";
"video/mp4" = "io.bassi.Showtime.desktop";
"video/x-matroska" = "io.bassi.Showtime.desktop";
"video/webm" = "io.bassi.Showtime.desktop";
"video/mpeg" = "io.bassi.Showtime.desktop";
"video/x-msvideo" = "io.bassi.Showtime.desktop";
"video/quicktime" = "io.bassi.Showtime.desktop";
"video/x-flv" = "io.bassi.Showtime.desktop";
"audio/mpeg" = "io.bassi.Showtime.desktop";
"audio/flac" = "io.bassi.Showtime.desktop";
"audio/ogg" = "io.bassi.Showtime.desktop";
"audio/wav" = "io.bassi.Showtime.desktop";
"audio/mp4" = "io.bassi.Showtime.desktop";
"audio/x-opus+ogg" = "io.bassi.Showtime.desktop";
"application/pdf" = [
"org.gnome.Papers.desktop"
"zen-browser.desktop"
];
"text/plain" = "Helix.desktop";
"text/markdown" = "Helix.desktop";
"text/x-log" = "Helix.desktop";
"application/x-shellscript" = "Helix.desktop";
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" =
"com.collabora.Office.desktop"; # DOCX
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" =
"com.collabora.Office.desktop"; # XLSX
"application/vnd.openxmlformats-officedocument.presentationml.presentation" =
"com.collabora.Office.desktop"; # PPTX
"application/vnd.oasis.opendocument.text" = "com.collabora.Office.desktop"; # ODT
"application/vnd.oasis.opendocument.spreadsheet" = "com.collabora.Office.desktop"; # ODS
"application/vnd.oasis.opendocument.presentation" = "com.collabora.Office.desktop"; # ODP
"application/msword" = "com.collabora.Office.desktop"; # DOC
"application/vnd.ms-excel" = "com.collabora.Office.desktop"; # XLS
"application/vnd.ms-powerpoint" = "com.collabora.Office.desktop"; # PPT
"application/zip" = "org.gnome.FileRoller.desktop";
"application/x-tar" = "org.gnome.FileRoller.desktop";
"application/x-compressed-tar" = "org.gnome.FileRoller.desktop";
"application/x-bzip-compressed-tar" = "org.gnome.FileRoller.desktop";
"application/x-xz-compressed-tar" = "org.gnome.FileRoller.desktop";
"application/x-7z-compressed" = "org.gnome.FileRoller.desktop";
"application/x-rar" = "org.gnome.FileRoller.desktop";
"application/gzip" = "org.gnome.FileRoller.desktop";
"application/x-bzip" = "org.gnome.FileRoller.desktop";
"inode/directory" = "org.gnome.Nautilus.desktop";
};
};
};
# Set Ghostty as default terminal
home.sessionVariables = {
TERMINAL = "ghostty";
};
}

View file

@ -1,229 +0,0 @@
{
inputs,
lib,
pkgs,
hostname ? null,
...
}:
let
isRotterdam = hostname == "rotterdam";
in
{
imports = [ inputs.noctalia.homeModules.default ];
services.kanshi = {
enable = true;
settings = [
{
profile.name = "default";
profile.outputs = [
{
criteria = "*";
scale = 1.0;
}
];
}
];
};
home = {
packages = with pkgs; [
xwayland-satellite
inputs.noctalia.packages.${pkgs.system}.default
];
sessionVariables.QT_QPA_PLATFORMTHEME = "gtk3";
};
xdg.configFile."niri/config.kdl".text = ''
input {
keyboard {
xkb {
layout "us"
variant "altgr-intl"
}
}
touchpad {
tap
dwt
drag true
drag-lock
natural-scroll
accel-speed 0.2
accel-profile "flat"
scroll-method "two-finger"
middle-emulation
}
mouse {
natural-scroll
accel-speed 0.2
accel-profile "flat"
}
warp-mouse-to-focus mode="center-xy"
focus-follows-mouse
}
layout {
gaps 8
center-focused-column "never"
auto-center-when-space-available
preset-column-widths {
${
if isRotterdam then
''
proportion 0.33333
proportion 0.5
proportion 0.66667
''
else
''
proportion 0.5
proportion 1.0
''
}
}
default-column-width { proportion ${if isRotterdam then "0.33333" else "0.5"}; }
focus-ring {
off
}
border {
width 4
active-color "#ffc87f"
inactive-color "#505050"
urgent-color "#9b0000"
}
tab-indicator {
width 4
gap 4
place-within-column
}
}
overview {
zoom 0.65
}
spawn-at-startup "noctalia-shell" "-d"
layer-rule {
match namespace="^wallpaper$"
place-within-backdrop true
}
layer-rule {
match namespace="^quickshell-overview$"
place-within-backdrop true
}
hotkey-overlay {
skip-at-startup
}
prefer-no-csd
screenshot-path "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png"
animations {
slowdown 0.3
}
window-rule {
match app-id="zen"
default-column-width { proportion ${if isRotterdam then "0.5" else "1.0"}; }
}
window-rule {
geometry-corner-radius 12
clip-to-geometry true
}
config-notification {
disable-failed
}
binds {
Alt+Space repeat=false { spawn "vicinae" "toggle"; }
XF86AudioRaiseVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "increase"; }
XF86AudioLowerVolume allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "decrease"; }
XF86AudioMute allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "volume" "muteOutput"; }
XF86MonBrightnessUp allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "increase"; }
XF86MonBrightnessDown allow-when-locked=true { spawn "noctalia-shell" "ipc" "call" "brightness" "decrease"; }
XF86AudioPlay allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "play-pause"; }
XF86AudioStop allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "stop"; }
XF86AudioPrev allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "previous"; }
XF86AudioNext allow-when-locked=true { spawn "${lib.getExe pkgs.playerctl}" "next"; }
Mod+V repeat=false { spawn "vicinae" "vicinae://extensions/vicinae/clipboard/history"; }
Mod+Shift+L repeat=false { spawn "noctalia-shell" "ipc" "call" "lockScreen" "lock"; }
Mod+Return { spawn "ghostty"; }
Ctrl+Alt+Shift+A allow-when-locked=true { spawn "toggleaudiosink"; }
Mod+W repeat=false { toggle-overview; }
Mod+Q { close-window; }
Alt+Shift+Q { close-window;}
Mod+Shift+Q { close-window; }
Alt+F4 { close-window; }
Mod+Left { focus-column-left; }
Mod+Down { focus-window-or-workspace-down; }
Mod+Up { focus-window-or-workspace-up; }
Mod+Right { focus-column-right; }
Mod+H { focus-column-left; }
Mod+L { focus-column-right; }
Mod+J { focus-window-or-workspace-down; }
Mod+K { focus-window-or-workspace-up; }
Mod+Ctrl+Left { move-column-left; }
Mod+Ctrl+Down { move-window-down-or-to-workspace-down; }
Mod+Ctrl+Up { move-window-up-or-to-workspace-up; }
Mod+Ctrl+Right { move-column-right; }
Mod+Ctrl+H { move-column-left; }
Mod+Ctrl+J { move-window-down-or-to-workspace-down; }
Mod+Ctrl+K { move-window-up-or-to-workspace-up; }
Mod+Ctrl+L { move-column-right; }
Mod+Home { focus-column-first; }
Mod+End { focus-column-last; }
Mod+Ctrl+Home { move-column-to-first; }
Mod+Ctrl+End { move-column-to-last; }
Mod+Alt+Left { focus-monitor-left; }
Mod+Alt+Down { focus-monitor-down; }
Mod+Alt+Up { focus-monitor-up; }
Mod+Alt+Right { focus-monitor-right; }
Mod+Alt+H { focus-monitor-left; }
Mod+Alt+J { focus-monitor-down; }
Mod+Alt+K { focus-monitor-up; }
Mod+Alt+L { focus-monitor-right; }
Mod+Alt+Ctrl+Left { move-column-to-monitor-left; }
Mod+Alt+Ctrl+Down { move-column-to-monitor-down; }
Mod+Alt+Ctrl+Up { move-column-to-monitor-up; }
Mod+Alt+Ctrl+Right { move-column-to-monitor-right; }
Mod+Alt+Ctrl+H { move-column-to-monitor-left; }
Mod+Alt+Ctrl+J { move-column-to-monitor-down; }
Mod+Alt+Ctrl+K { move-column-to-monitor-up; }
Mod+Alt+Ctrl+L { move-column-to-monitor-right; }
Mod+Ctrl+U { move-workspace-down; }
Mod+Ctrl+I { move-workspace-up; }
Mod+WheelScrollDown cooldown-ms=150 { focus-workspace-down; }
Mod+WheelScrollUp cooldown-ms=150 { focus-workspace-up; }
Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }
Mod+Ctrl+WheelScrollUp cooldown-ms=150 { move-column-to-workspace-up; }
Mod+Shift+WheelScrollDown { focus-column-right; }
Mod+Shift+WheelScrollUp { focus-column-left; }
Mod+Ctrl+Shift+WheelScrollDown { move-column-right; }
Mod+Ctrl+Shift+WheelScrollUp { move-column-left; }
Mod+BracketLeft { consume-or-expel-window-left; }
Mod+BracketRight { consume-or-expel-window-right; }
Mod+Comma { consume-window-into-column; }
Mod+Period { expel-window-from-column; }
Mod+R { switch-preset-column-width; }
Mod+F { maximize-column; }
Mod+Ctrl+F { fullscreen-window; }
Mod+C { center-visible-columns; }
Mod+Ctrl+C { center-column; }
Mod+Space { toggle-window-floating; }
Mod+Ctrl+Space { switch-focus-between-floating-and-tiling; }
Mod+T { toggle-column-tabbed-display; }
Print { screenshot-screen; }
Mod+Print { screenshot; }
Ctrl+Print { screenshot-window; }
Mod+Backspace allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }
Mod+Alt+E { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; }
Ctrl+Alt+Delete { spawn "noctalia-shell" "ipc" "call" "sessionMenu" "toggle"; }
Mod+Ctrl+P { power-off-monitors; }
}
'';
}

View file

@ -1,8 +0,0 @@
{ pkgs, ... }:
{
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
}

View file

@ -1,33 +0,0 @@
{ config, ... }:
{
programs.mangohud = {
enable = true;
enableSessionWide = true;
settings = {
position = "top-left";
fps = true;
frametime = false;
frame_timing = false;
gpu_stats = true;
gpu_temp = true;
gpu_power = true;
cpu_stats = true;
cpu_temp = true;
cpu_power = true;
ram = true;
vram = true;
gamemode = false;
vkbasalt = false;
version = false;
engine_version = false;
vulkan_driver = false;
wine = false;
time = false;
fps_sampling_period = 500;
toggle_hud = "Shift_L+F12";
toggle_logging = "Ctrl_L+F2";
output_folder = "${config.home.homeDirectory}/.local/share/mangohud";
};
};
}

View file

@ -1,49 +0,0 @@
{ pkgs, ... }:
{
home.sessionVariables = {
EDITOR = "hx";
};
programs.helix = {
enable = true;
settings = {
editor = {
file-picker.hidden = false;
idle-timeout = 0;
line-number = "relative";
cursor-shape = {
normal = "underline";
insert = "bar";
select = "underline";
};
soft-wrap.enable = true;
auto-format = true;
indent-guides.render = true;
};
keys.normal = {
space = {
o = "file_picker_in_current_buffer_directory";
esc = [
"collapse_selection"
"keep_primary_selection"
];
};
};
};
languages = {
language = [
{
name = "nix";
auto-format = true;
formatter.command = "nixfmt";
}
{
name = "typst";
auto-format = true;
formatter.command = "typstyle -c 1000 -i";
}
];
};
};
}

View file

@ -1,13 +0,0 @@
{ pkgs, ... }:
{
programs.obs-studio = {
enable = true;
plugins = [
pkgs.obs-studio-plugins.obs-vkcapture
pkgs.obs-studio-plugins.obs-backgroundremoval
pkgs.obs-studio-plugins.obs-pipewire-audio-capture
];
};
}

View file

@ -1,40 +0,0 @@
{ pkgs, ... }:
{
programs.starship = {
enable = true;
enableBashIntegration = true;
enableFishIntegration = true;
settings = {
add_newline = false;
format = ''
$hostname$directory$git_branch$git_status$nix_shell
[ ](bold green)
'';
right_format = "$cmd_duration$character";
hostname = {
ssh_symbol = "󰖟 ";
};
character = {
error_symbol = "[](red)";
success_symbol = "[󱐋](green)";
};
cmd_duration = {
format = "[󰄉 $duration ]($style)";
style = "yellow";
min_time = 500;
};
git_branch = {
symbol = " ";
style = "purple";
};
git_status.style = "red";
nix_shell = {
format = "via [$symbol$state]($style)";
heuristic = true;
style = "blue";
symbol = "󱄅 ";
};
};
};
}

View file

@ -1,69 +0,0 @@
{
config,
inputs,
pkgs,
...
}:
{
imports = [
inputs.stylix.homeModules.stylix
inputs.zen-browser.homeModules.beta
];
stylix = {
enable = true;
polarity = "dark";
base16Scheme = "${pkgs.base16-schemes}/share/themes/tokyodark.yaml";
cursor = {
package = pkgs.kdePackages.breeze;
name = "breeze_cursors";
size = 24;
};
icons = {
enable = true;
package = pkgs.morewaita-icon-theme;
light = "MoreWaita";
dark = "MoreWaita";
};
opacity = {
applications = 1.0;
desktop = 0.8;
popups = config.stylix.opacity.desktop;
terminal = 1.0;
};
fonts = {
serif = {
package = pkgs.source-serif;
name = "Source Serif 4 Display";
};
sansSerif = {
package = pkgs.inter;
name = "Inter";
};
monospace = {
package = pkgs.nerd-fonts.fira-code;
name = "FiraCode Nerd Font";
};
emoji = {
package = pkgs.noto-fonts-color-emoji;
name = "Noto Color Emoji";
};
sizes = {
applications = 10;
desktop = config.stylix.fonts.sizes.applications;
popups = config.stylix.fonts.sizes.applications;
terminal = 12;
};
};
targets.zen-browser = {
enable = true;
profileNames = [ "william" ];
};
};
programs.zen-browser = {
enable = true;
profiles.william = { };
};
}

View file

@ -1,11 +0,0 @@
{ pkgs, ... }:
{
programs.tmux = {
enable = true;
clock24 = true;
terminal = "xterm-256color";
mouse = true;
keyMode = "vi";
};
}

View file

@ -1,17 +0,0 @@
{ pkgs, ... }:
{
programs = {
git = {
enable = true;
settings.user = {
name = "William";
email = "baduhai@proton.me";
};
};
diff-so-fancy = {
enable = true;
enableGitIntegration = true;
};
};
}

233
utils.nix
View file

@ -1,233 +0,0 @@
{ inputs, lib }:
let
inherit (inputs)
self
nixpkgs
nixpkgs-stable
home-manager
agenix
;
# Import shared service definitions
sharedServices = import ./shared/services.nix;
# Enrich services with host IP information
enrichedServices = builtins.map (svc:
let
hostInfo = sharedServices.hosts.${svc.host} or {};
in
svc // lib.optionalAttrs (hostInfo ? lanIP) { inherit (hostInfo) lanIP; }
// lib.optionalAttrs (hostInfo ? tailscaleIP) { inherit (hostInfo) tailscaleIP; }
) sharedServices.services;
in
{
# Re-export enriched services and hosts for use in host configs
services = enrichedServices;
inherit (sharedServices) hosts;
# Tag-based host configuration system
mkHost =
{
hostname,
tags ? [ ],
system ? "x86_64-linux",
extraModules ? [ ],
}:
let
# Validate that server and desktop tags are mutually exclusive
hasServer = builtins.elem "server" tags;
hasDesktop = builtins.elem "desktop" tags;
# Always include "common" tag implicitly
allTags =
if hasServer && hasDesktop then
throw "Error: 'server' and 'desktop' tags are mutually exclusive for host '${hostname}'"
else
[ "common" ] ++ tags;
# Choose nixpkgs based on server tag
pkgs = if builtins.elem "server" allTags then nixpkgs-stable else nixpkgs;
# Tag-specific modules: each tag can be either:
# 1. A file: hosts/modules/${tag}.nix
# 2. A directory: hosts/modules/${tag}/*.nix (all .nix files imported)
tagModuleFiles = builtins.concatMap (
tag:
let
filePath = ./hosts/modules/${tag}.nix;
dirPath = ./hosts/modules/${tag};
in
# Check if it's a file first
if builtins.pathExists filePath then
[ filePath ]
# Then check if it's a directory
else if builtins.pathExists dirPath then
let
entries = builtins.readDir dirPath;
nixFiles = pkgs.lib.filterAttrs (
name: type: type == "regular" && pkgs.lib.hasSuffix ".nix" name
) entries;
in
map (name: dirPath + "/${name}") (builtins.attrNames nixFiles)
else
[ ]
) allTags;
# Automatically import all .nix files from hosts/${hostname}/
hostModulePath = ./hosts/${hostname};
hostModuleFiles =
if builtins.pathExists hostModulePath then
let
entries = builtins.readDir hostModulePath;
nixFiles = pkgs.lib.filterAttrs (
name: type: type == "regular" && pkgs.lib.hasSuffix ".nix" name && name != "${hostname}.nix"
) entries;
in
map (name: hostModulePath + "/${name}") (builtins.attrNames nixFiles)
else
[ ];
# Combine all modules
allModules = [
agenix.nixosModules.default
{
networking.hostName = hostname;
nix.nixPath = [ "nixos-config=${self.outPath}/nixosConfigurations/${hostname}" ];
nixpkgs.overlays = [
agenix.overlays.default
self.overlays.default
];
}
]
++ tagModuleFiles
++ hostModuleFiles
++ extraModules;
in
pkgs.lib.nixosSystem {
inherit system;
specialArgs = {
inherit inputs;
hostTags = allTags;
};
modules = allModules;
};
# Tag-based user configuration system
mkHome =
{
username,
hostname ? null,
homeDirectory ? "/home/${username}",
tags ? [ ],
extraModules ? [ ],
}:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
# Always include "common" tag implicitly
allTags = [ "common" ] ++ tags;
# Tag-specific modules: each tag maps to users/modules/${tag}.nix if it exists
tagModuleFiles = builtins.concatMap (
tag:
let
filePath = ./users/modules/${tag}.nix;
dirPath = ./users/modules/${tag};
in
# Check if it's a file first
if builtins.pathExists filePath then
[ filePath ]
# Then check if it's a directory
else if builtins.pathExists dirPath then
let
entries = builtins.readDir dirPath;
nixFiles = pkgs.lib.filterAttrs (
name: type: type == "regular" && pkgs.lib.hasSuffix ".nix" name
) entries;
in
map (name: dirPath + "/${name}") (builtins.attrNames nixFiles)
else
[ ]
) allTags;
# Automatically import all .nix files from users/${username}/
userModulePath = ./users/${username};
userModuleFiles =
if builtins.pathExists userModulePath then
let
entries = builtins.readDir userModulePath;
nixFiles = pkgs.lib.filterAttrs (
name: type: type == "regular" && pkgs.lib.hasSuffix ".nix" name
) entries;
in
map (name: userModulePath + "/${name}") (builtins.attrNames nixFiles)
else
[ ];
# Combine all modules
allModules = [
{
home = {
inherit username homeDirectory;
stateVersion = "22.05";
};
}
]
++ tagModuleFiles
++ userModuleFiles
++ extraModules;
in
home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = {
inherit inputs hostname;
userTags = allTags;
};
modules = allModules ++ [
{
nixpkgs.overlays = [ self.overlays.default ];
}
];
};
# Nginx virtual host utilities
mkNginxVHosts =
{ domains }:
let
# Extract domain name and apply it as useACMEHost
mkVHostConfig = domain: config:
lib.recursiveUpdate {
useACMEHost = domain;
forceSSL = true;
kTLS = true;
} config;
in
lib.mapAttrs mkVHostConfig domains;
# Split DNS utilities for unbound
# Generates unbound view config from a list of DNS entries
mkSplitDNS =
entries:
let
# Generate local-data entries for all domains
tailscaleData = map (e: ''"${e.domain}. IN A ${e.tailscaleIP}"'') entries;
lanData = map (e: ''"${e.domain}. IN A ${e.lanIP}"'') entries;
in
[
# Single Tailscale view with all domains
{
name = "tailscale";
view-first = true;
local-zone = ''"baduhai.dev." transparent'';
local-data = tailscaleData;
}
# Single LAN view with all domains
{
name = "lan";
view-first = true;
local-zone = ''"baduhai.dev." transparent'';
local-data = lanData;
}
];
}