Compare commits

..

1 commit

Author SHA1 Message Date
99ad3058a3 integrate sops-nix for secret management 2026-03-11 19:24:17 +07:00
59 changed files with 633 additions and 948 deletions

View file

@ -1,41 +0,0 @@
name: Activate Homelab Configuration
on:
workflow_dispatch:
push:
branches: [ main ]
env:
PATH: /run/current-system/sw/bin:/run/wrappers/bin
jobs:
rebuild:
runs-on: self-hosted
steps:
- name: Setup SSH key
run: |
mkdir -p ./ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ./ssh/deploy_key
chmod 600 ./ssh/deploy_key
- name: Rebuild and switch
run: |
ssh -i ./ssh/deploy_key \
-o PasswordAuthentication=no \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
root@localhost \
"bash -lc 'nixos-rebuild switch --refresh --flake git+http://localhost:5080/satr14/nix-flake#homelab -L'"
- name: Show generation
if: always()
run: |
ssh -i ./ssh/deploy_key \
-o PasswordAuthentication=no \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
root@localhost "bash -lc 'nixos-version'"
- name: Clean Up
if: always()
run: rm -f ./ssh/deploy_key

25
.sops.yaml Normal file
View file

@ -0,0 +1,25 @@
# To set up sops-nix:
# 1. Generate an age key on each host:
# mkdir -p ~/.config/sops/age
# age-keygen -o ~/.config/sops/age/keys.txt
# Or derive from the host SSH key:
# nix-shell -p ssh-to-age --run 'cat /etc/ssh/ssh_host_ed25519_key.pub | ssh-to-age'
#
# 2. Replace the placeholder age keys below with the actual public keys.
#
# 3. Encrypt secret files:
# sops secrets/homelab.yaml
#
# 4. To re-key after changing keys:
# sops updatekeys secrets/homelab.yaml
keys:
- &homelab age1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # replace with: ssh-to-age < /etc/ssh/ssh_host_ed25519_key.pub
- &admin age1XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # replace with: age-keygen output from your admin machine
creation_rules:
- path_regex: secrets/homelab\.yaml$
key_groups:
- age:
- *homelab
- *admin

View file

@ -1,3 +0,0 @@
{
"nixEnvSelector.suggestion": false
}

View file

