Compare commits

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

View file

@ -1,53 +0,0 @@
name: Activate Homelab Configuration
on:
workflow_dispatch:
push:
branches: [ main ]
env:
PATH: /run/current-system/sw/bin:/run/wrappers/bin
SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
jobs:
rebuild:
runs-on: self-hosted
steps:
- name: Setup SSH key
run: |
mkdir -p ./ssh
echo "$SSH_KEY" > ./ssh/deploy_key
chmod 600 ./ssh/deploy_key
- name: Build and set boot configuration
run: |
ssh -i ./ssh/deploy_key \
-o PasswordAuthentication=no \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
root@localhost \
"bash -lc 'nixos-rebuild boot --refresh --flake git+http://localhost:5080/satr14/nix-flake#homelab -L'"
- name: Activate configuration
continue-on-error: true
run: |
ssh -i ./ssh/deploy_key \
-o PasswordAuthentication=no \
-o StrictHostKeyChecking=no \
-o UserKnownHostsFile=/dev/null \
root@localhost \
"bash -lc 'setsid nohup /nix/var/nix/profiles/system/bin/switch-to-configuration switch > /var/log/nixos-switch.log 2>&1 < /dev/null & disown'"
- name: Notify on failure
if: failure()
run: |
curl -s -X POST https://notify.proxy.satr14.my.id/git-flake-updates \
-H "Title: NixOS Homelab Rebuild Failed" \
-H "Priority: high" \
-H "Tags: x" \
-H "Actions: view, Action Runs, https://git.satr14.my.id/${{ github.repository }}/actions?workflow=activate.yml; view, View Commit, https://git.satr14.my.id/${{ github.repository }}/commit/${{ github.sha }}" \
-d "${{ github.event.head_commit.message }}"
- 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)
rewrite of my nixos flake with hopefully better structuring and modularity
> [!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.**
## 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)
> 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.

226
flake.lock generated
View file

@ -5,11 +5,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1784366307,
"narHash": "sha256-VKatYOZwLQ+MuNkWH6/gZYxrNeSK1Mqb7mC0H1WSu+M=",
"lastModified": 1773146250,
"narHash": "sha256-azzOjRqTxAqByzRP87jUUsmfOQ85i7h/YkrgTX0jZgg=",
"owner": "catppuccin",
"repo": "nix",
"rev": "673f730d0fc8db3468c51575f1d3d777cc55e51f",
"rev": "0fa0d06dd3cd09f37f76d19b389d7ff947dfd7e8",
"type": "github"
},
"original": {
@ -18,22 +18,6 @@
"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": {
"inputs": {
"systems": "systems"
@ -78,11 +62,11 @@
]
},
"locked": {
"lastModified": 1784913159,
"narHash": "sha256-JWq0BfjO4ktpH5USfQNQzdvHpIDT8fSKD5K7LvdMRFs=",
"lastModified": 1773179137,
"narHash": "sha256-EdW2bwzlfme0vbMOcStnNmKlOAA05Bp6su2O8VLGT0k=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "079a3b5d1aa6a719920a51316253b7d6dd22738d",
"rev": "3f98e2bbc661ec0aaf558d8a283d6955f05f1d09",
"type": "github"
},
"original": {
@ -92,107 +76,18 @@
"type": "github"
}
},
"mc": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": "nixpkgs_3",
"systems": "systems_2"
},
"locked": {
"lastModified": 1784949919,
"narHash": "sha256-itGqjPYHqEUqabXbQb+eHguk1c6rBTRGZS4KImp45kM=",
"owner": "Infinidoge",
"repo": "nix-minecraft",
"rev": "a58c1fa23ec0273eb085be1e7874e964aa3cd34f",
"type": "github"
},
"original": {
"owner": "Infinidoge",
"repo": "nix-minecraft",
"type": "github"
}
},
"niri": {
"inputs": {
"niri-stable": "niri-stable",
"niri-unstable": "niri-unstable",
"nixpkgs": "nixpkgs_4",
"nixpkgs-stable": "nixpkgs-stable",
"xwayland-satellite-stable": "xwayland-satellite-stable",
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
},
"locked": {
"lastModified": 1784874881,
"narHash": "sha256-u4jhSIf/Un0qZB+Cn3hTTaHSI20XeAxYbA5o4faqdJs=",
"owner": "sodiboo",
"repo": "niri-flake",
"rev": "ef7a2a3d719af46b906c22a3ebfb7d65627b2cd2",
"type": "github"
},
"original": {
"owner": "sodiboo",
"repo": "niri-flake",
"type": "github"
}
},
"niri-stable": {
"flake": false,
"locked": {
"lastModified": 1756556321,
"narHash": "sha256-RLD89dfjN0RVO86C/Mot0T7aduCygPGaYbog566F0Qo=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "01be0e65f4eb91a9cd624ac0b76aaeab765c7294",
"type": "github"
},
"original": {
"owner": "YaLTeR",
"ref": "v25.08",
"repo": "niri",
"type": "github"
}
},
"niri-unstable": {
"flake": false,
"locked": {
"lastModified": 1784570726,
"narHash": "sha256-9EMn69JBcFWFgUM7f0VBAX+jBby5b9H3M59U75+5yI4=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "7f26c3ee804fb6ed458ef7fb0e3c794f14e0b3bc",
"type": "github"
},
"original": {
"owner": "YaLTeR",
"repo": "niri",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1783279667,
"narHash": "sha256-2l8yOB5aYd+05Q9V9Y1YhgbSa1j1o5QX+nvYs5FL80A=",
"rev": "f205b5574fd0cb7da5b702a2da51507b7f4fdd1b",
"type": "tarball",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1028110.f205b5574fd0/nixexprs.tar.xz"
},
"original": {
"type": "tarball",
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1782847189,
"narHash": "sha256-twXPFqFsrrY5r28Zh7Homgcp2gUMBgQ6WDS98Q/3xFI=",
"lastModified": 1772773019,
"narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b6018f87da91d19d0ab4cf979885689b469cdd41",
"rev": "aca4d95fce4914b3892661bcb80b8087293536c6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.11",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
@ -214,11 +109,11 @@
},
"nixpkgs_3": {
"locked": {
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"lastModified": 1772963539,
"narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"rev": "9dcb002ca1690658be4a04645215baea8b95f31d",
"type": "github"
},
"original": {
@ -230,32 +125,16 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1784796856,
"narHash": "sha256-wWFrV5/Qbm+lyt5x20E/bSbfJiGKMo4RCxZV8cl/WZI=",
"lastModified": 1772736753,
"narHash": "sha256-au/m3+EuBLoSzWUCb64a/MZq6QUtOV8oC0D9tY2scPQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "e2587caef70cea85dd97d7daab492899902dbf5d",
"rev": "917fec990948658ef1ccd07cef2a1ef060786846",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_5": {
"locked": {
"lastModified": 1784796856,
"narHash": "sha256-wWFrV5/Qbm+lyt5x20E/bSbfJiGKMo4RCxZV8cl/WZI=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "e2587caef70cea85dd97d7daab492899902dbf5d",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
@ -265,9 +144,26 @@
"ctp": "ctp",
"gl": "gl",
"hm": "hm",
"mc": "mc",
"niri": "niri",
"nixpkgs": "nixpkgs_5"
"nixpkgs": "nixpkgs_3",
"sops": "sops"
}
},
"sops": {
"inputs": {
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1773096132,
"narHash": "sha256-M3zEnq9OElB7zqc+mjgPlByPm1O5t2fbUrH3t/Hm5Ag=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "d1ff3b1034d5bab5d7d8086a7803c5a5968cd784",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
@ -284,54 +180,6 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"xwayland-satellite-stable": {
"flake": false,
"locked": {
"lastModified": 1755491097,
"narHash": "sha256-m+9tUfsmBeF2Gn4HWa6vSITZ4Gz1eA1F5Kh62B0N4oE=",
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"rev": "388d291e82ffbc73be18169d39470f340707edaa",
"type": "github"
},
"original": {
"owner": "Supreeeme",
"ref": "v0.7",
"repo": "xwayland-satellite",
"type": "github"
}
},
"xwayland-satellite-unstable": {
"flake": false,
"locked": {
"lastModified": 1784679892,
"narHash": "sha256-Mb7jpqnrcYCfNSItIkkHpuR3YxWFxPuIBfcwNKlRBkk=",
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"rev": "8d135d3b2854b30fd01ea6cd6c27e523dd50a839",
"type": "github"
},
"original": {
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"type": "github"
}
}
},
"root": "root",

View file

@ -7,11 +7,9 @@
inputs.nixpkgs.follows = "nixpkgs";
};
sops.url = "github:Mic92/sops-nix";
gl.url = "github:nix-community/nixGL";
ctp.url = "github:catppuccin/nix";
niri.url = "github:sodiboo/niri-flake";
mc.url = "github:Infinidoge/nix-minecraft";
};
outputs = inputs: let
@ -20,7 +18,7 @@
overlays = [ inputs.gl.overlay ];
config = {
allowUnfree = true;
permittedInsecurePackages = [ "ventoy-qt5-1.1.12" ];
permittedInsecurePackages = [ "ventoy-qt5-1.1.10" ];
};
};
args = {
@ -33,6 +31,7 @@
modules = [
./hosts/${host}/config.nix
inputs.ctp.nixosModules.catppuccin
inputs.sops.nixosModules.sops
];
};
@ -42,6 +41,7 @@
modules = [
./hosts/${host}/config.nix
inputs.ctp.nixosModules.catppuccin
inputs.sops.nixosModules.sops
inputs.hm.nixosModules.home-manager
{
home-manager = {

View file

@ -21,7 +21,7 @@
tailscale.enable = true;
openssh = {
enable = true;
settings.PermitRootLogin = "prohibit-password";
settings.PermitRootLogin = "yes";
};
};
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
username = "satr14";
@ -23,76 +15,20 @@ in {
homelab = rec {
domain = "satr14.my.id"; # root domain for dns, ssl certs, reverse proxy, etc.
ssh-keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIESvQFXoUBafatqnxTd6qk3WEOcfwb3AIWVTstR3lHzX forgejo"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC7nkis5iB9qJ0OLi8YO4MX1F/ISmBng/xYdNcupGAJC forgejo-actions"
];
cf-tunnel-id = "26318288-cdd7-4e58-904b-c45f10d3e40a";
disks = {
# gallery = ext4 "/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
# host = ext4 "/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/" ]
[ "Cockpit" "cockpit" "https://control.proxy.${domain}" "http://localhost:9090/" ]
[ "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 = {
"mc.${domain}" = "tcp://localhost:25565";
"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";
"control" = d "https://localhost:9090";
"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}";
};
gallery = "/dev/disk/by-uuid/834f51c1-90ee-4601-ba76-ef0419198d67"; # disk for photo gallery
data = "/dev/disk/by-uuid/a5752dd6-092d-484c-969c-2fdc7cb4a5f0"; # disk for app data
host = "/dev/disk/by-uuid/968f14a4-631e-4325-8cd1-f9aec0da9e4d"; # disk for media collection (named host for backwards compatibility)
};
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}" "proxy.${domain}" ]
@ -102,7 +38,7 @@ in {
};
rice = {
font = "DroidSansM Nerd Font"; # global font for rice GUIs, must be a Nerd Font for icon glyphs to render correctly
font = "monospace"; # global font for rice GUIs, leave empty to use monospace
bar = {
top = true; # false will put the bar at the bottom
fragmented = true; # enable fragmented bar, false will make it a single block
@ -126,9 +62,7 @@ in {
};
git = { # setup your git author
username = "satr14"; # forgejo username
server = "https://git.satr14.my.id"; # forgejo server url
user = "satr14";
user = "Satria";
email = "admin@satr14.my.id";
};
}

View file

@ -1,13 +1,14 @@
{ ... }: {
imports = [
# ./misc/cpu-hotplug.nix
# ./misc/serial.nix
# ./misc/qemu-virtio.nix
# ^^ only used if vm
./core/firmware.nix
./core/igpu.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;
services = {
@ -10,21 +10,6 @@
echo 85 > /sys/class/power_supply/BAT*/charge_control_end_threshold || true
''}"
'';
cron = {
enable = true;
systemCronJobs = [
"*/2 * * * * ${username} bash ${pkgs.writeShellScript "low-battery-notifier" ''
ACPI_OUT=$(${pkgs.acpi}/bin/acpi -b)
BAT_PCT=`echo "$ACPI_OUT" | ${pkgs.gnugrep}/bin/grep -P -o '[0-9]+(?=%)'`
BAT_STA=`echo "$ACPI_OUT" | ${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%." && brightnessctl s 30%
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 = {
enable = true;
percentageCritical = 15;

View file

@ -49,8 +49,8 @@
};
auto-cpufreq = {
enable = true; # wait for fix: https://github.com/AdnanHodzic/auto-cpufreq/issues/906
settings = let
performance = {
settings = {
charger = {
governor = "performance";
energy_performance_preference = "performance";
turbo = "always";
@ -58,18 +58,14 @@
scaling_min_freq = 800000;
scaling_max_freq = 3600000;
};
balanced = {
battery = {
governor = "powersave";
energy_performance_preference = "balance-power";
platform_profile = "low-power";
turbo = "never";
platform_profile = "balanced";
scaling_min_freq = 400000;
scaling_max_freq = 1700000;
};
in {
battery = balanced;
charger = balanced; # performance;
# ^^ disable overclocking for purely productivity use so low temps and fan noise
};
};
};

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
globalOpts = {
fsType = "ext4";
autoFormat = true;
autoResize = true;
};
in {
fileSystems = {
"/".autoResize = true;
} // lib.mapAttrs' (name: dev:
lib.nameValuePair "/mnt/${name}" (globalOpts // {
device = dev.path;
fsType = dev.type;
})
} // lib.mapAttrs' (name: device:
lib.nameValuePair "/mnt/${name}" (globalOpts // { inherit device; })
) 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 = {
kernelPackages = pkgs.linuxPackages_zen;
kernelPackages = pkgs.linuxPackages;
kernel.sysctl."vm.laptop_mode" = 5;
initrd.availableKernelModules = [ "thinkpad_acpi" ];
kernelParams = [
@ -28,13 +28,6 @@
"nvme_core.default_ps_max_latency_us=0"
];
};
nixpkgs.overlays = [
(final: prev: {
throttled = prev.throttled.overrideAttrs (old: {
pythonPath = (old.pythonPath or []) ++ [ final.python3Packages.dbus-next ];
});
})
];
hardware.bluetooth = {
enable = true;
powerOnBoot = false;

View file

@ -1,54 +1,44 @@
{ pkgs, ... }: {
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; [
zed-editor
opencode
github-copilot-cli
zed-editor
# kicad-small
# arduino-ide
slack
discord
protonmail-desktop
slack
discord
protonmail-desktop
vlc
brave
flameshot
libreoffice
appimage-run
vlc
brave
libreoffice
appimage-run
# keepassxc
virt-manager
remmina
moonlight-qt
gpu-screen-recorder
gpu-screen-recorder-gtk
virt-manager
# winboat
# LOCK IN
# (prismlauncher.override {
# jdks = with javaPackages.compiler.temurin-bin; [ jre-21 jdk-25 ];
# })
];
remmina
moonlight-qt
# rustdesk
# inkscape
# davinci-resolve
# kdePackages.kdenlive
(wrapOBS {
plugins = with obs-studio-plugins; [
wlrobs
obs-backgroundremoval
obs-pipewire-audio-capture
];
})
ferium
portablemc
prismlauncher
steamguard-cli
# modrinth-app
];
}

View file

@ -1,26 +0,0 @@
{ pkgs, ... }: {
programs.chromium = {
enable = true;
package = pkgs.brave;
extensions = map (id: { inherit id; }) [
"nngceckbapebfimnlniiiahkandclblb" # bitwarden
"kokhpbhfeokchmbimdlaldcmlinjpipm" # 2fauth
"gppongmhjkpfnbhagpmjfkannfbllamg" # wappalyzer
"cejckpjfigehbeecbbfhangbknpidcnh" # timezone changer
"dmghijelimhndkbmpgbldicpogfkceaj" # dark mode
"cebifddlogbjhoibpjobhlamopmlpckl" # disable page visibility
"efknglbfhoddmmfabeihlemgekhhnabb" # json viewer
"bhchdcejhohfmigjafbampogmaanbfkg" # user agent switcher
"bbppejejjfancffmhncgkhjdaikdgagc" # undisposition
"ocabkmapohekeifbkoelpmppmfbcibna" # xoom redirector
"fkagelmloambgokoeokbpihmgpkbgbfm" # indie wiki buddy
"bggfcpfjbdkhfhfmkjpbhnkhnpjjeomc" # github material icons
"hfckonpdalooejghjpbpimhcgighijck" # chess move confirm
"babnnfmbjokkeieobamoifmeapbbfhje" # medium unlock
"mnjggcdmjocbbbhaepdhchncahnbgone" # sponsor block
"ekcgkejcjdcmonfpmnljobemcbpnkamh" # whatsapp web plus
];
};
}

View file

@ -5,17 +5,10 @@
TERMINAL = "kitty";
};
home.packages = with pkgs; [ bun packwiz ];
home.packages = with pkgs; [ bun ];
programs = {
tmux = {
enable = true;
extraConfig = ''
set -g set-clipboard on
set -ag terminal-overrides ",*:Ms=\\E[52;%p1%s;%p2%s\\007"
set -g allow-passthrough on
'';
};
tmux.enable = true;
vim.enable = true;
bat.enable = true;
kitty = {
@ -30,9 +23,6 @@
cursor_trail = 10;
copy_on_select = true;
};
keybindings = {
"ctrl+backspace" = "send_text all \\x17";
};
};
ranger = {
enable = true;
@ -54,21 +44,13 @@
enable = true;
defaultEditor = true;
vimAlias = true;
withRuby = false;
withPython3 = false;
initLua = ''
vim.opt.clipboard = "unnamedplus"
vim.opt.termguicolors = true
local osc52 = require("vim.ui.clipboard.osc52")
vim.g.clipboard = {
name = "OSC 52",
copy = { ["+"] = osc52.copy("+"), ["*"] = osc52.copy("*") },
paste = { ["+"] = osc52.paste("+"), ["*"] = osc52.paste("*") },
}
require("nvim-tree").setup()
vim.api.nvim_create_autocmd("VimEnter", {
callback = function()
vim.cmd("set nu rnu")
-- vim.cmd("NvimTreeOpen")
vim.cmd.wincmd 'p'
end,
})
@ -81,9 +63,9 @@
telescope-file-browser-nvim
nvim-tree-lua
nvim-cmp
barbar-nvim
indent-blankline-nvim
markdown-preview-nvim
vim-suda
];
};
gh = {
@ -98,9 +80,7 @@
};
git = {
enable = true;
signing.format = null;
settings = {
push.autoSetupRemote = true;
pull.rebase = "true";
credential.helper = "cache --timeout=3600";
user = {

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 = {
enable = true;
package = pkgs.zed-editor;
extensions = [
"wakatime" "discord-presence"
"catppuccin" "catppuccin-icons"
"codebook"
"git-firefly" "nix"
"html" "html-snippets"
"svelte" "svelte-snippets"
];
extensions = [ "nix" ];
userSettings = {
diff_view_style = "unified";
cli_default_open_behavior = "existing_window";
format_on_save = "off";
features.edit_prediction_provider = "copilot";
vim_mode = true;
git.inline_blame.enabled = true;
gutter.line_numbers = true;
@ -27,28 +19,6 @@
file_types.tailwindcss = [ "*.css" ];
auto_install_extensions.catppuccin-icons = true;
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 = {
sidebar_side = "right";
tool_permissions.default = "allow";
default_model = {
provider = "copilot_chat";
model = "claude-sonnet-5";
effort = "low";
enable_thinking = true;
};
};
theme = {
mode = "dark";
light = "Catppuccin Mocha (sapphire)";

View file

@ -1,4 +1,4 @@
{ git, hostname, flake-path, zsh-theme, ... }: {
{ hostname, flake-path, zsh-theme, ... }: {
programs = {
pay-respects = {
enable = true;
@ -32,14 +32,14 @@
'';
shellAliases = {
"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";
"cd" = "z";
"sys" = "sudo systemctl --runtime";
"sys-log" = "journalctl -o cat -f -b -u";
"sys-log" = "journalctl -f -b -u";
"user" = "systemctl --user --runtime";
"user-log" = "journalctl -o cat -f -b --user-unit";
"user-log" = "journalctl -f -b --user-unit";
"ts" = "sudo tailscale";
"tsip" = "tailscale ip -4";
@ -49,6 +49,8 @@
"fetch-update" ="rm -f ~/.fetch.sh && wget https://raw.githubusercontent.com/SX-9/fetch.sh/master/fetch.sh -O ~/.fetch.sh && chmod +x ~/.fetch.sh";
"fetch" = "~/.fetch.sh";
"hm-sw" = "home-manager switch -b bak-hm --flake";
"nix-sw" = "sudo nixos-rebuild switch --flake";
"nix-hw-conf" = "nixos-generate-config --show-hardware-config";
"nixos-diff" = "nix build .#nixosConfigurations.$(hostname).config.system.build.toplevel -o /tmp/nix-flake-diff && nvd diff /run/current-system /tmp/nix-flake-diff";
"cd-conf" = "cd ${flake-path}";
@ -61,16 +63,10 @@
"wm-lock" = "wm-ctl dispatch exec loginctl lock-session && notify-send ${hostname} 'Manual lock triggered'";
"wm-disp" = "wm-ctl dispatch dpms";
"gz-compress" = "tar -czhf";
"gz-extract" = "tar -xzf";
"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";
"nix-fetch-hash" = "nix store prefetch-url --json";
"git-fix" = "git rebase --continue";
"mcl" = "portablemc start -l $(cat ~/.minecraft/portablemc-launch-params.json | jq -r .email) $(cat ~/.minecraft/portablemc-launch-params.json | jq -r .version) --jvm-args=-Xmx6G";
"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";
};
initContent = ''

View file

@ -1,20 +1,9 @@
{ username, ctp-opt, ... }: {
{ username, ... }: {
imports = [
./core/shell.nix
./core/cli.nix
./core/zsh.nix
];
catppuccin = {
enable = true;
autoEnable = true;
cache.enable = true;
flavor = ctp-opt.flavor;
accent = ctp-opt.accent;
hyprlock.useDefaultConfig = false;
nvim.settings.transparent_background = true;
};
home = {
stateVersion = "24.11";
username = "${username}";

View file

@ -1,35 +1,30 @@
{ pkgs, ... }: {
imports = [
./rice/compositor.nix
./rice/lockscreen.nix
./rice/keybinds.nix
./rice/logout.nix
./rice/notifs.nix
./rice/hyprland.nix
./rice/hyprlock.nix
./rice/waybar.nix
./rice/rofi.nix
./rice/wlogout.nix
./rice/hypridle.nix
./rice/dunst.nix
./rice/cursor.nix
./rice/theme.nix
./rice/menu.nix
./rice/idle.nix
./rice/bar.nix
./misc/handlers.nix
./misc/phone.nix
./rice/keybinds.nix
./misc/kde-connect.nix
./core/apps.nix
./core/code.nix
./core/browser.nix
./core/zed.nix
./core/xdg.nix
];
home.file.".config/discord/settings.json".text = builtins.toJSON {
SKIP_HOST_UPDATE = true;
};
services = {
awww.enable = true;
swww.enable = true;
hyprpolkitagent.enable = true;
};
home = {
packages = with pkgs; [
playerctl brightnessctl
networkmanagerapplet
networkmanagerapplet tailscale-systray
qt6Packages.qt6ct kdePackages.qtstyleplugin-kvantum
nwg-displays
lxqt.pcmanfm-qt

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

@ -1,11 +1,8 @@
{ lib, pkgs, ctp-opt, ... }: {
catppuccin.cursors.enable = false; # managed manually below to use the "Light" cursor variant
{ pkgs, ctp-opt, ... }: {
home.pointerCursor = {
enable = true;
gtk.enable = true;
package = pkgs.catppuccin-cursors."${ctp-opt.flavor}Light";
name = lib.mkOverride 30 "catppuccin-${ctp-opt.flavor}-light-cursors";
name = "catppuccin-${ctp-opt.flavor}-light-cursors";
size = 24;
};
}

View file

@ -5,8 +5,8 @@
general = {
lock_cmd = "hyprlock";
unlock_cmd = "pkill -USR1 hyprlock";
before_sleep_cmd = "niri msg action power-off-monitors && hyprlock";
after_sleep_cmd = "niri msg action power-on-monitors";
before_sleep_cmd = "hyprctl dispatch dpms off && hyprlock";
after_sleep_cmd = "hyprctl dispatch dpms on && pkill -USR2 hyprlock";
};
listener = [
{
@ -21,8 +21,8 @@
}
{
timeout = 420;
on-timeout = "niri msg action power-off-monitors";
on-resume = "niri msg action power-on-monitors";
on-timeout = "hyprctl dispatch dpms off";
on-resume = "hyprctl dispatch dpms on";
}
{
timeout = 600;

View file

@ -1,83 +1,23 @@
{ lib, pkgs, rice, ctp-opt, ... }: {
{ pkgs, rice, ctp-opt, ... }: {
imports = [
./keybinds.nix
];
# TODO: https://github.com/sodiboo/niri-flake/issues/1393 for nwg-displays monitor dynamic config
programs.niri = {
settings = {
outputs."eDP-1" = {
mode = { width=1920; height=1080; refresh=60.006; };
position = { x=0; y=0; };
scale = 1.0;
};
input = {
warp-mouse-to-focus.enable = true;
focus-follows-mouse = {
max-scroll-amount = "35%";
enable = true;
};
keyboard.xkb.options = "caps:none";
};
environment = {
XCURSOR_SIZE = "24";
XCURSOR_THEME = "catppuccin-${ctp-opt.flavor}-light-cursors";
CLIPHIST_MAX_ITEMS = "90";
GTK_APPLICATION_PREFER_DARK_THEME = "1";
GTK_THEME = "Adwaita:dark";
QT_QPA_PLATFORMTHEME = "kvantum";
QT_STYLE_OVERRIDE = "kvantum";
};
spawn-at-startup = map (sh: { inherit sh; }) [
"wl-paste --type text --watch cliphist store"
"wl-paste --type image --watch cliphist store"
"waybar &"
"sunshine &"
"blueman-applet &"
"nm-applet &"
"tailscale systray &"
];
xwayland-satellite = {
enable = true;
path = lib.getExe pkgs.xwayland-satellite;
};
prefer-no-csd = true;
layout = {
tab-indicator.enable = false;
gaps = rice.gap.outer;
focus-ring = {
enable = true;
width = rice.borders.size;
};
border.enable = false;
};
};
};
catppuccin.hyprland.enable = false; # temp fix until i get things migrated to lua
wayland.windowManager.hyprland = {
enable = true;
package = pkgs.hyprland; # inputs.hl.packages."${pkgs.system}".hyprland;
configType = "hyprlang"; # keep legacy config format (home.stateVersion < 26.05)
systemd.enable = false;
xwayland.enable = true;
settings = {
dwindle.preserve_split = true;
debug = {
error_position = 1;
disable_logs = true;
vfr = true;
};
# monitor = [
# "eDP-1,preferred,auto,1"
# ",preferred,auto,1"
# ];
source = [
"~/.config/hypr/monitors.conf"
"~/.config/hypr/workspaces.conf"
@ -88,10 +28,16 @@
"wl-paste --type text --watch cliphist store"
"wl-paste --type image --watch cliphist store"
#"dunst &"
#"hypridle &"
#"swww-daemon &"
"uwsm app -s s -- waybar &"
"uwsm app -s b -- sunshine &"
"uwsm app -s b -- blueman-applet &"
"uwsm app -s b -- nm-applet &"
"uwsm app -s b -- tailscale systray &"
"uwsm app -s b -- tailscale-systray &"
#"keepassxc &"
];
env = [
@ -105,7 +51,6 @@
"GTK_APPLICATION_PREFER_DARK_THEME,1"
"GTK_THEME,Adwaita:dark"
"QT_QPA_PLATFORMTHEME,kvantum"
"QT_STYLE_OVERRIDE,kvantum"
];
general = {
@ -116,8 +61,13 @@
allow_tearing = false;
layout = "dwindle";
"col.active_border" = if rice.borders.colored then "$accent" else "rgb(108,112,134)"; # accent overlay0
"col.inactive_border" = if rice.borders.colored then "rgb(147,153,178)" else "rgb(17,17,27)"; # overlay2 crust
"col.active_border" = if rice.borders.colored then "$accent" else "$overlay0";
"col.inactive_border" = if rice.borders.colored then "$overlay2" else "$crust";
};
dwindle = {
preserve_split = true;
pseudotile = true;
};
decoration = {
@ -130,21 +80,15 @@
enabled = true;
range = 6;
render_power = 3;
color_inactive = "rgba(17,17,27,99)"; # crust alpha 99
color = "rgba(17,17,27,238)"; # crust alpha ee
color_inactive = "rgba($crustAlpha99)";
color = "rgba($crustAlphaee)";
};
blur = {
enabled = true;
size = 7;
passes = 3;
ignore_opacity = true;
noise = 0.05;
contrast = 1.5;
xray = false;
new_optimizations = true;
size = 3;
passes = 1;
vibrancy = 0.1696;
};
};
@ -178,7 +122,8 @@
middle_click_paste = false;
exit_window_retains_fullscreen = true;
on_focus_under_fullscreen = 1;
background_color = "rgb(17, 17, 27)"; # crust
background_color = "$base";
vfr = true;
};
input = {
@ -195,7 +140,7 @@
layerrule = [
"no_anim on, match:namespace selection" # hyprshot overlay
"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 hyprshutdown"
"above_lock 2, match:namespace notifications"
@ -210,8 +155,7 @@
"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 ^(Preferences|Settings|Options|About|Passbolt).*"
"float on, match:title ^(MainPicker|Volume Control|File Operation Progress|Network Connections|Choose an Application)$"
"float on, match:title ^(Please wait)$"
"float on, match:title ^(MainPicker|Volume Control|File Operation Progress|Network Connections|Choose an Application| )$"
];
};
};

View file

@ -1,74 +1,23 @@
{ pkgs, lib, hostname, ... }: {
programs.niri.settings.binds = {
"XF86AudioRaiseVolume" = { action.spawn = [ "wpctl" "set-volume" "-l" "1" "@DEFAULT_AUDIO_SINK@" "2%+" ]; allow-when-locked = true; };
"XF86AudioLowerVolume" = { action.spawn = [ "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "2%-" ]; allow-when-locked = true; };
"XF86AudioMute" = { action.spawn = [ "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle" ]; allow-when-locked = true; };
"XF86AudioMicMute" = { action.spawn = [ "wpctl" "set-mute" "@DEFAULT_AUDIO_SOURCE@" "toggle" ]; allow-when-locked = true; };
"XF86MonBrightnessUp" = { action.spawn = [ "brightnessctl" "s" "10%+" ]; allow-when-locked = true; };
"XF86MonBrightnessDown" = { action.spawn = [ "brightnessctl" "s" "10%-" ]; allow-when-locked = true; };
{ pkgs, hostname, ... }: {
services.fusuma = {
extraPackages = with pkgs; [ systemd coreutils-full xprop ];
enable = true;
settings = {
swipe = {
"4".down.sendkey = "LEFTMETA+L";
"4".up.sendkey = "LEFTMETA+M";
"3".up.sendkey = "LEFTMETA+W";
"Mod+Q".action.close-window = {};
"Mod+W".action.maximize-column = {};
"Mod+S".action.fullscreen-window = {};
"Ctrl+Print".action.screenshot-window = {};
"Alt+Print".action.screenshot-screen = {};
"Print".action.screenshot = {};
"Mod+Up".action.focus-workspace-up = {};
"Mod+Down".action.focus-workspace-down = {};
"Mod+Left".action.focus-column-left = {};
"Mod+Right".action.focus-column-right = {};
"Mod+Shift+Up".action.move-window-up-or-to-workspace-up = {};
"Mod+Shift+Down".action.move-window-down-or-to-workspace-down = {};
"Mod+Shift+Left".action.move-column-left = {};
"Mod+Shift+Right".action.move-column-right = {};
"Mod+Ctrl+Left".action.set-window-width = [ "-2%" ];
"Mod+Ctrl+Right".action.set-window-width = [ "+2%" ];
"Mod+Ctrl+Down".action.set-window-height = [ "+2%" ];
"Mod+Ctrl+Up".action.set-window-height = [ "-2%" ];
"Mod+G".action.center-column = {};
"Mod+F".action.toggle-window-floating = {};
"Alt+Space".action.toggle-overview = {};
"Mod+Space" = { action.spawn = [ "playerctl" "play-pause" ]; allow-when-locked = true; };
"Mod+R".action.spawn = [ "rofi" "-show" "drun" "-show-icons" "-display-drun" "" "-run-command" "{cmd}" ];
"Mod+Shift+R".action.spawn = [ "rofi" "-show" "drun" "-show-icons" "-display-drun" "wayland-0" "-run-command" "sh -c 'WAYLAND_DISPLAY=wayland-0 DISPLAY=:1 exec {cmd}'" ];
"Mod+E".action.spawn = [ "pcmanfm-qt" ];
"Mod+T".action.spawn = [ "kitty" ];
"Mod+Y".action.spawn = [ "brave" "--restore-last-session" ];
"Mod+Return".action.spawn-sh = "ls ~/Projects | rofi -dmenu -p \"Open Project\" | xargs -I {} sh -c 'mkdir -p ~/Projects/\"{}\" && zeditor ~/Projects/\"{}\"'";
"Mod+M".action.spawn = [ "wlogout" ];
"Mod+Tab".action.spawn = [ "pkill" "-SIGUSR1" "waybar" ];
"Mod+H".action.show-hotkey-overlay = {};
"XF86Bluetooth".action.spawn = [ "blueman-manager" ];
"XF86Display".action.spawn = [ "nwg-displays" ];
"Ctrl+Alt+Delete".action.spawn = [ "wlogout" ];
"Ctrl+Shift+Escape".action.spawn = [ "kitty" "btop" ];
"Mod+Grave".action.spawn = [ "dunstctl" "set-paused" "toggle" ];
"Mod+N".action.spawn = [ "rofi-network-manager" ];
"Mod+J".action.spawn-sh = "notify-send -u critical ${hostname} 'Caffein Mode' && notify-send '(SUPER+X to reset)' && systemctl --user stop hypridle";
"Mod+Z".action.spawn = [ "dunstctl" "close-all" ];
"Mod+V".action.spawn = [ "rofi" "-modi" "clipboard:cliphist-rofi-img" "-show" "clipboard" "-show-icons" ];
"Mod+A".action.spawn = [ "zeditor" ];
"Mod+C".action.spawn = [ "kitty" "btop" ];
"Mod+Shift+T".action.spawn-sh = "WAYLAND_DISPLAY=wayland-0 ${lib.getExe pkgs.kitty}";
"Mod+Shift+F".action.spawn = [ (lib.getExe pkgs.labwc) ];
"Mod+Shift+C".action.spawn = [ "kitty" "zsh" "-c" "fastfetch; exec zsh -i" ];
"Mod+Shift+D".action.spawn = [ "steam" "-system-composer" "steam://open/bigpicture" ];
"Mod+D".action.spawn = [ "prismlauncher" ];
"Mod+X".action.spawn-sh = "dunstctl close-all && pkill -SIGUSR2 waybar && systemctl --user restart awww hypridle";
"Mod+K".action.spawn-sh = "notify-send -u critical ${hostname} 'Focus Mode' && notify-send '(SUPER+X to reset)' && systemctl --user stop awww && pkill -SIGUSR1 waybar";
"Mod+L".action.spawn = [ "loginctl" "lock-session" ];
"3".down.sendkey = "LEFTMETA+DOWN";
"3".right.sendkey = "LEFTMETA+LEFT";
"3".left.sendkey = "LEFTMETA+RIGHT";
};
hold = {
"3".sendkey = "LEFTMETA+TAB";
"4".sendkey = "LEFTMETA+SPACE";
};
};
};
wayland.windowManager.hyprland = {
settings = {
gestures = {
@ -146,10 +95,10 @@
"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, 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, 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 SHIFT, S, exec, hyprshot -zm region -o ~/Pictures/Screenshots; killall -9 hyprpicker hyprshot"
@ -157,7 +106,9 @@
", 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, 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, B, exec, rofi -show calc -modi calc -no-show-match -no-sort"
@ -175,9 +126,8 @@
"SUPER, W, fullscreen, 1"
"SUPER, S, fullscreen, 0"
"SUPER, F, togglefloating,"
"SUPER, G, layoutmsg, togglesplit"
"SUPER, G, togglesplit,"
"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 SHIFT, down, movetoworkspace, special:hidden"

View file

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

View file

@ -12,14 +12,15 @@
modules-left = [
"custom/start"
"niri/workspaces"
"niri/window"
"hyprland/workspaces"
"hyprland/window"
"mpris"
];
modules-center = if rice.bar.minimal then [] else [
"custom/dunst"
"clock"
"tray"
"hyprland/submap"
];
modules-right = if rice.bar.minimal then [
"tray"
@ -44,8 +45,8 @@
interval = 1;
format = " {usage:2}% {avg_frequency}GHz";
on-click = "auto-cpufreq-gtk";
on-click-right = "pkexec auto-cpufreq --force powersave && notify-send ${hostname} \"CPU Governor Powersave Overide\"";
on-click-middle = "pkexec auto-cpufreq --force reset && notify-send ${hostname} \"CPU Governor Overide Reset\"";
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 tlp start && notify-send ${hostname} \"TLP set to: $(tlp-stat -s | grep 'Power profile' | awk -F '=' '{print $2}' | xargs)\"";
};
"memory" = {
states = {
@ -53,7 +54,7 @@
};
interval = 1;
format = " {used:0.1f}GiB";
on-click = "kitty btop";
on-click = "hyprctl dispatch exec '[float; size 75%]' kitty btop";
};
"disk" = {
states = {
@ -61,7 +62,7 @@
};
interval = 5;
format = " {used}";
on-click = "kitty btop";
on-click = "hyprctl dispatch exec '[float; size 75%]' kitty btop";
on-click-right = "kitty sh -c 'sudo nix-collect-garbage -d; nix-collect-garbage -d; nix store optimise; sudo journalctl --rotate --vacuum-time=1s --vacuum-files=1; read'";
};
"network" = {
@ -80,7 +81,7 @@
critical-threshold = 80;
format = " {temperatureC}°C";
interval = 1;
on-click = "kitty btop";
on-click = "hyprctl dispatch exec '[float; size 75%]' kitty btop";
};
"power-profiles-daemon" = {
format = "{icon} {profile}";
@ -90,10 +91,15 @@
balanced = "";
};
};
"niri/workspaces" = {
format = "{value}";
on-scroll-down = "niri msg action focus-workspace-down";
on-scroll-up = "niri msg action focus-workspace-up";
"hyprland/workspaces" = {
format = "{name}";
format-icons = {
default = " ";
active = " ";
urgent = " ";
};
on-scroll-down = "hyprctl dispatch workspace e+1";
on-scroll-up = "hyprctl dispatch workspace e-1";
};
"custom/dunst" = {
format = "{}";
@ -113,7 +119,7 @@
on-click-right = "playerctl next";
on-click = "playerctl previous";
};
"niri/window" = {
"hyprland/window" = {
icon = true;
max-length = 35;
separate-outputs = false;
@ -122,9 +128,15 @@
"~" = "${username}@${hostname}";
"btop" = "${username}@${hostname}";
};
on-click-right = "niri msg action fullscreen-window";
on-click-middle = "niri msg action close-window";
on-click = "niri msg action maximize-column";
on-click-right = "hyprctl dispatch fullscreen 0";
on-click-middle = "hyprctl dispatch killactive";
on-click = "hyprctl dispatch fullscreen 1";
on-scroll-up = "hyprctl dispatch cyclenext";
on-scroll-down = "hyprctl dispatch cyclenext prev";
};
"hyprland/submap" = {
format = " {}";
on-click = "hyprctl dispatch submap reset";
};
"clock" = {
format = "{:%b %d, %I:%M:%S %p}";
@ -172,7 +184,8 @@
};
"custom/start" = {
format = "";
on-click-right = "wlogout";
on-click-middle = "wlogout";
on-click-right = "hyprctl dispatch togglespecialworkspace hidden";
on-click = "rofi -show drun -show-icons -display-drun '' -run-command \"uwsm app -- {cmd}\"";
};
}
@ -180,7 +193,7 @@
style = ''
* {
font-size: 12px;
font-family: ${rice.font};
font-family: Font Awesome, ${rice.font};
font-weight: bold;
color: @text;
transition: none;
@ -215,13 +228,12 @@
border: ${toString rice.borders.size}px solid transparent;
}
#window { padding: 0px 5px; }
#workspaces, #cpu, #memory, #disk, #clock, #window, #tray, #pulseaudio, #battery, #network, #temperature, #power-profiles-daemon, #custom-exit, #custom-start, #custom-dunst, #mpris { padding: 0px 5px; margin: 0px 5px; }
#window, #submap { padding: 0px 5px; }
#submap, #workspaces, #cpu, #memory, #disk, #clock, #window, #tray, #pulseaudio, #battery, #network, #temperature, #power-profiles-daemon, #custom-exit, #custom-start, #custom-dunst, #mpris { padding: 0px 5px; margin: 0px 5px; }
#workspaces button {
border-radius: 0px;
margin: 0px;
padding: 4px;
background: none;
border: none;
}
@ -235,7 +247,7 @@
background: @base;
}
#workspaces button.active {
#workspaces button.active, #submap {
background: @surface0;
}

View file

@ -4,13 +4,13 @@
layout = [
{
label = "shutdown";
action = "systemctl poweroff";
action = "hyprshutdown -t 'Shutting down...' --post-cmd 'systemctl poweroff'";
text = "(S)hutdown";
keybind = "s";
}
{
label = "reboot";
action = "systemctl reboot";
action = "hyprshutdown -t 'Rebooting...' --post-cmd 'systemctl reboot'";
text = "(R)eboot";
keybind = "r";
}
@ -28,7 +28,7 @@
}
{
label = "logout";
action = "niri msg action quit";
action = "hyprshutdown -t 'Logging Out...' --post-cmd 'uwsm stop'";
text = "L(o)gout";
keybind = "o";
}

View file

@ -5,35 +5,26 @@
{
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.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/e5a7d45d-b9e9-43e7-ba5f-f4e67821bd0b";
{ device = "/dev/disk/by-uuid/e33ab472-e518-4b4d-89d1-d75cfecb9f06";
fsType = "ext4";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/EC01-36B5";
{ device = "/dev/disk/by-uuid/880C-9F0A";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
options = [ "fmask=0077" "dmask=0077" ];
};
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";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -16,14 +16,7 @@
i18n.defaultLocale = locale;
environment.localBinInPath = true;
powerManagement.cpuFreqGovernor = "powersave";
boot.kernel.sysctl."vm.swappiness" = 10; # only swap when necessary
security = {
polkit = {
enable = true;
enablePkexecWrapper = true;
};
sudo.configFile = ''
Defaults insults
Defaults passwd_tries = 5

View file

@ -1,11 +1,12 @@
{ pkgs, legacy-boot, ... }: {
boot = {
plymouth.enable = true;
loader = {
efi.canTouchEfiVariables = true;
systemd-boot = {
enable = !legacy-boot;
configurationLimit = 3;
sortKey = "nixos";
sortKey = "z-nixos";
editor = false;
};
grub = {

View file

@ -1,8 +1,5 @@
{ inputs, pkgs, enable-dm, ... }: {
nixpkgs.overlays = [ inputs.niri.overlays.niri ];
{ pkgs, enable-dm, ... }: {
imports = [
inputs.niri.nixosModules.niri
./misc/programs.nix
./misc/graphics.nix
./misc/theme.nix
@ -10,30 +7,18 @@
./base.nix
];
programs = {
nix-ld = {
enable = true;
libraries = with pkgs; [
libxcursor libx11 libxi libxkbcommon
];
};
niri = {
enable = true;
package = pkgs.niri-unstable;
};
hyprland = {
enable = false;
withUWSM = true;
xwayland.enable = true;
package = pkgs.hyprland; # if rice.enable then inputs.hl.packages."${pkgs.system}".hyprland else pkgs.hyprland;
portalPackage = pkgs.xdg-desktop-portal-hyprland; # inputs.hl.packages.${pkgs.system}.xdg-desktop-portal-hyprland;
};
programs.hyprland = {
enable = true;
withUWSM = true;
xwayland.enable = true;
package = pkgs.hyprland; # if rice.enable then inputs.hl.packages."${pkgs.system}".hyprland else pkgs.hyprland;
portalPackage = pkgs.xdg-desktop-portal-hyprland; # inputs.hl.packages.${pkgs.system}.xdg-desktop-portal-hyprland;
};
xdg.portal = {
enable = true;
extraPortals = [
pkgs.xdg-desktop-portal-luminous
pkgs.xdg-desktop-portal-hyprland #inputs.hl.packages.${pkgs.system}.xdg-desktop-portal-hyprland
pkgs.xdg-desktop-portal-gtk
];
};

View file

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

View file

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

View file

@ -1,26 +0,0 @@
{ pkgs, ... }: let
python = pkgs.python3.withPackages (ps: with ps; [ pillow argon2-cffi ]);
script = let
version = "v1.20.18";
in pkgs.fetchurl {
url = "https://github.com/9001/copyparty/releases/download/${version}/copyparty-en.py";
hash = "sha256-8SBrKaLPat80n8sONKQYFeFSQXUnCYtwcOU7SR52h7E=";
};
executable = pkgs.writeShellScriptBin "copyparty" ''
exec ${python}/bin/python3 ${script} "$@"
'';
in {
environment.systemPackages = [ executable ];
systemd.services.copyparty = {
description = "File Sharing Service";
enable = true;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.ffmpeg ];
serviceConfig = {
# ExecStart = "${pkgs.copyparty-most}/bin/copyparty -c /mnt/share/cfg/files.conf";
ExecStart = "${python}/bin/python3 ${script} --ah-alg argon2 -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
dockge-dir = "/mnt/data/apps/dockge";
stacks-dir = "${dockge-dir}/stacks";
stacks-dir = "/mnt/data/dockge/stacks";
in {
virtualisation.oci-containers.containers."dockge" = {
image = "louislam/dockge:nightly";
@ -9,7 +8,7 @@ in {
};
volumes = [
"${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"
];
ports = [
@ -32,8 +31,10 @@ in {
RestartSec = lib.mkOverride 500 "100ms";
RestartSteps = lib.mkOverride 500 9;
};
after = [ "docker.service" "docker.socket" ];
requires = [ "docker.service" "docker.socket" ];
wantedBy = [ "multi-user.target" ];
wantedBy = [
"multi-user.target"
"network.target"
"docker.service"
];
};
}

View file

@ -1,9 +0,0 @@
{ homelab, pkgs, ... }: {
services.cockpit = {
enable = true;
allowed-origins = [ "https://control.proxy.${homelab.domain}" ];
plugins = with pkgs; [
cockpit-files cockpit-machines
];
};
}

View file

@ -1,4 +1,18 @@
{ timezone, homelab, ... }: let
{ config, timezone, homelab, ... }: let
rss = [
"https://www.raspberrypi.com/news/feed/"
"https://www.jeffgeerling.com/blog.xml"
"https://www.howtogeek.com/feed/"
"https://hackaday.com/feed/rss"
"https://www.xda-developers.com/feed/"
"https://9to5mac.com/feed/"
"https://9to5google.com/feed/"
"https://www.cnx-software.com/feed/"
"https://selfh.st/rss/"
"https://www.joshwcomeau.com/rss.xml"
"https://samwho.dev/rss.xml"
"https://ishadeed.com/feed.xml"
];
yt = [
"UCXuqSBlHAE6Xw-yeJA0Tunw" # LinusTechTips
"UCsBjURrPoezykLs9EqgamOA" # Fireship
@ -20,10 +34,50 @@
"UCGKEMK3s-ZPbjVOIuAV8clQ" # CoreDumped
"UCWQaM7SpSECp9FELz-cHzuQ" # DreamsOfCode
];
gh = [
"tailscale/tailscale"
"glanceapp/glance"
"nixos/nixpkgs"
"ollama/ollama"
"nginx/nginx"
"oven-sh/bun"
];
search = [
[ "Website" "!!" "https://{QUERY}" ]
[ "CVE" "!cve" "https://securityvulnerability.io/vulnerability/CVE-{QUERY}" ]
[ "YouTube" "!yt" "https://www.youtube.com/results?search_query={QUERY}" ]
[ "GitHub" "!gh" "https://github.com/search?q={QUERY}" ]
[ "Nix Packages" "!nix" "https://search.nixos.org/packages?channel=unstable&type=packages&query={QUERY}" ]
[ "Nix Options" "!opt" "https://mynixos.com/search?q={QUERY}" ]
[ "Flight Radar 24" "!f" "https://www.flightradar24.com/data/flights/{QUERY}" ]
[ "Google Web Results Only" "!s" "https://google.com/search?udm=14&q={QUERY}" ]
];
monitor = [
[ "Hypervisor" "https://10.3.14.69:8006/" ]
[ "Router" "http://10.3.14.1:80/" ]
[ "DNS" "http://localhost:8088/" ]
[ "CDN" "http://nas.local:3000/" ]
[ "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 = [
[ "Tailscale" "tailscale" "https://login.tailscale.com/" ]
[ "Cloudflare" "cloudflare" "https://dash.cloudflare.com/" ]
@ -42,6 +96,7 @@ in {
};
services.glance = {
enable = true;
environmentFile = config.sops.secrets.glance_env.path;
settings = {
server = {
host = "127.0.0.1";
@ -57,6 +112,104 @@ in {
};
pages = [
{
name = "Home";
show-mobile-header = true;
columns = [
{
size = "small";
widgets = [
{
type = "clock";
hide-header = true;
hour-format = "12h";
timezone = timezone;
}
{
type = "calendar";
hide-header = true;
first-day-of-week = "monday";
}
{
type = "rss";
hide-header = true;
title = "rss";
limit = 12;
cache = "12h";
feeds = map (e: { url = e; }) rss;
}
];
}
{
size = "full";
widgets = [
{
type = "search";
hide-header = true;
autofocus = true;
search-engine = "google";
bangs = map (e: {
title = builtins.elemAt e 0;
shortcut = builtins.elemAt e 1;
url = builtins.elemAt e 2;
}) search;
}
{
type = "hacker-news";
hide-header = true;
limit = 5;
cache = "1h";
}
{
type = "videos";
hide-header = true;
style = "grid-cards";
limit = 18;
channels = yt;
}
];
}
{
size = "small";
widgets = [
{
type = "weather";
hide-header = true;
location = "Jakarta, Indonesia";
units = "metric";
hour-format = "12h";
}
{
type = "to-do";
id = "tasks";
hide-header = true;
}
{
type = "repository";
repository = "is-a-dev/register";
pull-requests-limit = 5;
issues-limit = 3;
commits-limit = 0;
hide-header = true;
}
{
type = "repository";
repository = "partofmyid/register";
pull-requests-limit = 5;
issues-limit = 3;
commits-limit = 0;
hide-header = true;
}
{
type = "releases";
cache = "1d";
hide-header = true;
repositories = gh;
}
];
}
];
}
{
name = "Dashboard";
show-mobile-header = true;
@ -102,7 +255,6 @@ in {
title = builtins.elemAt e 0;
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
alt-status-codes = [ 401 ];
}) bookmarks;
}
];
@ -120,15 +272,22 @@ in {
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;
};
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";
@ -140,7 +299,7 @@ in {
icon = "si:${builtins.elemAt e 1}";
url = builtins.elemAt e 2;
check-url = builtins.elemAt e 3;
}) homelab.dash;
}) services;
}
{
type = "docker-containers";
@ -152,74 +311,6 @@ in {
}
];
}
{
name = "Home";
show-mobile-header = true;
columns = [
{
size = "small";
widgets = [
{
type = "clock";
hide-header = true;
hour-format = "12h";
timezone = timezone;
}
{
type = "calendar";
hide-header = true;
first-day-of-week = "monday";
}
];
}
{
size = "full";
widgets = [
{
type = "hacker-news";
hide-header = true;
limit = 5;
cache = "1h";
}
{
type = "videos";
hide-header = true;
style = "grid-cards";
limit = 18;
channels = yt;
}
];
}
{
size = "small";
widgets = [
{
type = "weather";
hide-header = true;
location = "Jakarta, Indonesia";
units = "metric";
hour-format = "12h";
}
{
type = "repository";
repository = "is-a-dev/register";
pull-requests-limit = 5;
issues-limit = 3;
commits-limit = 0;
hide-header = true;
}
{
type = "repository";
repository = "partofmyid/register";
pull-requests-limit = 5;
issues-limit = 3;
commits-limit = 0;
hide-header = true;
}
];
}
];
}
];
};
};

View file

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

View file

@ -21,13 +21,6 @@
whitelist = [
"https://gist.githubusercontent.com/mul14/eb05e88fcec5bb195cbb/raw/75a1fe122a4502e8d5a5268c9d0ec28332b19d5d/hosts"
];
blocked = [
# LOCK IN
"instagram"
"youtube"
"minecraft"
"steam"
];
in {
services.adguardhome = {
enable = true;
@ -44,7 +37,6 @@ in {
enabled = true;
};
filtering = {
blocked_services.ids = blocked;
blocking_mode = "null_ip";
protection_enabled = true;
safebrowsing_enabled = true;

View file

@ -1,10 +1,4 @@
{ pkgs, lib, ... }: {
# fix every update causing error:
# > microservices worker error: PostgresError: must be owner of function album_user_after_insert, stack: PostgresError: must be owner of function album_user_after_insert
systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
$PSQL -d immich -c "ALTER FUNCTION album_user_after_insert() OWNER TO immich;" || true
'';
{ lib, homelab, ... }: {
users.users.immich.extraGroups = [ "video" "render" ];
services = {
@ -12,7 +6,7 @@
enable = true;
port = 2283;
host = "127.0.0.1";
mediaLocation = "/mnt/data/gallery";
mediaLocation = "/mnt/gallery";
accelerationDevices = null;
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;

View file

@ -1,83 +1,48 @@
{ pkgs, homelab, ... }: {
services = {
forgejo = {
enable = true;
lfs.enable = true;
stateDir = "/mnt/data/apps/forgejo";
package = pkgs.forgejo;
settings = {
server = {
DISABLE_SSH = false;
START_SSH_SERVER = true;
SSH_DOMAIN = "main.dns.${homelab.domain}";
SSH_LISTEN_HOST = "0.0.0.0";
SSH_LISTEN_PORT = 5822;
SSH_PORT = 5822;
DOMAIN = "git.${homelab.domain}";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 5080;
PROTOCOL = "http";
ROOT_URL = "https://git.${homelab.domain}";
LANDING_PAGE = "explore";
};
actions.DEFAULT_ACTIONS_URL = "https://git.satr14.my.id";
oauth2_client.ENABLE_AUTO_REGISTRATION = true;
service = {
DISABLE_REGISTRATION = true;
ENABLE_OPENID_SIGNIN = false;
ENABLE_OPENID_SIGNUP = false;
ENABLE_INTERNAL_SIGNIN = false;
SHOW_REGISTRATION_BUTTON = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
ALLOW_ONLY_INTERNAL_REGISTRATION = false;
REQUIRE_EXTERNAL_REGISTRATION_PASSWORD = true;
};
"service.explore" = {
DISABLE_USERS_PAGE = true;
DISABLE_ORGANIZATIONS_PAGE = true;
};
user.ENABLE_FOLLOWING = false;
repository = {
DISABLE_STARS = true;
DISABLE_FORKS = true;
ENABLE_PUSH_CREATE_USER = true;
};
services.forgejo = {
enable = true;
lfs.enable = true;
stateDir = "/mnt/data/forgejo";
package = pkgs.forgejo;
#secrets = {
# oauth2.JWT_SECRET = "/mnt/data/forgejo/custom/conf/oauth2_jwt_secret";
# server.LFS_JWT_SECRET = "/mnt/data/forgejo/custom/conf/lfs_jwt_secret";
# security = {
# INTERNAL_TOKEN = "/mnt/data/forgejo/custom/conf/internal_token";
# SECRET_KEY = "/mnt/data/forgejo/custom/conf/secret_key";
# };
#};
settings = {
server = {
DISABLE_SSH = false;
START_SSH_SERVER = true;
SSH_DOMAIN = "main.dns.${homelab.domain}";
SSH_LISTEN_HOST = "0.0.0.0";
SSH_LISTEN_PORT = 5822;
SSH_PORT = 5822;
DOMAIN = "git.${homelab.domain}";
HTTP_ADDR = "127.0.0.1";
HTTP_PORT = 5080;
PROTOCOL = "http";
ROOT_URL = "https://git.${homelab.domain}";
LANDING_PAGE = "explore";
};
oauth2_client.ENABLE_AUTO_REGISTRATION=true;
service = {
DISABLE_REGISTRATION = true;
ENABLE_OPENID_SIGNIN = false;
ENABLE_OPENID_SIGNUP = false;
ENABLE_INTERNAL_SIGNIN = true; # TODO: set false after migration complete
SHOW_REGISTRATION_BUTTON = false;
ALLOW_ONLY_EXTERNAL_REGISTRATION = 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"
"bun:docker://docker.io/oven/bun"
"debian:docker://docker.io/library/node:26-trixie-slim"
"aio:docker://git.satr14.my.id/satr14/aio-container:latest"
];
hostPackages = with pkgs; [ bash coreutils git nix openssh bun ];
};
renovate = {
enable = true;
schedule = "*:0"; # every hour
credentials.RENOVATE_TOKEN = "/mnt/data/apps/renovate/token.env";
settings = {
platform = "forgejo";
endpoint = "https://git.${homelab.domain}";
gitAuthor = "renovate <system@${homelab.domain}>";
autodiscover = true;
nix.enabled = true;
lockFileMaintenance = {
enabled = true;
commitMessageAction = "update lock file(s)";
schedule = [ "* 0 * * 6" ]; # weekly, midnight Saturday
};
};
runtimePackages = with pkgs; [ bun nix ];
};
};
systemd.services = {
"gitea-runner-nixos-deploy".restartIfChanged = false;
"forgejo".restartIfChanged = false;
};
}

View file

@ -1,16 +0,0 @@
{ inputs, ... }: {
imports = [
./mc0-vanilla-plus.nix
./mc1-pure-vanilla.nix
inputs.mc.nixosModules.minecraft-servers
];
nixpkgs.overlays = [ inputs.mc.overlay ];
services.minecraft-servers = {
# LOCK IN
enable = false;
eula = true;
managementSystem.systemd-socket.enable = true;
# ^^^ https://github.com/Infinidoge/nix-minecraft/issues/119
};
}

View file

@ -1,120 +0,0 @@
{ inputs, lib, pkgs, ... }: let
name = "mc0-vanilla-plus";
ram-allocation-mb = 8192;
headroom-allocation-mb = 1024;
rcon-pass = "howdy";
ports = {
minecraft = 25565;
rcon = 25575;
};
modpack = let
useLatest = false;
commit = "86bf13316ed1352a676d9056d284448ea5e5a079";
path = if !useLatest then "commit/${commit}" else "branch/main";
in pkgs.fetchPackwizModpack {
packHash = "sha256-sc6vekjddYpwY2Hp3uZ/xFiXyPd4kfwcZVO/pKRRBwQ=";
url = "https://git.satr14.my.id/satr14/server-modpack/raw/${path}/pack.toml";
};
in {
systemd.services."minecraft-server-${name}" = {
environment.LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; # physics toys mod fix
# serviceConfig.Nice = -5; # higher scheduling priority (causes fan noise even when idle)
};
services.minecraft-servers.servers.${name} = {
enable = false;
autoStart = true;
restart = "always";
serverProperties = {
server-ip = "0.0.0.0";
server-port = ports.minecraft;
server-name = name;
motd = "§cCan't connect to server";
log-ips = false;
hide-online-players = true;
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 = 6;
enable-rcon = true;
sync-chunk-writes = false;
"rcon.password" = rcon-pass;
"rcon.port" = ports.rcon;
};
symlinks = inputs.mc.lib.collectFilesAt modpack "mods" // {
"polymer/packsquash" = let packsquash-binary = pkgs.runCommand "packsquash" {
src = pkgs.fetchurl {
url = "https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.1/packsquash-x86_64-unknown-linux-gnu.zip";
sha256 = "sha256-VsGZewoiO5MjhIhwjlLO5d5uHynlAK5Jh16jH2k2rPs=";
};
nativeBuildInputs = [ pkgs.unzip ];
} ''
mkdir -p $out/bin
unzip $src -d $out/bin
chmod +x $out/bin/packsquash
''; in "${packsquash-binary}/bin/packsquash";
};
files = inputs.mc.lib.collectFilesAt modpack "config" // {
"config/proxy_protocol_support.json".value = {
enableProxyProtocol = false; # polymer auto host has issues with proxy protocol
whitelistTCPShieldServers = false;
proxyServerIPs = [ "127.0.0.1" "::1" ];
directAccessIPs = [ "127.0.0.0/8" "::1/128" ];
};
};
extraStartPre = let sed-commands = lib.concatStringsSep "\n" (
lib.mapAttrsToList (substitution: file:
''sed -i "s|${substitution}|''${${substitution}}|g" ${file}''
) {
"REPLACE_SVC_HOST" = "config/voicechat/voicechat-server.properties";
"REPLACE_RP_LINK" = "config/welcomemessage.json5";
"REPLACE_DC_BOT_TOKEN" = "config/simple-discord-link/simple-discord-link.toml";
"REPLACE_DC_OWNER_ROLE" = "config/simple-discord-link/simple-discord-link.toml";
}
); in ''
# shellcheck disable=SC1091
if [ -f modpack-config.env ]; then
source modpack-config.env
${sed-commands}
fi
'';
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:+ZGenerational" # Use generational ZGC (newer and better ZGC, requires Java v21+)
"-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 like C2ME)
"-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:SoftMaxHeapSize=${toString (ram-allocation-mb - headroom-allocation-mb)}M" # Leave 2GB headroom
]; in lib.concatStringsSep " " flags;
};
}

View file

@ -1,81 +0,0 @@
{ inputs, lib, pkgs, ... }: let
name = "mc1-pure-vanilla";
ram-allocation-mb = 8192;
headroom-allocation-mb = 1024;
rcon-pass = "howdy";
ports = {
minecraft = 25566;
rcon = 25576;
};
modpack = pkgs.fetchModrinthModpack {
url = "https://cdn.modrinth.com/data/2wkV8mHp/versions/mFGJP1Ye/Server%20Optimization%201.21.11-2.1.mrpack";
packHash = "sha256-odvJs6s1/T13RQhE3NnpCIrulc98nd9vo9Alg/aU404=";
side = "server";
};
in {
services.minecraft-servers.servers.${name} = {
enable = false;
autoStart = true;
restart = "always";
serverProperties = {
server-ip = "0.0.0.0";
server-port = ports.minecraft;
server-name = name;
motd = "§cCan't connect to server";
log-ips = false;
hide-online-players = true;
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 = 10;
simulation-distance = 4;
enable-rcon = true;
sync-chunk-writes = false;
"rcon.password" = rcon-pass;
"rcon.port" = ports.rcon;
};
files = inputs.mc.lib.collectFilesAt modpack "config";
symlinks = inputs.mc.lib.collectFilesAt modpack "mods" // {
mods = pkgs.linkFarmFromDrvs "mods" (builtins.attrValues {
EasyAuth = pkgs.fetchurl { url = "https://cdn.modrinth.com/data/aZj58GfX/versions/R4EX0C3V/easyauth-mc1.21.11-3.4.3.jar"; hash = "sha256-T1PfPlyfkieOCsfoab+BpW8pB/CSDKlxGrS5FMgSMEU="; };
Floodgate = pkgs.fetchurl { url = "https://cdn.modrinth.com/data/bWrNNfkb/versions/81EuNxeZ/Floodgate-Fabric-2.2.6-b60.jar"; hash = "sha256-voH1QWv5GVm6EziJ3ERPjn5cx09/et73QiZlJ7l3foM="; };
Geyser = pkgs.fetchurl { url = "https://cdn.modrinth.com/data/wKkoqHrH/versions/6uw7I3Qj/geyser-fabric-Geyser-Fabric-2.9.6-b1133.jar"; hash = "sha256-aWMlDdHvNz6VaLVPdmO01YBAlQ7m4w8aUe47TbXxM60="; };
});
};
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:+ZGenerational" # Use generational ZGC (newer and better ZGC, requires Java v21+)
"-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 like C2ME)
"-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:SoftMaxHeapSize=${toString (ram-allocation-mb - headroom-allocation-mb)}M" # Leave 2GB headroom
]; in lib.concatStringsSep " " flags;
};
}

View file

@ -1,120 +0,0 @@
{ inputs, lib, pkgs, ... }: let
name = "mc2-create-aeronautics";
ram-allocation-mb = 12288;
headroom-allocation-mb = 2048;
rcon-pass = "howdy";
ports = {
minecraft = 25567;
rcon = 25577;
};
modpack = let
useLatest = true;
commit = "";
path = if !useLatest then "commit/${commit}" else "branch/main";
in pkgs.fetchPackwizModpack {
packHash = "";
url = "https://git.satr14.my.id/satr14/create-modpack/raw/${path}/pack.toml";
};
in {
systemd.services."minecraft-server-${name}" = {
environment.LD_LIBRARY_PATH = "${pkgs.stdenv.cc.cc.lib}/lib"; # physics toys mod fix
# serviceConfig.Nice = -5; # higher scheduling priority (causes fan noise even when idle)
};
services.minecraft-servers.servers.${name} = {
enable = false;
autoStart = true;
restart = "always";
serverProperties = {
server-ip = "0.0.0.0";
server-port = ports.minecraft;
server-name = name;
motd = "§cCan't connect to server";
log-ips = false;
hide-online-players = true;
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 = 6;
enable-rcon = true;
sync-chunk-writes = false;
"rcon.password" = rcon-pass;
"rcon.port" = ports.rcon;
};
symlinks = inputs.mc.lib.collectFilesAt modpack "mods" // {
"polymer/packsquash" = let packsquash-binary = pkgs.runCommand "packsquash" {
src = pkgs.fetchurl {
url = "https://github.com/ComunidadAylas/PackSquash/releases/download/v0.4.1/packsquash-x86_64-unknown-linux-gnu.zip";
sha256 = "sha256-VsGZewoiO5MjhIhwjlLO5d5uHynlAK5Jh16jH2k2rPs=";
};
nativeBuildInputs = [ pkgs.unzip ];
} ''
mkdir -p $out/bin
unzip $src -d $out/bin
chmod +x $out/bin/packsquash
''; in "${packsquash-binary}/bin/packsquash";
};
files = inputs.mc.lib.collectFilesAt modpack "config" // {
"config/proxy_protocol_support.json".value = {
enableProxyProtocol = false; # polymer auto host has issues with proxy protocol
whitelistTCPShieldServers = false;
proxyServerIPs = [ "127.0.0.1" "::1" ];
directAccessIPs = [ "127.0.0.0/8" "::1/128" ];
};
};
extraStartPre = let sed-commands = lib.concatStringsSep "\n" (
lib.mapAttrsToList (substitution: file:
''sed -i "s|${substitution}|''${${substitution}}|g" ${file}''
) {
"REPLACE_SVC_HOST" = "config/voicechat/voicechat-server.properties";
"REPLACE_RP_LINK" = "config/welcomemessage.json5";
"REPLACE_DC_BOT_TOKEN" = "config/simple-discord-link/simple-discord-link.toml";
"REPLACE_DC_OWNER_ROLE" = "config/simple-discord-link/simple-discord-link.toml";
}
); in ''
# shellcheck disable=SC1091
if [ -f modpack-config.env ]; then
source modpack-config.env
${sed-commands}
fi
'';
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:+ZGenerational" # Use generational ZGC (newer and better ZGC, requires Java v21+)
"-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 like C2ME)
"-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:SoftMaxHeapSize=${toString (ram-allocation-mb - headroom-allocation-mb)}M" # Leave 2GB headroom
]; in lib.concatStringsSep " " flags;
};
}

View file

@ -5,7 +5,6 @@
services = {
jellyfin = {
enable = true;
dataDir = "/mnt/data/apps/jellyfin";
hardwareAcceleration = {
enable = true;
device = "/dev/dri/renderD128";

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 = {
enable = true;
domain = "pass.proxy.${homelab.domain}";
backupDir = "/mnt/data/apps/vaultwarden/backups";
environmentFile = "/mnt/data/apps/vaultwarden/.env";
backupDir = "/mnt/data/vaultwarden/backups";
environmentFile = config.sops.secrets.vaultwarden_env.path;
config = {
ROCKET_PORT = 8060;
ROCKET_ADDRESS = "127.0.0.1";
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
htpasswd = "/mnt/data/apps/nginx/htpasswd";
{ config, homelab, lib, ... }: let
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 = ''
# proxy_set_header X-Auth-User $remote_user;
proxy_read_timeout 600s;
@ -8,7 +31,6 @@
proxy_cache off;
send_timeout 600s;
client_max_body_size 50000M;
proxy_ssl_session_reuse off;
'';
in {
users.users = {
@ -19,35 +41,24 @@ in {
security.acme = {
acceptTerms = true;
defaults.email = "admin@${homelab.domain}";
certs."${homelab.proxy.base}" = {
domain = "*.${homelab.proxy.base}";
extraDomainNames = [ homelab.proxy.base ];
environmentFile = "/mnt/data/apps/acme/cf-api.env";
certs."${base}" = {
domain = "*.${base}";
extraDomainNames = [ base ];
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 = {
nginx = {
enable = true;
package = pkgs.angie;
recommendedProxySettings = true;
recommendedTlsSettings = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
virtualHosts = {
"_" = {
default = true;
forceSSL = true;
useACMEHost = homelab.proxy.base;
useACMEHost = base;
# locations."/".return = "404";
locations."/" = {
proxyPass = "http://127.0.0.1:81"; # traefik for docker container dynamic proxy
@ -55,12 +66,12 @@ in {
extraConfig = exta-conf;
};
};
} // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair "${subdomain}.${homelab.proxy.base}" {
useACMEHost = homelab.proxy.base;
} // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair "${subdomain}.${base}" {
useACMEHost = base;
forceSSL = true;
locations."/".return = "301 ${cfg}";
}) homelab.proxy.redirects // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair (if subdomain == "@" then homelab.proxy.base else "${subdomain}.${homelab.proxy.base}") {
useACMEHost = homelab.proxy.base;
locations."/".return = "301 ${base}";
}) redirects // lib.mapAttrs' (subdomain: cfg: lib.nameValuePair (if subdomain == "@" then base else "${subdomain}.${base}") {
useACMEHost = base;
forceSSL = true;
extraConfig = ''
access_log /var/log/nginx/${subdomain}.access.log;
@ -69,16 +80,13 @@ in {
locations."/" = {
proxyPass = cfg.dest;
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;
};
}) homelab.proxy.hosts;
}) hosts;
};
traefik = {
enable = true;
dynamicConfigOptions = {
http.middlewares.auth.basicAuth.usersFile = htpasswd;
};
staticConfigOptions = {
entryPoints = {
traefik.address = "127.0.0.1:8082";
@ -98,6 +106,7 @@ in {
providers.docker = {
endpoint = "unix:///var/run/docker.sock";
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 = {
enable = true;
tunnels.homelab = {
credentialsFile = "/mnt/data/apps/cloudflared/homelab.json";
certificateFile = "/mnt/data/apps/cloudflared/cert.pem";
credentialsFile = config.sops.secrets.cloudflared_tunnel_credentials.path;
certificateFile = config.sops.secrets.cloudflared_cert.path;
default = "http_status:404";
ingress = homelab.routes;
ingress = routes;
};
};
@ -23,7 +31,7 @@
script = lib.concatMapStringsSep "\n" (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
'') (builtins.attrNames homelab.routes);
${pkgs.cloudflared}/bin/cloudflared tunnel --origincert ${config.sops.secrets.cloudflared_cert.path} route dns ${homelab.cf-tunnel-id} ${domain} || true
'') (builtins.attrNames routes);
};
}

View file

@ -16,8 +16,7 @@
};
programs = {
# LOCK IN
# steam.enable = true;
steam.enable = true;
gdk-pixbuf.modulePackages = [ pkgs.librsvg ];
appimage = {
enable = true;

View file

@ -7,7 +7,6 @@
catppuccin = {
enable = true;
autoEnable = true;
flavor = ctp-opt.flavor;
accent = ctp-opt.accent;
};

View file

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

View file

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

View file

@ -7,7 +7,6 @@
shell = pkgs.zsh;
extraGroups = [
"networkmanager"
"minecraft"
"wheel"
"dialout"
"libvirtd"
@ -17,8 +16,6 @@
"plugdev"
"adbusers"
"kvm"
"video"
"render"
];
};
}

View file

@ -1,3 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}

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