@ -1,18 +1,5 @@
![nix-flake](ss.png) ![nix-flake](ss.png)
rewrite of my nixos flake with hopefully better structuring and modularity
> [!WARNING] > [!WARNING]
> This flake is ment for personal use. The code is not well documented nor structured and is not ment to be used by others. **Use at your own risk.** > this flake is ment for personal use. code is not well documented and is not ment to be used by others. use at your own risk.
## Hosts
- `thinkpad` - Thinkpad T480, i5 8350U, 16GB RAM, 256GB NVME
- `homelab` - i7 8700T, 32GB RAM, 512GB NVME, 1TB 2.5" SATA
## Todo
- Automatic backups to external drives.
- Better documentation and code structure.
- Use NixOS modules system.
## Credits
- [orangc's flake](https://git.orangc.net/c/dots)
- [vimjoyer's tutorials](https://www.youtube.com/@vimjoyer)
- [wallpaper source](https://github.com/er2de2/catppuccin_walls/blob/master/wallpapers_png/autumn_2.0.png)

97
flake.lock generated
View file

@ -5,11 +5,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1777734189, "lastModified": 1773146250,
"narHash": "sha256-kbIhdhDPaTP6gxAPkcRYeB+cqPFDpTM/bnw+m+26vkI=", "narHash": "sha256-azzOjRqTxAqByzRP87jUUsmfOQ85i7h/YkrgTX0jZgg=",
"owner": "catppuccin", "owner": "catppuccin",
"repo": "nix", "repo": "nix",
"rev": "e68cf5deaf1a7afed2e548835dba2ae99f5a3ccb", "rev": "0fa0d06dd3cd09f37f76d19b389d7ff947dfd7e8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -18,22 +18,6 @@
"type": "github" "type": "github"
} }
}, },
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1747046372,
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": { "flake-utils": {
"inputs": { "inputs": {
"systems": "systems" "systems": "systems"
@ -78,11 +62,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1777977606, "lastModified": 1773179137,
"narHash": "sha256-8ceIdvijN2tm9fIAUgnIZ8BM8TlsFx7pRYKRoxNsi1k=", "narHash": "sha256-EdW2bwzlfme0vbMOcStnNmKlOAA05Bp6su2O8VLGT0k=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "7ef1c04d11f7ef69fd946b118c768c32de0b89a5", "rev": "3f98e2bbc661ec0aaf558d8a283d6955f05f1d09",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -92,33 +76,13 @@
"type": "github" "type": "github"
} }
}, },
"mc": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs_3",
"systems": "systems_2"
},
"locked": {
"lastModified": 1777952170,
"narHash": "sha256-8dQ/DOUvQI8x5i6MZ309/xZLLVfV1CgWbD2+JiQ7Hd4=",
"owner": "Infinidoge",
"repo": "nix-minecraft",
"rev": "34a46e4de360c5004ee1866f5e3de78bf5e8b289",
"type": "github"
},
"original": {
"owner": "Infinidoge",
"repo": "nix-minecraft",
"type": "github"
}
},
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1777268161, "lastModified": 1772773019,
"narHash": "sha256-bxrdOn8SCOv8tN4JbTF/TXq7kjo9ag4M+C8yzzIRYbE=", "narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1c3fe55ad329cbcb28471bb30f05c9827f724c76", "rev": "aca4d95fce4914b3892661bcb80b8087293536c6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -145,11 +109,11 @@
}, },
"nixpkgs_3": { "nixpkgs_3": {
"locked": { "locked": {
"lastModified": 1769461804, "lastModified": 1772963539,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=", "narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d", "rev": "9dcb002ca1690658be4a04645215baea8b95f31d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -161,16 +125,16 @@
}, },
"nixpkgs_4": { "nixpkgs_4": {
"locked": { "locked": {
"lastModified": 1777578337, "lastModified": 1772736753,
"narHash": "sha256-Ad49moKWeXtKBJNy2ebiTQUEgdLyvGmTeykAQ9xM+Z4=", "narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=",
"owner": "nixos", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "15f4ee454b1dce334612fa6843b3e05cf546efab", "rev": "917fec990948658ef1ccd07cef2a1ef060786846",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nixos", "owner": "NixOS",
"ref": "nixos-unstable", "ref": "nixpkgs-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }
@ -180,26 +144,29 @@
"ctp": "ctp", "ctp": "ctp",
"gl": "gl", "gl": "gl",
"hm": "hm", "hm": "hm",
"mc": "mc", "nixpkgs": "nixpkgs_3",
"nixpkgs": "nixpkgs_4" "sops": "sops"
} }
}, },
"systems": { "sops": {
"inputs": {
"nixpkgs": "nixpkgs_4"
},
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1773096132,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=",
"owner": "nix-systems", "owner": "Mic92",
"repo": "default", "repo": "sops-nix",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "nix-systems", "owner": "Mic92",
"repo": "default", "repo": "sops-nix",
"type": "github" "type": "github"
} }
}, },
"systems_2": { "systems": {
"locked": { "locked": {
"lastModified": 1681028828, "lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",

View file

@ -6,20 +6,19 @@
url = "github:nix-community/home-manager/master"; url = "github:nix-community/home-manager/master";
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
sops.url = "github:Mic92/sops-nix";
gl.url = "github:nix-community/nixGL"; gl.url = "github:nix-community/nixGL";
ctp.url = "github:catppuccin/nix"; ctp.url = "github:catppuccin/nix";
mc.url = "github:Infinidoge/nix-minecraft";
}; };
outputs = inputs: let outputs = inputs: let
pkgs = import inputs.nixpkgs { pkgs = import inputs.nixpkgs {
system = "x86_64-linux"; system = "x86_64-linux";
overlays = [ inputs.gl.overlay ]; overlays = [ inputs.gl.overlay ];
config = { config = {
allowUnfree = true; allowUnfree = true;
permittedInsecurePackages = [ "ventoy-qt5-1.1.12" ]; permittedInsecurePackages = [ "ventoy-qt5-1.1.10" ];
}; };
}; };
args = { args = {
@ -32,15 +31,17 @@
modules = [ modules = [
./hosts/${host}/config.nix ./hosts/${host}/config.nix
inputs.ctp.nixosModules.catppuccin inputs.ctp.nixosModules.catppuccin
inputs.sops.nixosModules.sops
]; ];
}; };
nixosConfigWithHome = host: inputs.nixpkgs.lib.nixosSystem { nixosConfigWithHome = host: inputs.nixpkgs.lib.nixosSystem {
inherit pkgs; inherit pkgs;
specialArgs = args // { hostname = host; }; specialArgs = args // { hostname = host; };
modules = [ modules = [
./hosts/${host}/config.nix ./hosts/${host}/config.nix
inputs.ctp.nixosModules.catppuccin inputs.ctp.nixosModules.catppuccin
inputs.sops.nixosModules.sops
inputs.hm.nixosModules.home-manager inputs.hm.nixosModules.home-manager
{ {
home-manager = { home-manager = {
@ -52,7 +53,7 @@
} }
]; ];
}; };
homeConfig = host: inputs.hm.lib.homeManagerConfiguration { homeConfig = host: inputs.hm.lib.homeManagerConfiguration {
extraSpecialArgs = args // { hostname = host; }; extraSpecialArgs = args // { hostname = host; };
inherit pkgs; inherit pkgs;

View file

@ -21,7 +21,7 @@
tailscale.enable = true; tailscale.enable = true;
openssh = { openssh = {
enable = true; enable = true;
settings.PermitRootLogin = "prohibit-password"; settings.PermitRootLogin = "yes";
}; };
}; };
users.users."${username}" = { users.users."${username}" = {

View file

@ -1,12 +1,4 @@
let {
d = dest: { inherit dest; auth = false; };
da = dest: { inherit dest; auth = true; };
ext4 = path: { inherit path; type = "ext4"; };
btrfs = path: { inherit path; type = "btrfs"; };
selfSigned = service: { inherit service; originRequest.noTLSVerify = true; };
in {
flake-path = "~/Projects/nix-flake"; # set this to the cloned repo path flake-path = "~/Projects/nix-flake"; # set this to the cloned repo path
username = "satr14"; username = "satr14";
@ -23,78 +15,20 @@ in {
homelab = rec { homelab = rec {
domain = "satr14.my.id"; # root domain for dns, ssl certs, reverse proxy, etc. domain = "satr14.my.id"; # root domain for dns, ssl certs, reverse proxy, etc.
ssh-keys = [ cf-tunnel-id = "26318288-cdd7-4e58-904b-c45f10d3e40a";
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIESvQFXoUBafatqnxTd6qk3WEOcfwb3AIWVTstR3lHzX forgejo"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJtdH1YqRH9xhuHMivezLvj/hpH77yfH3HUCaRboB/hb forgejo-deploy-runner"
];
disks = { disks = {
# gallery = ext4 "/dev/disk/by-uuid/834f51c1-90ee-4601-ba76-ef0419198d67"; # disk for photo gallery gallery = "/dev/disk/by-uuid/834f51c1-90ee-4601-ba76-ef0419198d67"; # disk for photo gallery
# data = ext4 "/dev/disk/by-uuid/a5752dd6-092d-484c-969c-2fdc7cb4a5f0"; # disk for app data data = "/dev/disk/by-uuid/a5752dd6-092d-484c-969c-2fdc7cb4a5f0"; # disk for app data
# host = ext4 "/dev/disk/by-uuid/968f14a4-631e-4325-8cd1-f9aec0da9e4d"; # disk for media collection (named host for backwards compatibility) host = "/dev/disk/by-uuid/968f14a4-631e-4325-8cd1-f9aec0da9e4d"; # disk for media collection (named host for backwards compatibility)
# ^^ virtual disks
# achive = ext4 "/dev/disk/by-uuid/"; # long term archival
data = ext4 "/dev/disk/by-uuid/aa453135-4b7a-4b12-8efc-f3dda093d2b7"; # app data
share = btrfs "/dev/disk/by-uuid/f1ee1d17-e852-4e02-ae86-eaf6116a2aeb"; # file server
};
dash = [
[ "PocketID" "authentik" "https://auth.${domain}" "http://localhost:1411/" ]
[ "Forgejo" "forgejo" "https://git.${domain}" "http://localhost:5080/" ]
[ "Copyparty" "files" "https://cdn.${domain}" "http://localhost:3923/" ]
[ "CryptPad" "cryptpad" "https://docs.${domain}" "http://localhost:7090/" ]
[ "CodeServer" "coder" "https://code.proxy.${domain}" "http://localhost:8443/" ]
[ "AdGuardHome" "adguard" "https://dns.proxy.${domain}" "http://localhost:8088/" ]
[ "Traefik" "traefikproxy" "https://dynamic.proxy.${domain}/dashboard/" "" ]
[ "Immich" "immich" "https://gallery.proxy.${domain}" "http://localhost:2283/" ]
[ "Jellyfin" "jellyfin" "https://media.proxy.${domain}" "http://localhost:8096/" ]
[ "VaultWarden" "vaultwarden" "https://pass.proxy.${domain}" "http://localhost:8060/" ]
[ "Ollama" "ollama" "https://ai.proxy.${domain}" "http://localhost:8080/" ]
[ "Ntfy" "ntfy" "https://notify.proxy.${domain}" "http://localhost:8067/" ]
[ "SearXNG" "searxng" "https://search.proxy.${domain}" "http://localhost:8091/" ]
[ "Dockge" "docker" "https://containers.proxy.${domain}" "http://localhost:5001/" ]
];
routes = {
"mc0.${domain}" = "tcp://localhost:25565";
"docs-sandbox.${domain}" = "http://localhost:7090";
"docs.${domain}" = "http://localhost:7090";
"cdn.${domain}" = selfSigned "https://localhost:3923";
"git.${domain}" = "http://localhost:5080";
"auth.${domain}" = "http://localhost:1411";
"dash.${domain}" = "http://localhost:5070";
"media.${domain}" = "http://localhost:8096";
"gallery.${domain}" = "http://localhost:2284";
};
proxy = {
base = "proxy.${domain}";
hosts = {
"containers" = da "http://localhost:5001";
"code" = da "http://localhost:8443";
"dns" = da "http://localhost:8088";
"gallery" = d "http://localhost:2283";
"dynamic" = d "http://localhost:8082";
"search" = d "http://localhost:8091";
"notify" = d "http://localhost:8067";
"media" = d "http://localhost:8096";
"pass" = d "http://localhost:8060";
"auth" = d "http://localhost:1411";
"git" = d "http://localhost:5080";
"cdn" = d "http://localhost:3923";
"ai" = d "http://localhost:8080";
"@" = d "http://localhost:5070";
};
redirects = {
"www" = "https://${proxy.base}";
"dash" = "https://${proxy.base}";
"immich" = "https://gallery.${proxy.base}";
"2fa" = "https://2fa.${domain}";
};
}; };
records = [ records = [
[ "main.dns.${domain}" "100.113.147.93" ] # this machine [ "server.dns.${domain}" "10.3.14.69" ]
[ "router.dns.${domain}" "10.3.14.1" ]
[ "home.dns.${domain}" "10.3.14.235" ]
[ "workspace.dns.${domain}" "10.3.14.57" ]
[ "old-main.dns.${domain}" "10.3.14.42" ] # old main machine for connecting while migrating
[ "main.dns.${domain}" "10.3.14.215" ] # this machine
[ "proxy.${domain}" "main.dns.${domain}" ] [ "proxy.${domain}" "main.dns.${domain}" ]
[ "*.proxy.${domain}" "proxy.${domain}" ] [ "*.proxy.${domain}" "proxy.${domain}" ]
@ -128,9 +62,7 @@ in {
}; };
git = { # setup your git author git = { # setup your git author
username = "satr14"; # forgejo username user = "Satria";
server = "https://git.satr14.my.id"; # forgejo server url
user = "satr14";
email = "admin@satr14.my.id"; email = "admin@satr14.my.id";
}; };
} }

View file

@ -1,13 +1,14 @@
{ ... }: { { ... }: {
imports = [ imports = [
# ./misc/cpu-hotplug.nix
# ./misc/serial.nix
# ./misc/qemu-virtio.nix
# ^^ only used if vm
./core/firmware.nix ./core/firmware.nix
./core/igpu.nix ./core/igpu.nix
./misc/disks.nix ./misc/disks.nix
./misc/serial.nix
]; ];
boot.initrd.availableKernelModules = [ "virtio_net" "virtio_pci" "virtio_mmio" "virtio_blk" "virtio_scsi" "virtio_console" ];
services = {
qemuGuest.enable = true;
spice-vdagentd.enable = true;
};
} }

View file

@ -1,4 +1,4 @@
{ pkgs, username, resume-dev, ... }: { { pkgs, resume-dev, ... }: {
powerManagement.powertop.enable = true; powerManagement.powertop.enable = true;
services = { services = {
@ -10,20 +10,6 @@
echo 85 > /sys/class/power_supply/BAT*/charge_control_end_threshold || true echo 85 > /sys/class/power_supply/BAT*/charge_control_end_threshold || true
''}" ''}"
''; '';
cron = {
enable = true;
systemCronJobs = [
"* * * * * ${username} bash -x ${pkgs.writeShellScript "low-battery-notifier" ''
BAT_PCT=`${pkgs.acpi}/bin/acpi -b | ${pkgs.gnugrep}/bin/grep -P -o '[0-9]+(?=%)'`
BAT_STA=`${pkgs.acpi}/bin/acpi -b | ${pkgs.gnugrep}/bin/grep -P -o '\w+(?=,)'`
echo "`date` battery status:$BAT_STA percentage:$BAT_PCT"
export DISPLAY=:0
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus
test $BAT_PCT -le 30 && test $BAT_PCT -gt 15 && test $BAT_STA = "Discharging" && ${pkgs.libnotify}/bin/notify-send "Low Battery" "Battery remaining: $BAT_PCT%."
test $BAT_PCT -le 15 && test $BAT_STA = "Discharging" && ${pkgs.libnotify}/bin/notify-send -u critical "Low Battery" "Shutdown at 10%."
''} > /tmp/cron.batt.log 2>&1"
];
};
upower = { upower = {
enable = true; enable = true;
percentageCritical = 15; percentageCritical = 15;

View file

@ -51,7 +51,7 @@
enable = true; # wait for fix: https://github.com/AdnanHodzic/auto-cpufreq/issues/906 enable = true; # wait for fix: https://github.com/AdnanHodzic/auto-cpufreq/issues/906
settings = { settings = {
charger = { charger = {
governor = "powersave"; # "performance"; governor = "performance";
energy_performance_preference = "performance"; energy_performance_preference = "performance";
turbo = "always"; turbo = "always";
platform_profile = "performance"; platform_profile = "performance";

View file

@ -1,5 +0,0 @@
{ ... }: {
services.udev.extraRules = ''
SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", ATTR{online}="1"
'';
}

View file

@ -1,15 +1,13 @@
{ lib, homelab, ... }: let { lib, homelab, ... }: let
globalOpts = { globalOpts = {
fsType = "ext4";
autoFormat = true; autoFormat = true;
autoResize = true; autoResize = true;
}; };
in { in {
fileSystems = { fileSystems = {
"/".autoResize = true; "/".autoResize = true;
} // lib.mapAttrs' (name: dev: } // lib.mapAttrs' (name: device:
lib.nameValuePair "/mnt/${name}" (globalOpts // { lib.nameValuePair "/mnt/${name}" (globalOpts // { inherit device; })
device = dev.path;
fsType = dev.type;
})
) homelab.disks; ) homelab.disks;
} }

View file

@ -1,14 +0,0 @@
{ ... }: {
boot.initrd.availableKernelModules = [
"virtio_net"
"virtio_pci"
"virtio_mmio"
"virtio_blk"
"virtio_scsi"
"virtio_console"
];
services = {
qemuGuest.enable = true;
spice-vdagentd.enable = true;
};
}

View file

@ -12,7 +12,7 @@
]; ];
boot = { boot = {
kernelPackages = pkgs.linuxPackages_zen; kernelPackages = pkgs.linuxPackages;
kernel.sysctl."vm.laptop_mode" = 5; kernel.sysctl."vm.laptop_mode" = 5;
initrd.availableKernelModules = [ "thinkpad_acpi" ]; initrd.availableKernelModules = [ "thinkpad_acpi" ];
kernelParams = [ kernelParams = [

View file

@ -1,69 +1,44 @@
{ pkgs, ... }: { { pkgs, ... }: {
nixpkgs.config.allowUnfree = true; nixpkgs.config.allowUnfree = true;
xdg = {
autostart.enable = true;
mimeApps = {
enable = true;
defaultApplications = {
"text/plain" = "nvim.desktop";
"text/html" = "brave-browser.desktop";
"application/pdf" = "brave-browser.desktop";
"x-scheme-handler/http" = "brave-browser.desktop";
"x-scheme-handler/https" = "brave-browser.desktop";
"x-terminal-emulator" = "kitty.desktop";
"inode/directory" = "pcmanfm-qt.desktop";
"audio/mpeg" = "vlc.desktop";
"audio/mp3" = "vlc.desktop";
"audio/wav" = "vlc.desktop";
"audio/flac" = "vlc.desktop";
"video/mp4" = "vlc.desktop";
"video/x-matroska" = "vlc.desktop";
"video/webm" = "vlc.desktop";
"video/x-msvideo" = "vlc.desktop";
};
};
};
home.packages = with pkgs; [ home.packages = with pkgs; [
zed-editor zed-editor
# kicad-small # kicad-small
# arduino-ide # arduino-ide
slack slack
discord discord
# protonmail-desktop # https://www.reddit.com/r/NixOS/comments/1rm9alf/protonmail_in_nixos/ protonmail-desktop
vlc vlc
brave brave
flameshot libreoffice
libreoffice appimage-run
appimage-run # keepassxc
# keepassxc
virt-manager virt-manager
# winboat # winboat
remmina remmina
moonlight-qt moonlight-qt
# rustdesk # rustdesk
# inkscape # inkscape
# davinci-resolve # davinci-resolve
# kdePackages.kdenlive # kdePackages.kdenlive
(wrapOBS { (wrapOBS {
plugins = with obs-studio-plugins; [ plugins = with obs-studio-plugins; [
wlrobs wlrobs
obs-backgroundremoval obs-backgroundremoval
obs-pipewire-audio-capture obs-pipewire-audio-capture
]; ];
}) })
ferium ferium
packwiz portablemc
portablemc prismlauncher
steamguard-cli steamguard-cli
# modrinth-app # modrinth-app
]; ];
} }

View file

@ -44,26 +44,13 @@
enable = true; enable = true;
defaultEditor = true; defaultEditor = true;
vimAlias = true; vimAlias = true;
withRuby = false;
withPython3 = false;
initLua = '' initLua = ''
vim.opt.clipboard = "unnamedplus" vim.opt.clipboard = "unnamedplus"
vim.opt.termguicolors = true vim.opt.termguicolors = true
vim.g.clipboard = {
name = "OSC 52",
copy = {
["+"] = require("vim.ui.clipboard.osc52").copy("+"),
["*"] = require("vim.ui.clipboard.osc52").copy("*"),
},
paste = {
["+"] = require("vim.ui.clipboard.osc52").paste("+"),
["*"] = require("vim.ui.clipboard.osc52").paste("*"),
},
}
require("nvim-tree").setup() require("nvim-tree").setup()
vim.api.nvim_create_autocmd("VimEnter", { vim.api.nvim_create_autocmd("VimEnter", {
callback = function() callback = function()
vim.cmd("set nu") -- vim.cmd("NvimTreeOpen")
vim.cmd.wincmd 'p' vim.cmd.wincmd 'p'
end, end,
}) })
@ -76,6 +63,7 @@
telescope-file-browser-nvim telescope-file-browser-nvim
nvim-tree-lua nvim-tree-lua
nvim-cmp nvim-cmp
barbar-nvim
indent-blankline-nvim indent-blankline-nvim
markdown-preview-nvim markdown-preview-nvim
]; ];
@ -92,7 +80,6 @@
}; };
git = { git = {
enable = true; enable = true;
signing.format = null;
settings = { settings = {
pull.rebase = "true"; pull.rebase = "true";
credential.helper = "cache --timeout=3600"; credential.helper = "cache --timeout=3600";

26
modules/home/core/xdg.nix Normal file
View file

@ -0,0 +1,26 @@
{ ... }: {
xdg = {
autostart.enable = true;
mimeApps = {
enable = true;
defaultApplications = {
"text/plain" = "nvim.desktop";
"text/html" = "brave-browser.desktop";
"application/pdf" = "brave-browser.desktop";
"x-scheme-handler/http" = "brave-browser.desktop";
"x-scheme-handler/https" = "brave-browser.desktop";
"x-scheme-handler/terminal" = "kitty.desktop";
"x-terminal-emulator" = "kitty.desktop";
"inode/directory" = "pcmanfm-qt.desktop";
"audio/mpeg" = "vlc.desktop";
"audio/mp3" = "vlc.desktop";
"audio/wav" = "vlc.desktop";
"audio/flac" = "vlc.desktop";
"video/mp4" = "vlc.desktop";
"video/x-matroska" = "vlc.desktop";
"video/webm" = "vlc.desktop";
"video/x-msvideo" = "vlc.desktop";
};
};
};
}

View file

@ -2,18 +2,10 @@
programs.zed-editor = { programs.zed-editor = {
enable = true; enable = true;
package = pkgs.zed-editor; package = pkgs.zed-editor;
extensions = [ extensions = [ "nix" ];
"html" "html-snippets"
"svelte" "svelte-snippets"
"wakatime" "discord-presence"
"catppuccin" "catppuccin-icons"
"git-firefly"
"nix"
];
userSettings = { userSettings = {
diff_view_style = "unified";
cli_default_open_behavior = "existing_window";
format_on_save = "off"; format_on_save = "off";
features.edit_prediction_provider = "copilot";
vim_mode = true; vim_mode = true;
git.inline_blame.enabled = true; git.inline_blame.enabled = true;
gutter.line_numbers = true; gutter.line_numbers = true;
@ -27,27 +19,6 @@
file_types.tailwindcss = [ "*.css" ]; file_types.tailwindcss = [ "*.css" ];
auto_install_extensions.catppuccin-icons = true; auto_install_extensions.catppuccin-icons = true;
icon_theme = "Catppuccin Mocha"; icon_theme = "Catppuccin Mocha";
git_panel.tree_view = true;
diagnostics = {
button = true;
include_warnings = true;
inline = {
enabled = true;
update_debounce_ms = 150;
padding = 4;
min_column = 0;
max_severity = null;
};
};
agent = {
tool_permissions.default = "allow";
default_model = {
provider = "copilot_chat";
model = "claude-sonnet-4.6";
effort = "high";
enable_thinking = false;
};
};
theme = { theme = {
mode = "dark"; mode = "dark";
light = "Catppuccin Mocha (sapphire)"; light = "Catppuccin Mocha (sapphire)";

View file

@ -1,4 +1,4 @@
{ git, hostname, flake-path, zsh-theme, ... }: { { hostname, flake-path, zsh-theme, ... }: {
programs = { programs = {
pay-respects = { pay-respects = {
enable = true; enable = true;
@ -32,14 +32,14 @@
''; '';
shellAliases = { shellAliases = {
"cd-gvfs" = "cd /run/user/$(id -u)/gvfs"; "cd-gvfs" = "cd /run/user/$(id -u)/gvfs";
"wlp-set" = "awww img --transition-type=grow --transition-duration=1"; "wlp-set" = "swww img --transition-type=grow --transition-duration=1";
"ssh" = "TERM=xterm-256color ssh"; "ssh" = "TERM=xterm-256color ssh";
"cd" = "z"; "cd" = "z";
"sys" = "sudo systemctl --runtime"; "sys" = "sudo systemctl --runtime";
"sys-log" = "journalctl -o cat -f -b -u"; "sys-log" = "journalctl -f -b -u";
"user" = "systemctl --user --runtime"; "user" = "systemctl --user --runtime";
"user-log" = "journalctl -o cat -f -b --user-unit"; "user-log" = "journalctl -f -b --user-unit";
"ts" = "sudo tailscale"; "ts" = "sudo tailscale";
"tsip" = "tailscale ip -4"; "tsip" = "tailscale ip -4";
@ -64,10 +64,9 @@
"wm-disp" = "wm-ctl dispatch dpms"; "wm-disp" = "wm-ctl dispatch dpms";
"gh-author-setup" = "git config user.name $(gh api -H \"Accept: application/vnd.github+json\" -H \"X-GitHub-Api-Version: 2022-11-28\" /user | jq -r .login) && git config user.email $(gh api -H \"Accept: application/vnd.github+json\" -H \"X-GitHub-Api-Version: 2022-11-28\" /user/emails | jq -r \".[1].email\")"; "gh-author-setup" = "git config user.name $(gh api -H \"Accept: application/vnd.github+json\" -H \"X-GitHub-Api-Version: 2022-11-28\" /user | jq -r .login) && git config user.email $(gh api -H \"Accept: application/vnd.github+json\" -H \"X-GitHub-Api-Version: 2022-11-28\" /user/emails | jq -r \".[1].email\")";
"fg-create-repo" = "git remote add origin ${git.server}/${git.username}/$(basename $PWDw).git && git push";
"convert-pdf" = "libreoffice --headless --convert-to pdf"; "convert-pdf" = "libreoffice --headless --convert-to pdf";
"mcl" = "portablemc start -l $(cat ~/.minecraft/portablemc-launch-params.json | jq -r .email) $(cat ~/.minecraft/portablemc-launch-params.json | jq -r .version)"; "mcl" = "portablemc start -l $(cat .minecraft/portablemc-launch-params.json | jq -r .email) $(cat .minecraft/portablemc-launch-params.json | jq -r .version)";
"mc" = "ferium upgrade; mcl"; "mc" = "ferium upgrade; mcl";
}; };
initContent = '' initContent = ''

View file

@ -1,16 +1,8 @@
{ username, ctp-opt, ... }: { { username, ... }: {
imports = [ imports = [
./core/shell.nix
./core/cli.nix ./core/cli.nix
./core/zsh.nix
]; ];
catppuccin = {
enable = true;
hyprlock.useDefaultConfig = false;
flavor = ctp-opt.flavor;
accent = ctp-opt.accent;
};
home = { home = {
stateVersion = "24.11"; stateVersion = "24.11";

View file

@ -1,23 +1,23 @@
{ pkgs, ... }: { { pkgs, ... }: {
imports = [ imports = [
./rice/compositor.nix ./rice/hyprland.nix
./rice/lockscreen.nix ./rice/hyprlock.nix
./rice/keybinds.nix ./rice/waybar.nix
./rice/logout.nix ./rice/rofi.nix
./rice/notifs.nix ./rice/wlogout.nix
./rice/hypridle.nix
./rice/dunst.nix
./rice/cursor.nix ./rice/cursor.nix
./rice/theme.nix ./rice/theme.nix
./rice/menu.nix ./rice/keybinds.nix
./rice/idle.nix ./misc/kde-connect.nix
./rice/bar.nix
./misc/handlers.nix
./misc/phone.nix
./core/apps.nix ./core/apps.nix
./core/code.nix ./core/zed.nix
./core/xdg.nix
]; ];
services = { services = {
awww.enable = true; swww.enable = true;
hyprpolkitagent.enable = true; hyprpolkitagent.enable = true;
}; };

View file

@ -1,18 +0,0 @@
{ pkgs, ... }:
let
ferium-installer-script = pkgs.writeShellScript "ferium-installer" ''
mod=$(echo "$1" | awk -F'/' '{print $NF}')
${pkgs.kitty}/bin/kitty sh -c "ferium add $mod; read"
'';
in
{
xdg.desktopEntries."ferium-installer" = {
name = "Intercept Modrinth Links to Ferium";
exec = "${ferium-installer-script} %u";
mimeType = [ "x-scheme-handler/modrinth" ];
};
xdg.mimeApps.defaultApplications = {
"x-scheme-handler/modrinth" = "ferium-installer.desktop";
};
}

View file

@ -6,7 +6,7 @@
lock_cmd = "hyprlock"; lock_cmd = "hyprlock";
unlock_cmd = "pkill -USR1 hyprlock"; unlock_cmd = "pkill -USR1 hyprlock";
before_sleep_cmd = "hyprctl dispatch dpms off && hyprlock"; before_sleep_cmd = "hyprctl dispatch dpms off && hyprlock";
after_sleep_cmd = "hyprctl dispatch dpms on"; after_sleep_cmd = "hyprctl dispatch dpms on && pkill -USR2 hyprlock";
}; };
listener = [ listener = [
{ {

View file

@ -30,7 +30,7 @@
#"dunst &" #"dunst &"
#"hypridle &" #"hypridle &"
#"awww-daemon &" #"swww-daemon &"
"uwsm app -s s -- waybar &" "uwsm app -s s -- waybar &"
"uwsm app -s b -- sunshine &" "uwsm app -s b -- sunshine &"
@ -51,7 +51,6 @@
"GTK_APPLICATION_PREFER_DARK_THEME,1" "GTK_APPLICATION_PREFER_DARK_THEME,1"
"GTK_THEME,Adwaita:dark" "GTK_THEME,Adwaita:dark"
"QT_QPA_PLATFORMTHEME,kvantum" "QT_QPA_PLATFORMTHEME,kvantum"
"QT_STYLE_OVERRIDE,kvantum"
]; ];
general = { general = {
@ -141,7 +140,7 @@
layerrule = [ layerrule = [
"no_anim on, match:namespace selection" # hyprshot overlay "no_anim on, match:namespace selection" # hyprshot overlay
"no_anim on, match:namespace hyprpicker" "no_anim on, match:namespace hyprpicker"
"animation fade, match:namespace awww-daemon" "animation fade, match:namespace swww-daemon"
"animation fade, match:namespace logout_dialog" "animation fade, match:namespace logout_dialog"
"animation fade, match:namespace hyprshutdown" "animation fade, match:namespace hyprshutdown"
"above_lock 2, match:namespace notifications" "above_lock 2, match:namespace notifications"
@ -156,8 +155,7 @@
"stay_focused on, suppress_event fullscreen maximize, dim_around on, float on, match:title ^(Hyprland Polkit Agent|Unlock Login Keyring|KeePassXC -.*)$" "stay_focused on, suppress_event fullscreen maximize, dim_around on, float on, match:title ^(Hyprland Polkit Agent|Unlock Login Keyring|KeePassXC -.*)$"
"float on, match:title ^(Open|Print|Save|Rename|Move|Copy|Confirm).*" "float on, match:title ^(Open|Print|Save|Rename|Move|Copy|Confirm).*"
"float on, match:title ^(Preferences|Settings|Options|About|Passbolt).*" "float on, match:title ^(Preferences|Settings|Options|About|Passbolt).*"
"float on, match:title ^(MainPicker|Volume Control|File Operation Progress|Network Connections|Choose an Application)$" "float on, match:title ^(MainPicker|Volume Control|File Operation Progress|Network Connections|Choose an Application| )$"
"float on, match:title ^(Please wait)$"
]; ];
}; };
}; };

View file

@ -95,10 +95,10 @@
"SUPER, N, exec, uwsm app -- rofi-network-manager" "SUPER, N, exec, uwsm app -- rofi-network-manager"
"SUPER, J, exec, notify-send -u critical ${hostname} 'Caffein Mode' && notify-send '(SUPER+X to reset)' && systemctl --user stop hypridle" "SUPER, J, exec, notify-send -u critical ${hostname} 'Caffein Mode' && notify-send '(SUPER+X to reset)' && systemctl --user stop hypridle"
"SUPER, K, exec, notify-send -u critical ${hostname} 'Focus Mode' && notify-send '(SUPER+X to reset)' && systemctl --user stop awww && pkill -SIGUSR1 waybar && hyprctl --batch 'keyword decoration:inactive_opacity 1.0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword decoration:shadow:enabled false'" "SUPER, K, exec, notify-send -u critical ${hostname} 'Focus Mode' && notify-send '(SUPER+X to reset)' && systemctl --user stop swww && pkill -SIGUSR1 waybar && hyprctl --batch 'keyword decoration:inactive_opacity 1.0; keyword decoration:blur:enabled 0; keyword general:gaps_in 0; keyword general:gaps_out 0; keyword general:border_size 1; keyword decoration:rounding 0; keyword decoration:shadow:enabled false'"
"SUPER, B, submap, disabled-all-keybinds" "SUPER, B, submap, disabled-all-keybinds"
"SUPER, H, exec, notify-send ${hostname} 'Animations Off' && hyprctl keyword animations:enabled 0" "SUPER, H, exec, notify-send ${hostname} 'Animations Off' && hyprctl keyword animations:enabled 0"
"SUPER, X, exec, dunstctl close-all && hyprctl reload && hyprctl dispatch submap reset && pkill -SIGUSR2 waybar && systemctl --user restart awww hypridle fusuma" "SUPER, X, exec, dunstctl close-all && hyprctl reload && hyprctl dispatch submap reset && pkill -SIGUSR2 waybar && systemctl --user restart swww hypridle fusuma"
"SUPER, Z, exec, dunstctl close-all" "SUPER, Z, exec, dunstctl close-all"
"SUPER SHIFT, S, exec, hyprshot -zm region -o ~/Pictures/Screenshots; killall -9 hyprpicker hyprshot" "SUPER SHIFT, S, exec, hyprshot -zm region -o ~/Pictures/Screenshots; killall -9 hyprpicker hyprshot"
@ -106,7 +106,9 @@
", PRINT, exec, hyprshot -zm region -o ~/Pictures/Screenshots; killall -9 hyprpicker hyprshot" ", PRINT, exec, hyprshot -zm region -o ~/Pictures/Screenshots; killall -9 hyprpicker hyprshot"
"SUPER, R, exec, rofi -show drun -show-icons -display-drun '' -run-command \"uwsm app -- {cmd}\"" "SUPER, R, exec, rofi -show drun -show-icons -display-drun '' -run-command \"uwsm app -- {cmd}\""
"SUPER, RETURN, exec, ls ~/Projects | rofi -dmenu -p \"Open Project\" | xargs -I {} sh -c 'mkdir -p ~/Projects/\"{}\" && zeditor ~/Projects/\"{}\"'" "SUPER, RETURN, exec, rofi -show window -show-icons -drun-display '' -window-format '{c} {t}'"
"SUPER CTRL, RETURN, exec, rofi rofi -dmenu -p 'run nixpkgs' -lines 0 < /dev/null | xargs -r -I {} kitty -- nix run 'nixpkgs#{}'"
"SUPER ALT, RETURN, exec, rofi rofi -dmenu -p 'shell nixpkgs' -lines 0 < /dev/null | xargs -r -I {} kitty -- nde`ix shell 'nixpkgs#{}'"
"SUPER, V, exec, rofi -modi clipboard:cliphist-rofi-img -show clipboard -show-icons" "SUPER, V, exec, rofi -modi clipboard:cliphist-rofi-img -show clipboard -show-icons"
# "SUPER, B, exec, rofi -show calc -modi calc -no-show-match -no-sort" # "SUPER, B, exec, rofi -show calc -modi calc -no-show-match -no-sort"
@ -124,9 +126,8 @@
"SUPER, W, fullscreen, 1" "SUPER, W, fullscreen, 1"
"SUPER, S, fullscreen, 0" "SUPER, S, fullscreen, 0"
"SUPER, F, togglefloating," "SUPER, F, togglefloating,"
"SUPER, G, layoutmsg, togglesplit" "SUPER, G, togglesplit,"
"SUPER, L, exec, loginctl lock-session" "SUPER, L, exec, loginctl lock-session"
"SUPER SHIFT, L, exec, hyprctl dispatch dpms off && loginctl lock-session && sleep 1 && hyprctl dispatch dpms on"
"SUPER, down, togglespecialworkspace, hidden" "SUPER, down, togglespecialworkspace, hidden"
"SUPER SHIFT, down, movetoworkspace, special:hidden" "SUPER SHIFT, down, movetoworkspace, special:hidden"

View file

@ -1,16 +1,23 @@
{ lib, pkgs, ctp-opt, rice, ... }: { { lib, pkgs, ctp-opt, rice, ... }: {
catppuccin = {
enable = true;
hyprlock.useDefaultConfig = false;
flavor = ctp-opt.flavor;
accent = ctp-opt.accent;
};
dconf = { dconf = {
enable = true; enable = true;
settings."org/gnome/desktop/interface" = { settings."org/gnome/desktop/interface" = {
color-scheme = "prefer-dark"; color-scheme = "prefer-dark";
gtk-theme = lib.mkForce "Adwaita-dark"; gtk-theme = "Adwaita-dark";
}; };
}; };
gtk = { gtk = {
enable = true; enable = true;
gtk3.extraConfig.gtk-application-prefer-dark-theme = 1; gtk3.extraConfig.gtk-application-prefer-dark-theme = 1;
gtk4.theme = null;
iconTheme = { iconTheme = {
name = "Papirus-Dark"; name = "Papirus-Dark";
package = lib.mkForce pkgs.papirus-icon-theme; package = lib.mkForce pkgs.papirus-icon-theme;
@ -23,11 +30,6 @@
qt = { qt = {
enable = true; enable = true;
kvantum = {
enable = true;
themes = with pkgs; [ catppuccin-kvantum ];
settings.General.theme = "catppuccin-${ctp-opt.flavor}-${ctp-opt.accent}";
};
platformTheme.name = "kvantum"; platformTheme.name = "kvantum";
style = { style = {
name = "kvantum"; name = "kvantum";

View file

@ -45,8 +45,8 @@
interval = 1; interval = 1;
format = " {usage:2}% {avg_frequency}GHz"; format = " {usage:2}% {avg_frequency}GHz";
on-click = "auto-cpufreq-gtk"; on-click = "auto-cpufreq-gtk";
on-click-right = "pkexec auto-cpufreq --force powersave && notify-send ${hostname} \"CPU Governor Powersave Overide\""; on-click-right = "pkexec tlp power-saver && notify-send ${hostname} \"TLP set to: $(tlp-stat -s | grep 'Power profile' | awk -F '=' '{print $2}' | xargs)\"";
on-click-middle = "pkexec auto-cpufreq --force reset && notify-send ${hostname} \"CPU Governor Overide Reset\""; on-click-middle = "pkexec tlp start && notify-send ${hostname} \"TLP set to: $(tlp-stat -s | grep 'Power profile' | awk -F '=' '{print $2}' | xargs)\"";
}; };
"memory" = { "memory" = {
states = { states = {

View file

@ -5,35 +5,26 @@
{ {
imports = imports =
[ (modulesPath + "/installer/scan/not-detected.nix") [ (modulesPath + "/profiles/qemu-guest.nix")
]; ];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usbhid" "uas" "usb_storage" "sd_mod" ]; boot.initrd.availableKernelModules = [ "uhci_hcd" "ehci_pci" "ahci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
boot.initrd.kernelModules = [ ]; boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ]; boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ]; boot.extraModulePackages = [ ];
fileSystems."/" = fileSystems."/" =
{ device = "/dev/disk/by-uuid/e5a7d45d-b9e9-43e7-ba5f-f4e67821bd0b"; { device = "/dev/disk/by-uuid/e33ab472-e518-4b4d-89d1-d75cfecb9f06";
fsType = "ext4"; fsType = "ext4";
}; };
fileSystems."/boot" = fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/EC01-36B5"; { device = "/dev/disk/by-uuid/880C-9F0A";
fsType = "vfat"; fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ]; options = [ "fmask=0077" "dmask=0077" ];
}; };
swapDevices = [ ]; swapDevices = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp2s0.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp3s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; }
}

View file

@ -5,16 +5,15 @@
host = "127.0.0.1"; host = "127.0.0.1";
port = 11434; port = 11434;
user = "ollama"; user = "ollama";
home = "/mnt/data/apps/ollama"; home = "/mnt/data/ollama";
loadModels = [ loadModels = [
"gemma3n:e4b" # "gemma3n:e2b" "gemma3n:e4b" # "gemma3n:e2b"
"qwen3-coder-next:cloud" # "codellama:7b" "starcoder:3b" # "codellama:7b" "starcoder:3b"
]; ];
}; };
open-webui = { open-webui = {
enable = true; enable = true;
port = 8080; port = 8080;
environmentFile = "/mnt/data/apps/ollama/.env";
environment = { environment = {
OLLAMA_BASE_URL = "http://localhost:11434"; OLLAMA_BASE_URL = "http://localhost:11434";
# WEBUI_AUTH = "False"; # WEBUI_AUTH = "False";

View file

@ -1,8 +1,8 @@
{ homelab, ... }: { { config, homelab, ... }: {
services.pocket-id = { services.pocket-id = {
enable = true; enable = true;
credentials.ENCRYPTION_KEY = "/mnt/data/apps/pocketid/encryption-key"; credentials.ENCRYPTION_KEY = config.sops.secrets.pocketid_encryption_key.path;
dataDir = "/mnt/data/apps/pocketid/data"; dataDir = "/mnt/data/pocketid/data";
settings = { settings = {
PORT = "1411"; PORT = "1411";
HOST = "127.0.0.1"; HOST = "127.0.0.1";

View file

@ -1,14 +0,0 @@
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [ copyparty-most ];
systemd.services.copyparty = {
description = "File Sharing Service";
enable = true;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.copyparty-most}/bin/copyparty -c /mnt/share/cfg/files.conf";
Restart = "on-failure";
};
};
}

View file

@ -1,12 +0,0 @@
{ username, ... }: {
services.code-server = {
enable = true;
host = "127.0.0.1";
port = 8443;
user = username;
auth = "none";
disableTelemetry = true;
extensionsDir = "/mnt/data/apps/code-server/extensions";
userDataDir = "/mnt/data/apps/code-server/user-data";
};
}

View file

@ -1,6 +1,5 @@
{ homelab, lib, ... }: let { homelab, lib, ... }: let
dockge-dir = "/mnt/data/apps/dockge"; stacks-dir = "/mnt/data/dockge/stacks";
stacks-dir = "${dockge-dir}/stacks";
in { in {
virtualisation.oci-containers.containers."dockge" = { virtualisation.oci-containers.containers."dockge" = {
image = "louislam/dockge:nightly"; image = "louislam/dockge:nightly";
@ -9,7 +8,7 @@ in {
}; };
volumes = [ volumes = [
"${stacks-dir}:${stacks-dir}:rw" "${stacks-dir}:${stacks-dir}:rw"
"${dockge-dir}/data:/app/data:rw" "/mnt/data/dockge/data:/app/data:rw"
"/var/run/docker.sock:/var/run/docker.sock:rw" "/var/run/docker.sock:/var/run/docker.sock:rw"
]; ];
ports = [ ports = [

View file

@ -1,4 +1,4 @@
{ timezone, homelab, ... }: let { config, timezone, homelab, ... }: let
rss = [ rss = [
"https://www.raspberrypi.com/news/feed/" "https://www.raspberrypi.com/news/feed/"
"https://www.jeffgeerling.com/blog.xml" "https://www.jeffgeerling.com/blog.xml"
@ -53,9 +53,31 @@
[ "Google Web Results Only" "!s" "https://google.com/search?udm=14&q={QUERY}" ] [ "Google Web Results Only" "!s" "https://google.com/search?udm=14&q={QUERY}" ]
]; ];
monitor = [ monitor = [
[ "Hypervisor" "https://10.3.14.69:8006/" ]
[ "Router" "http://10.3.14.1:80/" ]
[ "DNS" "http://localhost:8088/" ] [ "DNS" "http://localhost:8088/" ]
[ "CDN" "http://nas.local:3000/" ]
[ "Proxy" "https://proxy.${homelab.domain}/" ] [ "Proxy" "https://proxy.${homelab.domain}/" ]
]; ];
external = [
[ "Proxmox" "proxmox" "https://server.proxy.${homelab.domain}" "http://server.dns.${homelab.domain}:8006/" ]
[ "OpenWRT" "openwrt" "https://router.proxy.${homelab.domain}" "http://router.dns.${homelab.domain}:80/" ]
[ "HomeAssistant" "homeassistant" "https://home.proxy.${homelab.domain}" "http://home.dns.${homelab.domain}:8123/" ]
[ "OpenMediaVault" "openmediavault" "https://nas.local:80" "http://nas.local:80/" ]
[ "ApacheHTTPD" "apache" "https://nas.local:3000" "http://nas.local:3000/" ]
];
services = [
[ "PocketID" "authentik" "https://auth.${homelab.domain}" "http://localhost:1411/" ]
[ "Forgejo" "forgejo" "https://git.${homelab.domain}" "http://localhost:5080/" ]
[ "AdGuardHome" "adguard" "https://dns.proxy.${homelab.domain}" "http://localhost:8088/" ]
[ "Traefik" "traefikproxy" "https://dynamic.proxy.${homelab.domain}/dashboard/" "http://localhost:81/dashboard/" ]
[ "Immich" "immich" "https://gallery.proxy.${homelab.domain}" "http://localhost:2283/" ]
[ "Jellyfin" "jellyfin" "https://media.proxy.${homelab.domain}" "http://localhost:8096/" ]
[ "VaultWarden" "vaultwarden" "https://pass.proxy.${homelab.domain}" "http://localhost:8060/" ]
[ "Ollama" "ollama" "https://ai.proxy.${homelab.domain}" "http://localhost:8080/" ]
[ "Dockge" "docker" "https://containers.proxy.${homelab.domain}" "http://localhost:5001/" ]
[ "Guacamole" "apacheguacamole" "https://remote.proxy.${homelab.domain}/guacamole" "http://localhost:8085/guacamole/" ]
];
bookmarks = [ bookmarks = [
[ "Tailscale" "tailscale" "https://login.tailscale.com/" ] [ "Tailscale" "tailscale" "https://login.tailscale.com/" ]
[ "Cloudflare" "cloudflare" "https://dash.cloudflare.com/" ] [ "Cloudflare" "cloudflare" "https://dash.cloudflare.com/" ]
@ -74,6 +96,7 @@ in {
}; };
services.glance = { services.glance = {
enable = true; enable = true;
environmentFile = config.sops.secrets.glance_env.path;
settings = { settings = {
server = { server = {
host = "127.0.0.1"; host = "127.0.0.1";
@ -89,101 +112,6 @@ in {
}; };
pages = [ pages = [
{
name = "Dashboard";
show-mobile-header = true;
width = "slim";
columns = [
{
size = "small";
widgets = [
{
type = "monitor";
title = "Critical Systems";
cache = "15s";
style = "compact";
show-failing-only = true;
sites = map (e: {
same-tab = true;
allow-insecure = true;
title = builtins.elemAt e 0;
url = builtins.elemAt e 1;
}) monitor;
}
{
type = "dns-stats";
title = "DNS Stats";
service = "adguard";
url = "http://localhost:8088/";
hour-format = "12h";
}
{
type = "bookmarks";
groups = [
{
links = [{
same-tab = true;
title = "NixFlake";
icon = "si:nixos";
url = "https://flake.satr14.my.id";
}];
}
{
links = map (e: {
same-tab = true;
title = builtins.elemAt e 0;
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
alt-status-codes = [ 401 ];
}) bookmarks;
}
];
}
{
type = "to-do";
id = "tasks";
}
];
}
{
size = "full";
widgets = [
{
type = "server-stats";
servers = [{
type = "local";
mountpoints = {
"/boot".hide = true;
"/nix/store".hide = true;
"/var/lib/vaultwarden".hide = true;
"/var/lib/private/cryptpad".hide = true;
"/var/lib/acme/proxy.satr14.my.id".hide = true;
};
}];
}
{
type = "monitor";
cache = "1m";
title = "Services";
sites = map (e: {
same-tab = true;
allow-insecure = true;
title = builtins.elemAt e 0;
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
check-url = builtins.elemAt e 3;
}) homelab.dash;
}
{
type = "docker-containers";
title = "Containers";
format-container-names = true;
hide-by-default = true;
}
];
}
];
}
{ {
name = "Home"; name = "Home";
show-mobile-header = true; show-mobile-header = true;
@ -282,6 +210,107 @@ in {
} }
]; ];
} }
{
name = "Dashboard";
show-mobile-header = true;
width = "slim";
columns = [
{
size = "small";
widgets = [
{
type = "monitor";
title = "Critical Systems";
cache = "15s";
style = "compact";
show-failing-only = true;
sites = map (e: {
same-tab = true;
allow-insecure = true;
title = builtins.elemAt e 0;
url = builtins.elemAt e 1;
}) monitor;
}
{
type = "dns-stats";
title = "DNS Stats";
service = "adguard";
url = "http://localhost:8088/";
hour-format = "12h";
}
{
type = "bookmarks";
groups = [
{
links = [{
same-tab = true;
title = "NixFlake";
icon = "si:nixos";
url = "https://flake.satr14.my.id";
}];
}
{
links = map (e: {
same-tab = true;
title = builtins.elemAt e 0;
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
}) bookmarks;
}
];
}
{
type = "to-do";
id = "tasks";
}
];
}
{
size = "full";
widgets = [
{
type = "server-stats";
servers = [{
type = "local";
mountpoints."/nix/store".hide = true;
}];
}
{
type = "monitor";
cache = "1m";
title = "External";
sites = map (e: {
same-tab = true;
allow-insecure = true;
title = builtins.elemAt e 0;
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
check-url = builtins.elemAt e 3;
}) external;
}
{
type = "monitor";
cache = "1m";
title = "Services";
sites = map (e: {
same-tab = true;
allow-insecure = true;
title = builtins.elemAt e 0;
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
check-url = builtins.elemAt e 3;
}) services;
}
{
type = "docker-containers";
title = "Containers";
format-container-names = true;
hide-by-default = true;
}
];
}
];
}
]; ];
}; };
}; };

View file

@ -1,7 +0,0 @@
{ pkgs, ... }: {
services.postgresql = {
enable = true;
dataDir = "/mnt/data/apps/postgresql";
package = pkgs.postgresql_16;
};
}

View file

@ -1,46 +0,0 @@
{ lib, pkgs, homelab, ... }: let
domain = "docs.${homelab.domain}";
sandbox = "docs-sandbox.${homelab.domain}";
in {
services.cryptpad = {
enable = true;
settings = {
websocketPort = 7091;
httpPort = 7090;
httpAddress = "127.0.0.1";
httpUnsafeOrigin = "https://${domain}";
httpSafeOrigin = "https://${sandbox}";
blockDailyCheck = true;
disableIntegratedEviction = true;
adminKeys = [
"[satr14@docs.satr14.my.id/f1A82fmBuqQka2bNqrCb1WbB9r2ex5A3rdys5xLX3Hc=]"
];
};
};
systemd.tmpfiles.rules = lib.singleton "L+ /var/lib/cryptpad/customize/application_config.js - - - - ${pkgs.writeText "cryptpad-application-config.js" ''
(() => {
const factory = (AppConfig) => {
AppConfig.disableAnonymousPadCreation = true;
AppConfig.disableAnonymousStore = true;
AppConfig.defaultDarkTheme = true;
return AppConfig;
};
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory(
require('../www/common/application_config_internal.js')
);
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define(['/common/application_config_internal.js'], factory);
}
})();
''}";
fileSystems."/var/lib/private/cryptpad" = {
device = "/mnt/data/apps/cryptpad";
depends = [ "/mnt/data" ];
options = [ "bind" "nofail" ];
fsType = "none";
};
}

View file

@ -1,4 +1,4 @@
{ lib, ... }: { { lib, homelab, ... }: {
users.users.immich.extraGroups = [ "video" "render" ]; users.users.immich.extraGroups = [ "video" "render" ];
services = { services = {
@ -6,7 +6,7 @@
enable = true; enable = true;
port = 2283; port = 2283;
host = "127.0.0.1"; host = "127.0.0.1";
mediaLocation = "/mnt/data/gallery"; mediaLocation = "/mnt/gallery";
accelerationDevices = null; accelerationDevices = null;
environment.DB_URL = lib.mkForce "postgresql:///immich?host=/var/run/postgresql&user=immich"; # https://github.com/immich-app/immich/issues/26140 environment.DB_URL = lib.mkForce "postgresql:///immich?host=/var/run/postgresql&user=immich"; # https://github.com/immich-app/immich/issues/26140
machine-learning.enable = true; machine-learning.enable = true;

View file

@ -1,55 +1,48 @@
{ pkgs, homelab, ... }: { { pkgs, homelab, ... }: {
services = { services.forgejo = {
forgejo = { enable = true;
enable = true; lfs.enable = true;
lfs.enable = true; stateDir = "/mnt/data/forgejo";
stateDir = "/mnt/data/apps/forgejo"; package = pkgs.forgejo;
package = pkgs.forgejo; #secrets = {
settings = { # oauth2.JWT_SECRET = "/mnt/data/forgejo/custom/conf/oauth2_jwt_secret";
server = { # server.LFS_JWT_SECRET = "/mnt/data/forgejo/custom/conf/lfs_jwt_secret";
DISABLE_SSH = false; # security = {
START_SSH_SERVER = true; # INTERNAL_TOKEN = "/mnt/data/forgejo/custom/conf/internal_token";
SSH_DOMAIN = "main.dns.${homelab.domain}"; # SECRET_KEY = "/mnt/data/forgejo/custom/conf/secret_key";
SSH_LISTEN_HOST = "0.0.0.0"; # };
SSH_LISTEN_PORT = 5822; #};
SSH_PORT = 5822; settings = {
DOMAIN = "git.${homelab.domain}"; server = {
HTTP_ADDR = "127.0.0.1"; DISABLE_SSH = false;
HTTP_PORT = 5080; START_SSH_SERVER = true;
PROTOCOL = "http"; SSH_DOMAIN = "main.dns.${homelab.domain}";
ROOT_URL = "https://git.${homelab.domain}"; SSH_LISTEN_HOST = "0.0.0.0";
LANDING_PAGE = "explore"; SSH_LISTEN_PORT = 5822;
}; SSH_PORT = 5822;
oauth2_client.ENABLE_AUTO_REGISTRATION=true; DOMAIN = "git.${homelab.domain}";
service = { HTTP_ADDR = "127.0.0.1";
DISABLE_REGISTRATION = true; HTTP_PORT = 5080;
ENABLE_OPENID_SIGNIN = false; PROTOCOL = "http";
ENABLE_OPENID_SIGNUP = false; ROOT_URL = "https://git.${homelab.domain}";
ENABLE_INTERNAL_SIGNIN = false; LANDING_PAGE = "explore";
SHOW_REGISTRATION_BUTTON = false; };
ALLOW_ONLY_EXTERNAL_REGISTRATION = true; oauth2_client.ENABLE_AUTO_REGISTRATION=true;
ALLOW_ONLY_INTERNAL_REGISTRATION = false; service = {
REQUIRE_EXTERNAL_REGISTRATION_PASSWORD = true; DISABLE_REGISTRATION = true;
}; ENABLE_OPENID_SIGNIN = false;
user.ENABLE_FOLLOWING = false; ENABLE_OPENID_SIGNUP = false;
repository = { ENABLE_INTERNAL_SIGNIN = true; # TODO: set false after migration complete
DISABLE_STARS = true; SHOW_REGISTRATION_BUTTON = false;
DISABLE_FORKS = true; ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
ENABLE_PUSH_CREATE_USER = true; ALLOW_ONLY_INTERNAL_REGISTRATION = false;
}; REQUIRE_EXTERNAL_REGISTRATION_PASSWORD = true;
};
user.ENABLE_FOLLOWING = false;
repository = {
DISABLE_STARS = true;
DISABLE_FORKS = true;
}; };
}; };
gitea-actions-runner.instances.nixos-deploy = {
enable = true;
name = "nixos-server-runner";
url = "http://localhost:5080"; #"https://git.proxy.${homelab.domain}";
tokenFile = "/mnt/data/apps/forgejo/token-runner";
labels = [ "self-hosted:host" ];
hostPackages = with pkgs; [ bash coreutils git nix openssh bun ];
};
};
systemd.services = {
"gitea-runner-nixos-deploy".restartIfChanged = false;
"forgejo".restartIfChanged = false;
}; };
} }

View file

@ -1,114 +0,0 @@
{ inputs, lib, pkgs, ... }: let
production = true;
ram-allocation-mb = 12288;
rcon-pass = "howdy";
modpack = let
commit = "8523f89493ace13087eb68cd9fe3b5eb4f669440";
path = if production then "commit/${commit}" else "branch/main";
in pkgs.fetchPackwizModpack {
packHash = "sha256-xB9Oc/aneogSQ9r7L42vyVM6xwq+QkoTaXYNuUzeo6M=";
url = "https://git.satr14.my.id/satr14/server-modpack/raw/${path}/pack.toml";
};
in {
imports = [ inputs.mc.nixosModules.minecraft-servers ];
nixpkgs.overlays = [ inputs.mc.overlay ];
powerManagement.cpuFreqGovernor = "powersave"; # performance governor causes overheating and thermal throttling, works fine with powesave
boot.kernel.sysctl = {
"vm.nr_hugepages" = (ram-allocation-mb / 2) + 512; # (heap_mb / 2MB per page) + 512 pages (1GB) for ZGC off-heap overhead
"vm.swappiness" = 10;
};
services.minecraft-servers = {
enable = true;
eula = true;
managementSystem.systemd-socket.enable = true;
# ^^^ https://github.com/Infinidoge/nix-minecraft/issues/119
# TODO: figure out how to set gamerules on start
# gamerules to disable: locator_bar, mob_explosion_drop_decay, (and possibly) reduced_debug_info, global_sound_events
# gamerules to enable (temporarily): noend:disable_end
servers.da-s3 = {
enable = true;
autoStart = true;
restart = "always";
enableReload = production;
# extraReload = ''
# function rcon() {
# ${pkgs.rcon-cli}/bin/rcon-cli -p ${rcon-pass} $@
# }
# rcon "gamerule locator_bar false"
# rcon "gamerule mob_explosion_drop_decay false"
# rcon "gamerule reduced_debug_info false"
# rcon "gamerule global_sound_events false"
# '';
operators = lib.mkIf (!production) {
"satr14" = {
uuid = "54441a30-fe73-46e7-adca-c476bd4fc6d2";
bypassesPlayerLimit = true;
level = 4;
};
};
serverProperties = {
# server-ip = "localhost";
server-port = 25565;
server-name = "Minecraft Server";
motd = "§lSeason 3§r - §dExplorers Creativity 🔥";
log-ips = false; # TODO: figure out how to get ips from cloudflared tunnel
difficulty = "normal";
gamemode = "survival";
max-world-size = 25000;
spawn-protection = 0;
pvp = true;
online-mode = true;
enable-query = true;
enforce-secure-profile = false;
pevent-proxy-connections = false;
allow-flight = false;
player-idle-timeout = 0;
view-distance = 12;
simulation-distance = 4;
enable-rcon = true;
sync-chunk-writes = false;
"rcon.password" = rcon-pass;
"rcon.port" = 25575;
};
symlinks = lib.mapAttrs'
(name: _: lib.nameValuePair "mods/${name}" "${modpack}/mods/${name}")
(builtins.readDir "${modpack}/mods");
package = pkgs.fabricServers.fabric-1_21_11.override {
jre_headless = pkgs.javaPackages.compiler.temurin-bin.jdk-25;
loaderVersion = "0.19.2";
};
jvmOpts = let flags = [
"-Xms${toString ram-allocation-mb}M"
"-Xmx${toString ram-allocation-mb}M"
"-XX:+UseZGC" # Use ZGC (requires Java v25+, 8+ CPU cores, 10GB+ RAM)
"-XX:+UseCompactObjectHeaders" # Use compact object headers (requires Java v16+, saves a couple of bits per object)
"--add-modules=jdk.incubator.vector" # Exposes SIMD instructions (requires full JDK, useful with performance mods)
"-XX:+UseLargePages" # Large pages support (requires hugepages configured on the system)
"-XX:+AlwaysPreTouch" # Pre-allocates memory on startup, OS claims it immediately for JVM instead of negotiating it
"-XX:+DisableExplicitGC" # Disables mods from manually invoking the GC
"-XX:+PerfDisableSharedMem" # Disables constant /tmp writes for JVM metrics
"-XX:ZAllocationSpikeTolerance=5" # Helps when server is active with many players
"-XX:SoftMaxHeapSize=${toString (ram-allocation-mb - 2048)}M" # Leave 2GB headroom
"-XX:ZCollectionInterval=1" # Force a GC cycle at minimum every second
"-XX:ConcGCThreads=8" # Threads ZGC uses for concurrent work
]; in lib.concatStringsSep " " flags;
};
};
}

View file

@ -5,7 +5,6 @@
services = { services = {
jellyfin = { jellyfin = {
enable = true; enable = true;
dataDir = "/mnt/data/apps/jellyfin";
hardwareAcceleration = { hardwareAcceleration = {
enable = true; enable = true;
device = "/dev/dri/renderD128"; device = "/dev/dri/renderD128";
@ -44,4 +43,4 @@
# port = 8191; # port = 8191;
# }; # };
}; };
} }

View file

@ -1,9 +0,0 @@
{ homelab, ... }: {
services.ntfy-sh = {
enable = true;
settings = {
listen-http = "127.0.0.1:8067";
base-url = "https://ntfy.proxy.${homelab.domain}";
};
};
}

View file

@ -1,20 +1,14 @@
{ homelab, ... }: { { config, homelab, ... }: {
services.vaultwarden = { services.vaultwarden = {
enable = true; enable = true;
domain = "pass.proxy.${homelab.domain}"; domain = "pass.proxy.${homelab.domain}";
backupDir = "/mnt/data/apps/vaultwarden/backups"; backupDir = "/mnt/data/vaultwarden/backups";
environmentFile = "/mnt/data/apps/vaultwarden/.env"; environmentFile = config.sops.secrets.vaultwarden_env.path;
config = { config = {
ROCKET_PORT = 8060; ROCKET_PORT = 8060;
ROCKET_ADDRESS = "127.0.0.1"; ROCKET_ADDRESS = "127.0.0.1";
ROCKET_LOG = "critical"; ROCKET_LOG = "critical";
SIGNUPS_ALLOWED = true;
}; };
}; };
fileSystems."/var/lib/vaultwarden" = {
device = "/mnt/data/apps/vaultwarden/data";
depends = [ "/mnt/data" ];
options = [ "bind" "nofail" ];
fsType = "none";
};
} }

View file

@ -1,5 +1,28 @@
{ pkgs, homelab, lib, ... }: let { config, homelab, lib, ... }: let
htpasswd = "/mnt/data/apps/nginx/htpasswd"; base = "proxy.${homelab.domain}";
hosts = {
"server" = { dest = "https://server.dns.${homelab.domain}:8006"; auth = false; };
"router" = { dest = "http://router.dns.${homelab.domain}:80"; auth = false; };
"home" = { dest = "http://home.dns.${homelab.domain}:8123"; auth = false; };
"dynamic" = { dest = "http://127.0.0.1:8082"; auth = true; };
"dns" = { dest = "http://localhost:8088"; auth = true; };
"containers" = { dest = "http://localhost:5001"; auth = false; };
"gallery" = { dest = "http://localhost:2283"; auth = false; };
"remote" = { dest = "http://localhost:8085"; auth = false; };
"media" = { dest = "http://localhost:8096"; auth = false; };
"pass" = { dest = "http://localhost:8060"; auth = false; };
"auth" = { dest = "http://localhost:1411"; auth = false; };
"git" = { dest = "http://localhost:5080"; auth = false; };
"ai" = { dest = "http://localhost:8080"; auth = false; };
"@" = { dest = "http://localhost:5070"; auth = false; };
};
redirects = {
"www" = "https://proxy.${homelab.domain}";
"dash" = "https://${homelab.domain}";
"immich" = "https://gallery.proxy${homelab.domain}";
};
exta-conf = '' exta-conf = ''
# proxy_set_header X-Auth-User $remote_user; # proxy_set_header X-Auth-User $remote_user;
proxy_read_timeout 600s; proxy_read_timeout 600s;
@ -18,35 +41,24 @@ in {
security.acme = { security.acme = {
acceptTerms = true; acceptTerms = true;
defaults.email = "admin@${homelab.domain}"; defaults.email = "admin@${homelab.domain}";
certs."${homelab.proxy.base}" = { certs."${base}" = {
domain = "*.${homelab.proxy.base}"; domain = "*.${base}";
extraDomainNames = [ homelab.proxy.base ]; extraDomainNames = [ base ];
environmentFile = "/mnt/data/apps/acme/cf-api.env";
dnsProvider = "cloudflare"; dnsProvider = "cloudflare";
# ^^^contents: CLOUDFLARE_DNS_API_TOKEN=XXXXX environmentFile = config.sops.templates."cloudflare.env".path;
}; };
}; };
fileSystems."/var/lib/acme/${homelab.proxy.base}" = {
device = "/mnt/data/apps/acme/${homelab.proxy.base}";
depends = [ "/mnt/data" ];
options = [ "bind" "nofail" ];
fsType = "none";
};
services = { services = {
nginx = { nginx = {
enable = true; enable = true;
package = pkgs.angie;
recommendedProxySettings = true; recommendedProxySettings = true;
recommendedTlsSettings = true; recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
virtualHosts = { virtualHosts = {
"_" = { "_" = {
default = true; default = true;
forceSSL = true; forceSSL = true;
useACMEHost = homelab.proxy.base; useACMEHost = base;
# locations."/".return = "404"; # locations."/".return = "404";
locations."/" = { locations."/" = {
proxyPass = "http://127.0.0.1:81"; # traefik for docker container dynamic proxy proxyPass = "http://127.0.0.1:81"; # traefik for docker container dynamic proxy
@ -54,12 +66,12 @@ in {
extraConfig = exta-conf; extraConfig = exta-conf;
}; };
}; };
} // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair "${subdomain}.${homelab.proxy.base}" { } // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair "${subdomain}.${base}" {
useACMEHost = homelab.proxy.base; useACMEHost = base;
forceSSL = true; forceSSL = true;
locations."/".return = "301 ${cfg}"; locations."/".return = "301 ${base}";
}) homelab.proxy.redirects // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair (if subdomain == "@" then homelab.proxy.base else "${subdomain}.${homelab.proxy.base}") { }) redirects // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair (if subdomain == "@" then base else "${subdomain}.${base}") {
useACMEHost = homelab.proxy.base; useACMEHost = base;
forceSSL = true; forceSSL = true;
extraConfig = '' extraConfig = ''
access_log /var/log/nginx/${subdomain}.access.log; access_log /var/log/nginx/${subdomain}.access.log;
@ -68,16 +80,13 @@ in {
locations."/" = { locations."/" = {
proxyPass = cfg.dest; proxyPass = cfg.dest;
proxyWebsockets = true; proxyWebsockets = true;
basicAuthFile = if cfg.auth then htpasswd else null; basicAuthFile = if cfg.auth then config.sops.secrets.nginx_htpasswd.path else null;
extraConfig = exta-conf; extraConfig = exta-conf;
}; };
}) homelab.proxy.hosts; }) hosts;
}; };
traefik = { traefik = {
enable = true; enable = true;
dynamicConfigOptions = {
http.middlewares.auth.basicAuth.usersFile = htpasswd;
};
staticConfigOptions = { staticConfigOptions = {
entryPoints = { entryPoints = {
traefik.address = "127.0.0.1:8082"; traefik.address = "127.0.0.1:8082";
@ -97,8 +106,9 @@ in {
providers.docker = { providers.docker = {
endpoint = "unix:///var/run/docker.sock"; endpoint = "unix:///var/run/docker.sock";
exposedByDefault = false; exposedByDefault = false;
defaultRule = "Host(`ct-{{ normalize .Name }}.${base}`)";
}; };
}; };
}; };
}; };
} }

View file

@ -0,0 +1,18 @@
{ ... }: {
services = {
guacamole-server = {
enable = true;
host = "127.0.0.1";
port = 4822;
};
guacamole-client = {
enable = true;
enableWebserver = true;
settings = {
guacd-hostname = "127.0.0.1";
guacd-port = 4822;
};
};
tomcat.port = 8085;
};
}

View file

@ -1,21 +0,0 @@
{ ... }: {
services.searx = {
enable = true;
redisCreateLocally = true;
environmentFile = "/mnt/data/apps/searxng/.env";
settings = {
server = {
bind_address = "127.0.0.1";
port = 8091;
secret_key = "$SECRET_KEY";
};
general = {
debug = false;
donation_url = false;
contact_url = false;
privacy_policy_url = false;
enable_metrics = true;
};
};
};
}

View file

@ -0,0 +1,34 @@
{ ... }: {
services = {
httpd = {
enable = true;
virtualHosts."cdn" = {
listen = [{ ip = "127.0.0.1"; port = 3000; }];
documentRoot = "/mnt/share";
};
};
samba = {
enable = true;
settings = {
global = {
workgroup = "WORKGROUP";
"disable netbios" = "yes";
"allow insecure wide links" = "yes";
"server min protocol" = "SMB2_02";
};
"NAS" = {
path = "/mnt/share";
browseable = "yes";
"read only" = "no";
"create mask" = "0664";
"force create mode" = "0664";
"directory mask" = "0775";
"force directory mode" = "0775";
"follow symlinks" = "yes";
"wide links" = "yes";
};
};
};
};
}

View file

@ -0,0 +1,59 @@
{ config, ... }: {
sops = {
defaultSopsFile = ../../../secrets/homelab.yaml;
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
secrets = {
cloudflare_dns_api_token = {
owner = "acme";
group = "acme";
};
cloudflared_tunnel_credentials = {
owner = "cloudflared";
group = "cloudflared";
};
cloudflared_cert = {
owner = "cloudflared";
group = "cloudflared";
};
vaultwarden_env = {
owner = "vaultwarden";
group = "vaultwarden";
restartUnits = [ "vaultwarden.service" ];
};
glance_env = {
owner = "glance";
group = "glance";
restartUnits = [ "glance.service" ];
};
pocketid_encryption_key = {
owner = "root";
group = "root";
restartUnits = [ "pocket-id.service" ];
};
tailscale_authkey = {
owner = "root";
group = "root";
restartUnits = [ "tailscaled.service" ];
};
nginx_htpasswd = {
owner = "nginx";
group = "nginx";
restartUnits = [ "nginx.service" ];
};
};
templates."cloudflare.env" = {
owner = "acme";
group = "acme";
content = "CLOUDFLARE_DNS_API_TOKEN=${config.sops.placeholder.cloudflare_dns_api_token}";
};
};
}

View file

@ -1,11 +1,19 @@
{ pkgs, lib, homelab, ... }: { { config, pkgs, lib, homelab, ... }: let
routes = {
"git.${homelab.domain}" = "http://localhost:5080";
"auth.${homelab.domain}" = "http://localhost:1411";
"dash.${homelab.domain}" = "http://localhost:5070";
"media.${homelab.domain}" = "http://localhost:8096";
"gallery.${homelab.domain}" = "http://localhost:2284";
};
in {
services.cloudflared = { services.cloudflared = {
enable = true; enable = true;
tunnels.homelab = { tunnels.homelab = {
credentialsFile = "/mnt/data/apps/cloudflared/homelab.json"; credentialsFile = config.sops.secrets.cloudflared_tunnel_credentials.path;
certificateFile = "/mnt/data/apps/cloudflared/cert.pem"; certificateFile = config.sops.secrets.cloudflared_cert.path;
default = "http_status:404"; default = "http_status:404";
ingress = homelab.routes; ingress = routes;
}; };
}; };
@ -23,7 +31,7 @@
script = lib.concatMapStringsSep "\n" (domain: '' script = lib.concatMapStringsSep "\n" (domain: ''
echo "Ensuring DNS route for ${domain}..." echo "Ensuring DNS route for ${domain}..."
${pkgs.cloudflared}/bin/cloudflared tunnel --origincert /mnt/data/apps/cloudflared/cert.pem route dns --overwrite-dns $(cat /mnt/data/apps/cloudflared/homelab.json | ${pkgs.jq}/bin/jq -r .TunnelID) ${domain} || true ${pkgs.cloudflared}/bin/cloudflared tunnel --origincert ${config.sops.secrets.cloudflared_cert.path} route dns ${homelab.cf-tunnel-id} ${domain} || true
'') (builtins.attrNames homelab.routes); '') (builtins.attrNames routes);
}; };
} }

View file

@ -1,82 +1,60 @@
{ pkgs, ... }: { { pkgs, ... }: {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
# Disk & Storage
baobab baobab
gnome-disk-utility file-roller
gparted
parted
ntfs3g
exfatprogs
smartmontools
rclone
ncdu
ventoy-full-qt
# System Monitoring & Hardware
htop
sysstat
powertop
lm_sensors
fastfetch
pciutils
usbutils
stress
stress-ng
# Networking
gnome-network-displays gnome-network-displays
gnome-disk-utility
parted
smartmontools
lm_sensors
ntfs3g
virt-viewer
dconf2nix
pciutils
gparted
exfatprogs
pavucontrol
jq
powertop
fastfetch
ethtool ethtool
dig dig
dnslookup dnslookup
nmap lsof
netcat gucharmap
traceroute ncdu
wakeonlan
cloudflared
cloud-utils
# Archives & Compression
file-roller
zip zip
unzip unzip
p7zip
# GUI Utilities
pavucontrol
gucharmap
lxappearance
blueman blueman
shared-mime-info shared-mime-info
usbutils
# Virtualization & Containers
virt-viewer
distrobox
# Android
android-tools
scrcpy
# Remote Access
freerdp
# Media
ffmpeg
# Printing
hplipWithPlugin hplipWithPlugin
# CLI Essentials android-tools
scrcpy
distrobox
ventoy-full-qt
ffmpeg
vim vim
wget wget
curl curl
openssl_3 openssl_3
htop
nmap
sysstat
netcat
p7zip
stress
stress-ng
wakeonlan
coreutils-full coreutils-full
jq traceroute
lsof lxappearance
freerdp
# Nix & Development
rcon-cli
dconf2nix
home-manager home-manager
nix-index nix-index
nixd nixd

View file

@ -1,8 +1,8 @@
{ lib, homelab, ... }: let { config, lib, homelab, ... }: let
ts-flags = [ ts-flags = [
"--advertise-exit-node" "--advertise-exit-node"
"--advertise-routes=10.3.14.0/24,192.168.1.0/24" "--advertise-routes=10.3.14.0/24,192.168.1.0/24"
"--ssh" "--ssh" # "--webclient"
]; ];
in { in {
imports = [ imports = [
@ -11,21 +11,16 @@ in {
./homelab/containers.nix ./homelab/containers.nix
./homelab/gallery.nix ./homelab/gallery.nix
./homelab/tunnels.nix ./homelab/tunnels.nix
./homelab/notify.nix ./homelab/remote.nix
./homelab/search.nix
./homelab/media.nix ./homelab/media.nix
./homelab/proxy.nix ./homelab/proxy.nix
./homelab/auth.nix ./homelab/auth.nix
./homelab/pass.nix ./homelab/pass.nix
./homelab/dash.nix ./homelab/dash.nix
./homelab/code.nix
./homelab/docs.nix
./homelab/dns.nix ./homelab/dns.nix
./homelab/git.nix ./homelab/git.nix
./homelab/cdn.nix
./homelab/ai.nix ./homelab/ai.nix
./homelab/db.nix ./homelab/sops.nix
./homelab/mc.nix
./core/swapfile.nix ./core/swapfile.nix
./core/oom.nix ./core/oom.nix
@ -33,19 +28,14 @@ in {
./base.nix ./base.nix
]; ];
users.users.root.openssh.authorizedKeys.keys = homelab.ssh-keys; services.tailscale = {
enable = true;
services = { authKeyFile = config.sops.secrets.tailscale_authkey.path;
netbird.enable = true; useRoutingFeatures = "server";
tailscale = { extraUpFlags = ts-flags;
enable = true; extraSetFlags = ts-flags;
authKeyFile = "/mnt/data/apps/tailscale/authkey";
useRoutingFeatures = "server";
extraUpFlags = ts-flags;
extraSetFlags = ts-flags;
};
}; };
virtualisation = { virtualisation = {
oci-containers.backend = "docker"; oci-containers.backend = "docker";
docker = { docker = {

View file

@ -7,7 +7,6 @@
shell = pkgs.zsh; shell = pkgs.zsh;
extraGroups = [ extraGroups = [
"networkmanager" "networkmanager"
"minecraft"
"wheel" "wheel"
"dialout" "dialout"
"libvirtd" "libvirtd"

30
scripts/check-sops.sh Executable file
View file

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Pre-commit hook: block commits containing unencrypted sops secret files.
# Install with: ln -sf ../../scripts/check-sops.sh .git/hooks/pre-commit
set -euo pipefail
staged_secrets=$(git diff --cached --name-only --diff-filter=ACM -- 'secrets/*.yaml' 'secrets/*.yml' 'secrets/*.json')
if [ -z "$staged_secrets" ]; then
exit 0
fi
failed=0
for file in $staged_secrets; do
# sops-encrypted YAML/JSON files always contain a top-level "sops" key with metadata
if ! git show ":$file" | grep -q '"sops"\|sops:'; then
echo "ERROR: $file is not encrypted with sops! Encrypt it first:"
echo " sops $file"
echo
echo "hint: bypass with: git commit --no-verify"
failed=1
fi
done
if [ "$failed" -ne 0 ]; then
echo ""
echo "Commit aborted. Encrypt secret files before committing."
exit 1
fi

11
secrets/homelab.yaml Normal file
View file

@ -0,0 +1,11 @@
# This file should be encrypted with sops before committing.
# Run: sops secrets/homelab.yaml
# All values below are placeholders. Replace them with actual values.
cloudflare_dns_api_token: REPLACE_ME
cloudflared_tunnel_credentials: REPLACE_ME
cloudflared_cert: REPLACE_ME
vaultwarden_env: REPLACE_ME
glance_env: REPLACE_ME
pocketid_encryption_key: REPLACE_ME
tailscale_authkey: REPLACE_ME
nginx_htpasswd: REPLACE_ME