79 Commits

Author SHA1 Message Date
f9f3abee19 fix(pkgs): moving some home.packages to system 2025-11-02 16:50:13 +01:00
15bc0f211f fix(fish): fixing nixpkgs module with lib.getExe 2025-11-02 16:30:56 +01:00
f0fb53b480 feat(tailscale): adding tailscale to bunk 2025-11-02 15:47:49 +01:00
1ae85bd66e feat(fish): disable gpg, its fking up fish atm 2025-11-02 12:14:31 +01:00
87b49d0f58 feat(fish): adding some abbrs for dry running and show trace 2025-11-02 10:14:05 +01:00
c5a1c2861c feat(kanata) adding pipe symbol 2025-11-02 10:07:07 +01:00
8dc67e2b54 chore(update): flake lock 2025-10-28 19:47:35 +01:00
322136e4f3 Merge pull request 'bunk things' (#8) from bunk into main
Reviewed-on: #8
2025-10-28 19:47:07 +01:00
300eb66afc bunk things 2025-10-28 19:25:34 +01:00
545888878e Merge pull request 'chore(update): flake up' (#7) from upd into main
Reviewed-on: #7
2025-10-26 19:16:27 +01:00
5042675e0b chore(update): flake up 2025-10-26 19:14:50 +01:00
ece5e89a84 feat(hyprlock): visuals 2025-10-26 00:31:45 +02:00
2933bcdf02 feat(unbound): adding manual traefik data 2025-10-25 18:48:20 +02:00
59e548f02e feat(headscale): remove for now 2025-10-25 14:13:30 +02:00
2ffc94161d chore(dead): remove obsolete code 2025-10-25 14:04:38 +02:00
ff5490194b feat(headscale): just an initial test 2025-10-25 14:03:34 +02:00
1dd06ef3f5 chore(git): fix deprecated settings 2025-10-23 19:13:12 +02:00
ec9a3bd845 feat(waybar) some visual updates 2025-10-20 20:15:26 +02:00
2c08f78586 feat(hypr): more keybindings 2025-10-20 18:22:52 +02:00
d22801168f feat(hypr): add swapping window bind 2025-10-20 18:16:59 +02:00
0c86dc56bd chore(update): flake up 2025-10-18 14:57:12 +02:00
3d8deae6f3 feat(llm): testing some local models 2025-10-16 21:20:40 +02:00
cd978f5eb6 feat(hypr): back to hyprland, and fix some clib importing stuffs 2025-10-15 20:00:31 +02:00
64df7abad5 feat(hypr): clean up 2025-10-15 19:38:47 +02:00
8efa649d47 feat(homepage-dashboard): change vaultwarden icon 2025-10-15 18:01:39 +02:00
2dc09e23a0 chore(jellyseerr): typo 2025-10-15 17:50:11 +02:00
8fd2a7d9ad feat(homepage-dashboard): reintroduce path option 2025-10-15 17:49:30 +02:00
113892b75d chore(update): flake lock 2025-10-14 22:43:59 +02:00
001dfbf27f chore(traefik): delete dead code 2025-10-14 22:00:16 +02:00
3deca06206 Merge pull request 'refactor' (#6) from refactor into main
Reviewed-on: #6
2025-10-14 21:56:13 +02:00
07333b4544 feat(refactor): ready for merge 2025-10-14 21:50:44 +02:00
63f495fa0d feat(refactor): WIP 2.0 some progress 2025-10-13 21:13:53 +02:00
d2bd385367 feat(refactor): WIP refactor server modules 2025-10-12 21:07:30 +02:00
57cb48a11c feat(gaming): cleaning up gaming related pkgs 2025-10-11 16:44:54 +02:00
6b7ca2b194 feat(update): new kernel, new container versions and temporarily moving to zfs_unstable in waiting for stable to catch up with new kernel 2025-10-11 11:04:15 +02:00
e578a280db chore(update): flake lock and removing unmaintained pkgs 2025-10-11 09:40:35 +02:00
01ca3d7ebe feat(gitea): integrate with authentik 2025-10-08 20:39:54 +02:00
46aa5a9deb fix(fail2ban): some hacky fix 2025-10-07 21:05:43 +02:00
549037fe69 chore(flake) lock 2025-10-06 21:00:09 +02:00
0cb6862dcd feat(sqlite): adding sqlite pkgs 2025-10-06 20:57:01 +02:00
9e4454ff57 feat(gitea): move to cnst.dev domain, cf tunnel 2025-10-06 20:55:31 +02:00
15a20dd8e0 feat(pkgs): adding some dev pkgs to sobotka and dig as default 2025-10-05 19:27:15 +02:00
3306598f8a feat(jellyfin): adding to tnet 2025-10-05 19:10:43 +02:00
93f227ba7e feat(network): adding options for dns and search 2025-10-05 15:40:52 +02:00
9d20eff7f9 feat(jellyfin): TS testing 2025-10-05 10:47:08 +02:00
94d3f2ad35 feat(jellyfin): will this break things? 2025-10-05 10:35:22 +02:00
1d5bc22274 Merge branch 'main' into working 2025-10-05 10:21:16 +02:00
f2386a851e working 1 2025-10-05 10:11:40 +02:00
c9edc99a85 chore(revert): slowly introducing changes 2025-10-05 09:27:51 +02:00
67e83e3e4e feat(authentik): fixing some fail2ban things 2025-10-02 05:45:35 +02:00
923c810972 feat(authentik): fixing some fail2ban things 2025-10-01 18:00:55 +02:00
6ab35f4e91 feat(www): fixing fail2ban and other minor tweaks 2025-09-30 18:16:49 +02:00
593f0e619c chore(ded): remove dead code 2025-09-29 19:31:23 +02:00
688e23d229 feat(pstate): opt in changes and sooooo 2025-09-29 19:28:33 +02:00
725a3ed27e chore(niri): go to nixpkgs niri release 2025-09-29 17:10:38 +02:00
e45dc0d223 feat(homelab): fixing cf tunnels, authentik and tailscale! 2025-09-28 18:27:17 +02:00
bc78dd7302 chore(?): hm 2025-09-28 16:24:32 +02:00
94c34f8675 chore(update): flake lock 2025-09-28 08:03:38 +02:00
fda7d972c4 chore(age): adding bunk credentials to agenix 2025-09-27 19:54:03 +02:00
f6bb6672bb chore(agenix): refactor some secrets 2025-09-27 14:35:04 +02:00
68f1cb9b09 chore(misc): removing dead code and small insignificant changes 2025-09-26 20:41:26 +02:00
e721a2088b feat(homepage-dashboard): adding some disk info 2025-09-26 17:41:19 +02:00
551a47989c Merge pull request 'feat(swaybg) adding swaybg and some script' (#5) from wutwut into main
Reviewed-on: https://git.cnix.dev/cnst/cnix/pulls/5
2025-09-25 17:30:37 +02:00
2cb07c45a7 Merge pull request 'feat(swaybg) adding bg script' (#4) from wut into main
Reviewed-on: https://git.cnix.dev/cnst/cnix/pulls/4
2025-09-25 17:26:09 +02:00
4666731676 feat(swaybg) adding swaybg and some script 2025-09-25 17:17:49 +02:00
8fe6382c48 feat(swaybg) adding bg script 2025-09-25 17:16:55 +02:00
068f47e9a2 chore(alacritty): fix cfg 2025-09-24 18:46:36 +02:00
27bd976a60 chore(alacritty): fix cfg 2025-09-24 06:30:48 +02:00
9adfb329af feat(theme): go to adwaita gtk theme 2025-09-23 20:04:08 +02:00
757c3081fd feat(alacritty): change theme and flake lock 2025-09-23 20:02:08 +02:00
1d2f934c98 chore(?): remove deader code 2025-09-23 18:14:43 +02:00
86624f362d feat(IP): migrate to traefik and authentik, remove dead code 2025-09-23 18:13:28 +02:00
b752781064 feat(nextcloud): switch from nginx to caddy 2025-09-21 13:27:02 +02:00
884b40c71d chore(?): remove dead code 2025-09-21 10:32:05 +02:00
f861d363ca feat(nextcloud): finishing touches and other chores 2025-09-21 10:28:54 +02:00
c63daec95c feat(nextcloud): tweaks to nextcloud 2025-09-20 12:31:12 +02:00
2e1d28450b Merge pull request 'feat(nextcloud): back to basics' (#3) from nextc into main
Reviewed-on: https://git.cnix.dev/cnst/cnix/pulls/3
2025-09-19 20:09:18 +02:00
1228c800a1 feat(nextcloud): back to basics 2025-09-19 20:08:45 +02:00
1c8ccb6405 feat(sh): niri spawning script for stacking two windows of same app vertically 2025-09-19 20:03:11 +02:00
133 changed files with 3116 additions and 2826 deletions

716
flake.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,8 @@
{ {
description = "cnix nix"; description = "cnix nix";
outputs = outputs = inputs:
inputs: inputs.flake-parts.lib.mkFlake {inherit inputs;} {
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
systems = [ systems = [
"x86_64-linux" "x86_64-linux"
"aarch64-linux" "aarch64-linux"
@@ -17,9 +16,11 @@
./fmt-hooks.nix ./fmt-hooks.nix
]; ];
perSystem = perSystem = {
{ config, pkgs, ... }: config,
{ pkgs,
...
}: {
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
packages = [ packages = [
pkgs.git pkgs.git
@@ -51,6 +52,10 @@
inputs.nixpkgs-lib.follows = "nixpkgs"; inputs.nixpkgs-lib.follows = "nixpkgs";
}; };
authentik = {
url = "github:nix-community/authentik-nix/version/2025.8.4";
};
flake-compat.url = "github:edolstra/flake-compat"; flake-compat.url = "github:edolstra/flake-compat";
# Hyprland environment # Hyprland environment
@@ -135,8 +140,6 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
niri.url = "github:sodiboo/niri-flake";
# Custom # Custom
tuirun = { tuirun = {
url = "git+https://git.sr.ht/~canasta/tuirun"; url = "git+https://git.sr.ht/~canasta/tuirun";

View File

@@ -38,17 +38,11 @@ in
./settings.nix ./settings.nix
]; ];
boot.initrd.luks.devices."luks-0ad53967-bb38-4485-be75-ca55ae4c3b68".device = "/dev/disk/by-uuid/0ad53967-bb38-4485-be75-ca55ae4c3b68";
networking.hostName = "bunk"; networking.hostName = "bunk";
swapDevices = [
{
device = "/var/lib/swapfile";
size = 32 * 1024;
}
];
environment.variables.NH_FLAKE = "/home/cnst/.nix-config"; environment.variables.NH_FLAKE = "/home/cnst/.nix-config";
# https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion
system.stateVersion = lib.mkDefault "23.11"; system.stateVersion = lib.mkDefault "25.05";
} }

View File

@@ -1,48 +1,36 @@
# Do not modify this file! It was generated by nixos-generate-config # Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes # and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead. # to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{ {
config, imports =
lib, [ (modulesPath + "/installer/scan/not-detected.nix")
modulesPath,
...
}:
{
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
boot = {
initrd = {
availableKernelModules = [
"nvme"
"xhci_pci"
"ahci"
"usbhid"
"usb_storage"
"sd_mod"
]; ];
kernelModules = [ "amdgpu" ];
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/d15672b5-dc97-4f99-9ad2-70f9ddf20447";
fsType = "btrfs";
options = [ "subvol=@" ];
}; };
kernelModules = [ "kvm-amd" ]; boot.initrd.luks.devices."luks-2f0dfe96-bc63-4f38-b190-3d9fa45dc560".device = "/dev/disk/by-uuid/2f0dfe96-bc63-4f38-b190-3d9fa45dc560";
extraModulePackages = [ ];
};
fileSystems."/" = { fileSystems."/boot" =
device = "/dev/disk/by-uuid/da41c89a-7ab8-4697-9a14-0d115b97cc2e"; { device = "/dev/disk/by-uuid/F3FC-3CDF";
fsType = "ext4";
};
boot.initrd.luks.devices."luks-e75ac560-748f-4071-bbe7-479678400be3".device =
"/dev/disk/by-uuid/e75ac560-748f-4071-bbe7-479678400be3";
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/7E84-D168";
fsType = "vfat"; fsType = "vfat";
options = [ options = [ "fmask=0077" "dmask=0077" ];
"fmask=0022"
"dmask=0022"
];
}; };
swapDevices =
[ { device = "/dev/disk/by-uuid/e6464248-0d1e-4950-bf48-4cebeabaf871"; }
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking # 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 # (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 # still possible to use this option, but it's recommended to use it in conjunction

View File

@@ -27,6 +27,13 @@
}; };
network = { network = {
enable = true; enable = true;
nameservers = [
"192.168.88.1"
"192.168.88.69"
];
search = [
"taila7448a.ts.net"
];
interfaces = { interfaces = {
"wlp6s0" = { "wlp6s0" = {
allowedTCPPorts = [ allowedTCPPorts = [
@@ -73,8 +80,8 @@
enable = false; enable = false;
}; };
hyprland = { hyprland = {
enable = false; enable = true;
withUWSM = false; withUWSM = true;
}; };
inkscape = { inkscape = {
enable = false; enable = false;
@@ -86,7 +93,7 @@
enable = true; enable = true;
}; };
niri = { niri = {
enable = true; enable = false;
}; };
pkgs = { pkgs = {
enable = true; enable = true;
@@ -123,10 +130,10 @@
enable = false; enable = false;
}; };
thunar = { thunar = {
enable = true; enable = false;
}; };
yubikey = { yubikey = {
enable = true; enable = false;
}; };
zsh = { zsh = {
enable = false; enable = false;
@@ -168,7 +175,7 @@
enable = true; enable = true;
}; };
mullvad = { mullvad = {
enable = true; enable = false;
}; };
nix-ld = { nix-ld = {
enable = false; enable = false;
@@ -191,11 +198,14 @@
samba = { samba = {
enable = false; enable = false;
}; };
tailscale = {
enable = true;
};
udisks = { udisks = {
enable = true; enable = true;
}; };
zram = { zram = {
enable = false; enable = true;
}; };
}; };
system = { system = {

View File

@@ -10,7 +10,7 @@
name = "DP-3"; name = "DP-3";
width = 2560; width = 2560;
height = 1440; height = 1440;
refreshRate = 240; refreshRate = "143.99";
position = "0x0"; position = "0x0";
transform = 0; transform = 0;
bitDepth = 10; bitDepth = 10;
@@ -20,7 +20,7 @@
name = "HDMI-A-1"; name = "HDMI-A-1";
width = 1920; width = 1920;
height = 1080; height = 1080;
refreshRate = 60; refreshRate = "60";
position = "2560x0"; position = "2560x0";
# transform = 3; # transform = 3;
workspace = "5"; workspace = "5";
@@ -29,7 +29,7 @@
name = "eDP-1"; name = "eDP-1";
width = 1920; width = 1920;
height = 1200; height = 1200;
refreshRate = 60; refreshRate = "60";
workspace = "1"; workspace = "1";
} }
]; ];

View File

@@ -8,7 +8,7 @@
{ {
flake.nixosConfigurations = flake.nixosConfigurations =
let let
cLib = import ../lib inputs.nixpkgs.lib; clib = import ../lib inputs.nixpkgs.lib;
userConfig = "${self}/home"; userConfig = "${self}/home";
systemConfig = "${self}/system"; systemConfig = "${self}/system";
hostConfig = "${self}/hosts"; hostConfig = "${self}/hosts";
@@ -24,7 +24,6 @@
specialArgs = { specialArgs = {
inherit inherit
cLib
inputs inputs
outputs outputs
self self
@@ -37,17 +36,20 @@
smodPath smodPath
; ;
}; };
specialArgsWithClib = specialArgs // {
inherit clib;
};
in in
{ {
kima = nixosSystem { kima = nixosSystem {
inherit specialArgs; specialArgs = specialArgsWithClib;
modules = [ modules = [
./kima ./kima
"${self}/nix" "${self}/nix"
{ {
home-manager = { home-manager = {
users.cnst.imports = homeImports."cnst@kima"; users.cnst.imports = homeImports."cnst@kima";
extraSpecialArgs = specialArgs; extraSpecialArgs = specialArgsWithClib;
}; };
} }
self.nixosModules.nixos self.nixosModules.nixos
@@ -57,14 +59,14 @@
]; ];
}; };
bunk = nixosSystem { bunk = nixosSystem {
inherit specialArgs; specialArgs = specialArgsWithClib;
modules = [ modules = [
./bunk ./bunk
"${self}/nix" "${self}/nix"
{ {
home-manager = { home-manager = {
users.cnst.imports = homeImports."cnst@bunk"; users.cnst.imports = homeImports."cnst@bunk";
extraSpecialArgs = specialArgs; extraSpecialArgs = specialArgsWithClib;
}; };
} }
self.nixosModules.nixos self.nixosModules.nixos
@@ -82,6 +84,7 @@
self.nixosModules.settings self.nixosModules.settings
self.nixosModules.server self.nixosModules.server
inputs.agenix.nixosModules.default inputs.agenix.nixosModules.default
inputs.authentik.nixosModules.default
]; ];
}; };
ziggy = nixosSystem { ziggy = nixosSystem {
@@ -96,14 +99,14 @@
]; ];
}; };
toothpc = nixosSystem { toothpc = nixosSystem {
inherit specialArgs; specialArgs = specialArgsWithClib;
modules = [ modules = [
./toothpc ./toothpc
"${self}/nix" "${self}/nix"
{ {
home-manager = { home-manager = {
users.toothpick.imports = homeImports."toothpick@toothpc"; users.toothpick.imports = homeImports."toothpick@toothpc";
extraSpecialArgs = specialArgs; extraSpecialArgs = specialArgsWithClib;
}; };
} }
self.nixosModules.nixos self.nixosModules.nixos

View File

@@ -5,6 +5,7 @@
variant = "latest"; variant = "latest";
hardware = [ "amd" ]; hardware = [ "amd" ];
extraKernelParams = [ ]; extraKernelParams = [ ];
amdOverdrive.enable = true;
}; };
loader = { loader = {
default = { default = {
@@ -28,6 +29,13 @@
}; };
network = { network = {
enable = true; enable = true;
nameservers = [
"192.168.88.1"
"192.168.88.69"
];
search = [
"taila7448a.ts.net"
];
interfaces = { interfaces = {
"eno1" = { "eno1" = {
allowedTCPPorts = [ allowedTCPPorts = [
@@ -65,7 +73,7 @@
}; };
}; };
gamescope = { gamescope = {
enable = true; enable = false;
}; };
gimp = { gimp = {
enable = true; enable = true;
@@ -74,8 +82,8 @@
enable = false; enable = false;
}; };
hyprland = { hyprland = {
enable = false; enable = true;
withUWSM = false; withUWSM = true;
}; };
inkscape = { inkscape = {
enable = false; enable = false;
@@ -90,7 +98,7 @@
enable = true; enable = true;
}; };
niri = { niri = {
enable = true; enable = false;
}; };
pkgs = { pkgs = {
enable = true; enable = true;
@@ -214,6 +222,9 @@
scheduler = "scx_lavd"; scheduler = "scx_lavd";
flags = "--performance"; flags = "--performance";
}; };
tailscale = {
enable = true;
};
udisks = { udisks = {
enable = true; enable = true;
}; };

View File

@@ -10,7 +10,7 @@
name = "DP-3"; name = "DP-3";
width = 2560; width = 2560;
height = 1440; height = 1440;
refreshRate = 240; refreshRate = "143.99";
position = "0x0"; position = "0x0";
transform = 0; transform = 0;
bitDepth = 10; bitDepth = 10;
@@ -20,7 +20,7 @@
name = "HDMI-A-1"; name = "HDMI-A-1";
width = 1920; width = 1920;
height = 1080; height = 1080;
refreshRate = 60; refreshRate = "60";
position = "2560x0"; position = "2560x0";
transform = 3; transform = 3;
workspace = "5"; workspace = "5";
@@ -29,7 +29,7 @@
name = "eDP-1"; name = "eDP-1";
width = 1920; width = 1920;
height = 1200; height = 1200;
refreshRate = 60; refreshRate = "60";
workspace = "1"; workspace = "1";
} }
]; ];

View File

@@ -3,11 +3,9 @@
config, config,
pkgs, pkgs,
... ...
}: }: let
let
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups; ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
in in {
{
users.users.cnst = { users.users.cnst = {
isNormalUser = true; isNormalUser = true;
shell = pkgs.fish; shell = pkgs.fish;
@@ -41,6 +39,7 @@ in
"share" "share"
"jellyfin" "jellyfin"
"render" "render"
"traefik"
]; ];
}; };
@@ -51,8 +50,7 @@ in
./server.nix ./server.nix
]; ];
boot.initrd.luks.devices."luks-47b35d4b-467a-4637-a5f9-45177da62897".device = boot.initrd.luks.devices."luks-47b35d4b-467a-4637-a5f9-45177da62897".device = "/dev/disk/by-uuid/47b35d4b-467a-4637-a5f9-45177da62897";
"/dev/disk/by-uuid/47b35d4b-467a-4637-a5f9-45177da62897";
networking = { networking = {
hostName = "sobotka"; hostName = "sobotka";
@@ -69,8 +67,11 @@ in
]; ];
boot = { boot = {
supportedFilesystems = [ "zfs" ]; supportedFilesystems = ["zfs"];
zfs.extraPools = [ "data" ]; zfs = {
package = pkgs.zfs_unstable;
extraPools = ["data"];
};
}; };
services.zfs = { services.zfs = {
@@ -78,6 +79,8 @@ in
autoScrub.enable = true; autoScrub.enable = true;
}; };
environment.etc."nextcloud-admin-pass".text = "DeHKor3x8^eqqnBXjqhQ&QBl*3!sOLg8agfzOILihju#^0!2AfJ9W*vn";
environment.variables.NH_FLAKE = "/home/cnst/.nix-config"; environment.variables.NH_FLAKE = "/home/cnst/.nix-config";
# # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion # # https://nixos.wiki/wiki/FAQ/When_do_I_update_stateVersion

View File

@@ -3,8 +3,8 @@
boot = { boot = {
kernel = { kernel = {
variant = "latest"; variant = "latest";
hardware = [ "amd" ]; hardware = ["amd"];
extraKernelParams = [ ]; extraKernelParams = [];
}; };
loader = { loader = {
default = { default = {
@@ -109,7 +109,7 @@
enable = true; enable = true;
}; };
dev = { dev = {
enable = false; enable = true;
}; };
}; };
mysql-workbench = { mysql-workbench = {
@@ -213,6 +213,9 @@
scheduler = "scx_lavd"; scheduler = "scx_lavd";
flags = "--performance"; flags = "--performance";
}; };
tailscale = {
enable = false;
};
udisks = { udisks = {
enable = true; enable = true;
}; };

View File

@@ -3,97 +3,276 @@
enable = true; enable = true;
email = "adam@cnst.dev"; email = "adam@cnst.dev";
domain = "cnix.dev"; domain = "cnix.dev";
ip = "192.168.88.14";
user = "share"; user = "share";
group = "share"; group = "share";
uid = 994; uid = 994;
gid = 993; gid = 993;
gitea = { infra = {
authentik = {
enable = true;
url = "auth.cnst.dev";
port = 9000;
cloudflared = {
tunnelId = "b66f9368-db9e-4302-8b48-527cda34a635";
credentialsFile = config.age.secrets.authentikCloudflared.path;
};
};
traefik = {
enable = true;
};
tailscale = {
enable = true; enable = true;
}; };
unbound = { unbound = {
enable = true; enable = true;
}; };
caddy = {
enable = true;
};
homepage-dashboard = {
enable = true;
};
bazarr = {
enable = true;
};
prowlarr = {
enable = true;
};
lidarr = {
enable = true;
};
sonarr = {
enable = true;
};
radarr = {
enable = true;
};
jellyseerr = {
enable = true;
};
jellyfin = {
enable = true;
};
uptime-kuma = {
enable = true;
};
keycloak = {
enable = true;
url = "login.cnst.dev";
dbPasswordFile = config.age.secrets.keycloakDbPasswordFile.path;
cloudflared = {
tunnelId = "590f60f8-baaa-4106-b2d1-43740c79531e";
credentialsFile = config.age.secrets.keycloakCloudflared.path;
};
};
vaultwarden = {
enable = true;
url = "vault.cnst.dev";
cloudflared = {
tunnelId = "fdd98086-6a4c-44f2-bba0-eb86b833cce5";
credentialsFile = config.age.secrets.vaultwardenCloudflared.path;
};
};
ocis = {
enable = true;
url = "cloud.cnst.dev";
cloudflared = {
tunnelId = "8871dad0-e6ff-424c-9a6b-222ef0f492df";
credentialsFile = config.age.secrets.ocisCloudflared.path;
};
};
fail2ban = { fail2ban = {
enable = true; enable = true;
apiKeyFile = config.age.secrets.cloudflareFirewallApiKey.path; apiKeyFile = config.age.secrets.cloudflareFirewallApiKey.path;
zoneId = "0027acdfb8bbe010f55b676ad8698dfb"; zoneId = "0027acdfb8bbe010f55b676ad8698dfb";
}; };
syncthing = {
enable = false;
};
keepalived = { keepalived = {
enable = true; enable = true;
interface = "enp6s0"; interface = "enp6s0";
}; };
gluetun = {
enable = true;
};
podman = { podman = {
enable = true; enable = true;
gluetun.enable = true; };
www = {
enable = true;
url = "cnst.dev";
port = 8283;
cloudflared = {
tunnelId = "e5076186-efb7-405a-998c-6155af7fb221";
credentialsFile = config.age.secrets.wwwCloudflared.path;
};
};
};
services = {
homepage-dashboard = {
enable = true;
subdomain = "dash";
exposure = "local";
port = 8082;
};
n8n = {
enable = true;
subdomain = "n8n";
exposure = "local";
port = 5678;
homepage = {
name = "n8n";
description = "A workflow automation platform";
icon = "n8n.svg";
category = "Services";
};
};
ollama = {
enable = true;
subdomain = "ai";
exposure = "local";
port = 8001;
homepage = {
name = "ollama";
description = "AI platform";
icon = "ollama.svg";
category = "Services";
};
};
bazarr = {
enable = true;
subdomain = "bazarr";
exposure = "local";
port = 6767;
homepage = {
name = "Bazarr";
description = "Subtitle manager";
icon = "bazarr.svg";
category = "Arr";
};
};
prowlarr = {
enable = true;
subdomain = "prowlarr";
exposure = "local";
port = 9696;
homepage = {
name = "Prowlarr";
description = "PVR indexer";
icon = "prowlarr.svg";
category = "Arr";
};
};
flaresolverr = {
enable = true;
subdomain = "flaresolverr";
exposure = "local";
port = 8191;
homepage = {
name = "FlareSolverr";
description = "Proxy to bypass Cloudflare/DDoS-GUARD protection";
icon = "flaresolverr.svg";
category = "Arr";
};
};
lidarr = {
enable = true;
subdomain = "lidarr";
exposure = "local";
port = 8686;
homepage = {
name = "Lidarr";
description = "Music collection manager";
icon = "lidarr.svg";
category = "Arr";
};
};
sonarr = {
enable = true;
subdomain = "sonarr";
exposure = "local";
port = 8989;
homepage = {
name = "Sonarr";
description = "Internet PVR for Usenet and Torrents";
icon = "sonarr.svg";
category = "Arr";
};
};
radarr = {
enable = true;
subdomain = "radarr";
exposure = "local";
port = 7878;
homepage = {
name = "Radarr";
description = "Movie collection manager";
icon = "radarr.svg";
category = "Arr";
};
};
jellyseerr = {
enable = true;
subdomain = "jellyseerr";
exposure = "local";
port = 5055;
homepage = {
name = "Jellyseerr";
description = "Media request and discovery manager";
icon = "jellyseerr.svg";
category = "Arr";
};
};
jellyfin = {
enable = true;
subdomain = "fin";
exposure = "tailscale";
port = 8096;
homepage = {
name = "Jellyfin";
description = "The Free Software Media System";
icon = "jellyfin.svg";
category = "Media";
};
};
uptime-kuma = {
enable = true;
subdomain = "uptime";
exposure = "local";
port = 3001;
homepage = {
name = "Uptime Kuma";
description = "Service monitoring tool";
icon = "uptime-kuma.svg";
category = "Services";
};
};
gitea = {
enable = true;
subdomain = "git";
exposure = "tunnel";
port = 5003;
cloudflared = {
tunnelId = "33e2fb8e-ecef-4d42-b845-6d15e216e448";
credentialsFile = config.age.secrets.giteaCloudflared.path;
};
homepage = {
name = "Gitea";
description = "Git with a cup of tea";
icon = "gitea.svg";
category = "Services";
};
};
vaultwarden = {
enable = true;
subdomain = "vault";
exposure = "tunnel";
port = 8222;
cloudflared = {
tunnelId = "fdd98086-6a4c-44f2-bba0-eb86b833cce5";
credentialsFile = config.age.secrets.vaultwardenCloudflared.path;
};
homepage = {
name = "Vaultwarden";
description = "Password manager";
icon = "vaultwarden-light.svg";
category = "Services";
};
};
nextcloud = {
enable = true;
subdomain = "cloud";
exposure = "local";
port = 8182;
homepage = {
name = "Nextcloud";
description = "A safe home for all your data";
icon = "nextcloud.svg";
category = "Services";
};
};
qbittorrent = { qbittorrent = {
enable = true; enable = true;
subdomain = "qbt";
exposure = "local";
port = 8080; port = 8080;
homepage = {
name = "qBittorrent";
description = "Torrent client";
icon = "qbittorrent.svg";
category = "Downloads";
};
}; };
slskd = { slskd = {
enable = true; enable = true;
subdomain = "slskd";
exposure = "local";
port = 5030;
homepage = {
name = "Soulseek";
description = "Web-based Soulseek client";
icon = "slskd.svg";
category = "Downloads";
};
}; };
pihole = { pihole = {
enable = true; enable = true;
subdomain = "pihole";
exposure = "local";
port = 8053; port = 8053;
homepage = {
name = "PiHole";
description = "Adblocking and DNS service";
icon = "pi-hole.svg";
category = "Services";
path = "/admin";
};
}; };
}; };
}; };

View File

@@ -4,6 +4,10 @@
username = "cnst"; username = "cnst";
mail = "adam@cnst.dev"; mail = "adam@cnst.dev";
sshUser = "sobotka"; sshUser = "sobotka";
domains = {
local = "cnix.dev";
public = "cnst.dev";
};
}; };
}; };
} }

View File

@@ -10,7 +10,7 @@
name = "DVI-D-1"; name = "DVI-D-1";
width = 1920; width = 1920;
height = 1080; height = 1080;
refreshRate = 144; refreshRate = "144";
position = "0x0"; position = "0x0";
transform = 0; transform = 0;
workspace = "1"; workspace = "1";

View File

@@ -1,5 +1,4 @@
{ config, ... }: {config, ...}: {
{
server = { server = {
enable = true; enable = true;
email = "adam@cnst.dev"; email = "adam@cnst.dev";
@@ -12,9 +11,6 @@
unbound = { unbound = {
enable = true; enable = true;
}; };
caddy = {
enable = true;
};
homepage-dashboard = { homepage-dashboard = {
enable = false; enable = false;
}; };

26
lib/server/default.nix Normal file
View File

@@ -0,0 +1,26 @@
{lib}: let
server = {
mkDomain = config: service: let
localDomain = config.settings.accounts.domains.local;
publicDomain = config.settings.accounts.domains.public;
tailscaleDomain = "ts.${publicDomain}";
in
if service.exposure == "tunnel"
then publicDomain
else if service.exposure == "tailscale"
then tailscaleDomain
else localDomain;
mkFullDomain = config: service: let
domain = server.mkDomain config service;
in "${service.subdomain}.${domain}";
mkHostDomain = config: service: let
domain = server.mkDomain config service;
in "${domain}";
mkSubDomain = config: service: "${service.subdomain}";
};
in {
server = server;
}

View File

@@ -1,11 +1,11 @@
lib: { lib: {
bgs = rec { bgs = rec {
files = { files = {
wallpaper_1 = "~/media/images/bg_1.jpg"; wallpaper_1 = "~/media/images/bgs/bg_1.jpg";
wallpaper_2 = "~/media/images/bg_2.jpg"; wallpaper_2 = "~/media/images/bgs/bg_2.jpg";
wallpaper_3 = "~/media/images/bg_3.jpg"; wallpaper_3 = "~/media/images/bgs/bg_3.jpg";
wallpaper_4 = "~/media/images/waterwindow.jpg"; wallpaper_4 = "~/media/images/bgs/waterwindow.jpg";
wallpaper_5 = "~/media/images/barngreet.png"; wallpaper_5 = "~/media/images/bgs/barngreet.png";
}; };
list = builtins.attrNames files; list = builtins.attrNames files;

View File

@@ -100,7 +100,6 @@
./nixos/services/virtualisation ./nixos/services/virtualisation
./nixos/services/locate ./nixos/services/locate
./nixos/services/mullvad ./nixos/services/mullvad
./nixos/services/mullvad-netns
./nixos/services/nfs ./nixos/services/nfs
./nixos/services/nix-ld ./nixos/services/nix-ld
./nixos/services/openssh ./nixos/services/openssh
@@ -114,6 +113,7 @@
./nixos/services/udisks ./nixos/services/udisks
./nixos/services/xserver ./nixos/services/xserver
./nixos/services/zram ./nixos/services/zram
./nixos/services/tailscale
./nixos/system/fonts ./nixos/system/fonts
./nixos/system/locale ./nixos/system/locale
@@ -123,26 +123,6 @@
server = { server = {
imports = [ imports = [
./server ./server
./server/caddy
./server/fail2ban
./server/homepage-dashboard
./server/ocis
./server/keycloak
./server/vaultwarden
./server/bazarr
./server/prowlarr
./server/lidarr
./server/radarr
./server/sonarr
./server/syncthing
./server/jellyseerr
./server/jellyfin
./server/podman
./server/unbound
./server/uptime-kuma
./server/keepalived
./server/gitea
./server/postgres
]; ];
}; };
settings = { settings = {

View File

@@ -14,36 +14,37 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
programs.alacritty = { programs.alacritty = {
enable = true; enable = true;
theme = "gruvbox_material_hard_dark";
settings = { settings = {
# Default colors # Default colors
colors.primary = { # colors = {
background = "#282828"; # primary = {
foreground = "#d4be98"; # background = "#282828";
}; # foreground = "#d4be98";
colors = { # };
# Normal colors # # Normal colors
normal = { # normal = {
black = "#3c3836"; # black = "#3c3836";
red = "#ea6962"; # red = "#ea6962";
green = "#a9b665"; # green = "#a9b665";
yellow = "#d8a657"; # yellow = "#d8a657";
blue = "#7daea3"; # blue = "#7daea3";
magenta = "#d3869b"; # magenta = "#d3869b";
cyan = "#89b482"; # cyan = "#89b482";
white = "#d4be98"; # white = "#d4be98";
}; # };
# Bright colors (same as normal colors) # # Bright colors (same as normal colors)
bright = { # bright = {
black = "#3c3836"; # black = "#3c3836";
red = "#ea6962"; # red = "#ea6962";
green = "#a9b665"; # green = "#a9b665";
yellow = "#d8a657"; # yellow = "#d8a657";
blue = "#7daea3"; # blue = "#7daea3";
magenta = "#d3869b"; # magenta = "#d3869b";
cyan = "#89b482"; # cyan = "#89b482";
white = "#d4be98"; # white = "#d4be98";
}; # };
}; # };
font = { font = {
size = 12; size = 12;
normal = { normal = {
@@ -73,7 +74,7 @@ in
]; ];
window = { window = {
dynamic_title = true; dynamic_title = true;
opacity = 0.9; opacity = 0.95;
padding = { padding = {
x = 5; x = 5;
y = 5; y = 5;

View File

@@ -6,8 +6,9 @@
}: }:
let let
inherit (lib) mkIf mkEnableOption; inherit (lib) mkIf mkEnableOption;
inherit (lib.meta) getExe; packageNames = map (p: p.pname or p.name or null) config.home.packages;
inherit (pkgs) eza bat; hasPackage = name: lib.any (x: x == name) packageNames;
hasEza = hasPackage "eza";
cfg = config.home.programs.fish; cfg = config.home.programs.fish;
in in
{ {
@@ -28,7 +29,9 @@ in
nixclean = "nh clean all --keep 3"; nixclean = "nh clean all --keep 3";
nixdev = "nix develop ~/.nix-config -c $SHELL"; nixdev = "nix develop ~/.nix-config -c $SHELL";
nixup = "nh os switch -H $hostname"; nixup = "nh os switch -H $hostname";
nixupv = "nh os switch -v -H $hostname"; nixupn = "nh os switch -n -H $hostname";
nixupv = "nh os switch -v --show-trace -H $hostname";
nixupvn = "nh os switch -n -v --show-trace -H $hostname";
flakeup = "nix flake update"; flakeup = "nix flake update";
}; };
shellAliases = { shellAliases = {
@@ -44,12 +47,8 @@ in
nset = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/settings.nix"; nset = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/settings.nix";
nixosmodules = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix"; nixosmodules = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix";
nmod = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix"; nmod = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix";
tree = "${getExe eza} --tree --icons=always"; ls = mkIf hasEza "eza";
cat = "${getExe bat} --style=plain"; tree = mkIf hasEza "eza --tree --icons=always";
ls = "${getExe eza} -h --git --icons --color=auto --group-directories-first -s extension";
ll = "${getExe eza} -l --git --icons --color=auto --group-directories-first -s extension";
lat = "${getExe eza} -lah --tree --color=auto --group-directories-first -s extension";
la = "${getExe eza} -lah --color=auto --group-directories-first -s extension";
# Clear screen and scrollback # Clear screen and scrollback
clear = "printf '\\033[2J\\033[3J\\033[1;1H'"; clear = "printf '\\033[2J\\033[3J\\033[1;1H'";
}; };
@@ -59,14 +58,12 @@ in
# Merge history when pressing up # Merge history when pressing up
up-or-search = lib.readFile ./up-or-search.fish; up-or-search = lib.readFile ./up-or-search.fish;
# Check stuff in PATH # Check stuff in PATH
nix-inspect = nix-inspect = # fish
# fish
'' ''
set -s PATH | grep "PATH\[.*/nix/store" | cut -d '|' -f2 | grep -v -e "-man" -e "-terminfo" | perl -pe 's:^/nix/store/\w{32}-([^/]*)/bin$:\1:' | sort | uniq set -s PATH | grep "PATH\[.*/nix/store" | cut -d '|' -f2 | grep -v -e "-man" -e "-terminfo" | perl -pe 's:^/nix/store/\w{32}-([^/]*)/bin$:\1:' | sort | uniq
''; '';
}; };
interactiveShellInit = interactiveShellInit = # fish
# fish
'' ''
# Open command buffer in vim when alt+e is pressed # Open command buffer in vim when alt+e is pressed
bind \ee edit_command_buffer bind \ee edit_command_buffer

View File

@@ -28,7 +28,7 @@ in
enableFishIntegration = config.programs.fish.enable; enableFishIntegration = config.programs.fish.enable;
enableZshIntegration = config.programs.zsh.enable; enableZshIntegration = config.programs.zsh.enable;
settings = { settings = {
theme = "GruvboxDarkHard"; theme = "Gruvbox Dark Hard";
focus-follows-mouse = true; focus-follows-mouse = true;
resize-overlay = "never"; resize-overlay = "never";
background-opacity = 0.95; background-opacity = 0.95;

View File

@@ -15,17 +15,16 @@ in
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
home.packages = [ pkgs.gh ]; home.packages = [ pkgs.gh ];
programs.git = { programs = {
git = {
enable = true; enable = true;
userName = osConfig.settings.accounts.username; settings = {
userEmail = osConfig.settings.accounts.mail;
delta = {
enable = true;
options.dark = true;
};
extraConfig = {
# user.signingkey = "${config.home.homeDirectory}/.ssh/id_ed25519.pub"; # user.signingkey = "${config.home.homeDirectory}/.ssh/id_ed25519.pub";
user.signingkey = "${config.home.homeDirectory}/.config/git/allowed_signers"; user = {
name = osConfig.settings.accounts.username;
email = osConfig.settings.accounts.mail;
signingkey = "${config.home.homeDirectory}/.config/git/allowed_signers";
};
signing = { signing = {
format = lib.mkDefault "ssh"; format = lib.mkDefault "ssh";
key = "${config.home.homeDirectory}/.ssh/id_ed25519"; key = "${config.home.homeDirectory}/.ssh/id_ed25519";
@@ -56,6 +55,14 @@ in
".jj" ".jj"
]; ];
}; };
delta = {
enableGitIntegration = true;
enable = true;
options.dark = true;
};
};
xdg.configFile."git/allowed_signers".text = '' xdg.configFile."git/allowed_signers".text = ''
${osConfig.settings.accounts.mail} namespaces="git" ${osConfig.settings.accounts.sshKey} ${osConfig.settings.accounts.mail} namespaces="git" ${osConfig.settings.accounts.sshKey}
''; '';

View File

@@ -1,26 +1,20 @@
{ {
inputs,
pkgs,
lib, lib,
osConfig, osConfig,
cLib, clib,
... ...
}: }:
let let
inherit (lib) mkIf mkEnableOption; inherit (lib) mkIf;
cfg = osConfig.nixos.programs.hyprland; cfg = osConfig.nixos.programs.hyprland;
hyprlockFlake = inputs.hyprlock.packages.${pkgs.system}.hyprlock;
# hyprlockPkg = pkgs.hyprlock;
#
bg = osConfig.settings.theme.background; bg = osConfig.settings.theme.background;
inherit (cLib.theme.bgs) resolve; inherit (clib.theme.bgs) resolve;
in in
{ {
config = mkIf cfg.enable { config = mkIf cfg.enable {
programs.hyprlock = { programs.hyprlock = {
enable = true; enable = true;
package = hyprlockFlake;
settings = { settings = {
general = { general = {
# disable_loading_bar = true; # disable_loading_bar = true;
@@ -60,6 +54,7 @@ in
position = "0, 20"; position = "0, 20";
halign = "center"; halign = "center";
valign = "center"; valign = "center";
font_family = "DepartureMono Nerd Font Mono Italic";
} }
]; ];
label = [ label = [
@@ -71,7 +66,7 @@ in
shadow_boost = 0.5; shadow_boost = 0.5;
color = "rgba(FFFFFFFF)"; color = "rgba(FFFFFFFF)";
font_size = 25; font_size = 25;
font_family = "Input Mono Compressed"; font_family = "DepartureMono Nerd Font Mono Regular";
position = "0, 230"; position = "0, 230";
halign = "center"; halign = "center";
valign = "center"; valign = "center";
@@ -84,7 +79,7 @@ in
shadow_boost = 0.5; shadow_boost = 0.5;
color = "rgba(FFFFFFFF)"; color = "rgba(FFFFFFFF)";
font_size = 85; font_size = 85;
font_family = "Input Mono Compressed"; font_family = "DepartureMono Nerd Font Mono Regular";
position = "0, 300"; position = "0, 300";
halign = "center"; halign = "center";
valign = "center"; valign = "center";

View File

@@ -7,6 +7,9 @@
let let
inherit (lib) mkIf mkEnableOption; inherit (lib) mkIf mkEnableOption;
cfg = config.home.programs.mpv; cfg = config.home.programs.mpv;
inherit (config.xdg.userDirs) videos;
inherit (config.home) homeDirectory;
shaders_dir = "${pkgs.mpv-shim-default-shaders}/share/mpv-shim-default-shaders/shaders";
in in
{ {
options = { options = {
@@ -15,8 +18,71 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
programs.mpv = { programs.mpv = {
enable = true; enable = true;
defaultProfiles = [ "gpu-hq" ]; config = {
scripts = [ pkgs.mpvScripts.mpris ]; profile = "gpu-hq";
gpu-context = "wayland";
vo = "gpu-next";
video-sync = "display-resample";
interpolation = true;
tscale = "oversample";
fullscreen = false;
keep-open = true;
sub-auto = "fuzzy";
sub-font = "Noto Sans Medium";
sub-blur = 10;
screenshot-format = "png";
title = "\${filename} - mpv";
script-opts = "osc-title=\${filename},osc-boxalpha=150,osc-visibility=never,osc-boxvideo=yes";
ytdl-format = "bestvideo[height<=?1440]+bestaudio/best";
ao = "pipewire";
alang = "eng,en";
slang = "eng,en,enUS";
glsl-shader = "${homeDirectory}/.config/mpv/shaders/FSR.glsl";
scale = "lanczos";
cscale = "lanczos";
dscale = "mitchell";
deband = "yes";
scale-antiring = 1;
osc = "no";
osd-on-seek = "no";
osd-bar = "no";
osd-bar-w = 30;
osd-bar-h = "0.2";
osd-duration = 750;
really-quiet = "yes";
autofit = "65%";
};
bindings = {
"ctrl+a" = "script-message osc-visibility cycle";
};
scripts = with pkgs.mpvScripts; [
mpris
uosc
thumbfast
sponsorblock
autocrop
];
};
programs.yt-dlp = {
enable = true;
extraConfig = ''
-o ${videos}/youtube/%(title)s.%(ext)s
'';
};
home = {
file = {
".config/mpv/shaders/FSR.glsl".source = "${shaders_dir}/FSR.glsl";
};
packages = with pkgs; [
jellyfin-mpv-shim
];
}; };
}; };
} }

View File

@@ -62,16 +62,8 @@ in
[ [
cmatrix cmatrix
xcur2png xcur2png
ripgrep
file
fd
gnused
nix-tree nix-tree
wireguard-tools wireguard-tools
unzip
zip
gnutar
p7zip
] ]
(mkIf cfg.common.enable [ (mkIf cfg.common.enable [
@@ -88,7 +80,7 @@ in
hyprpicker hyprpicker
libnotify libnotify
pamixer pamixer
oculante loupe
adwaita-icon-theme adwaita-icon-theme
qt5.qtwayland qt5.qtwayland
qt6.qtwayland qt6.qtwayland

View File

@@ -10,7 +10,7 @@
"group/system" "group/system"
], ],
"modules-center": [ "modules-center": [
"niri/workspaces" "hyprland/workspaces"
], ],
"modules-right": [ "modules-right": [
"custom/progress", "custom/progress",
@@ -126,16 +126,28 @@
"all-outputs": false, "all-outputs": false,
"format": "{icon}", "format": "{icon}",
"format-icons": { "format-icons": {
"urgent": "", "1": "1",
"visible": "", "2": "2",
"empty": "" "3": "3",
"4": "4",
"5": "5",
"6": "6",
"7": "7",
"8": "8",
"9": "9",
"default": "_",
"active": "_"
}, },
"on-click": "activate", "on-click": "activate",
"show-special": false, "show-special": false,
"on-scroll-up": "hyprctl dispatch workspace r-1", "on-scroll-up": "hyprctl dispatch workspace r-1",
"on-scroll-down": "hyprctl dispatch workspace r+1", "on-scroll-down": "hyprctl dispatch workspace r+1",
"persistent-workspaces": { "persistent-workspaces": {
"*": 3 "1": [],
"2": [],
"3": [],
"4": [],
"5": []
} }
}, },
"niri/workspaces": { "niri/workspaces": {

View File

@@ -28,8 +28,8 @@ tooltip label {
margin: 0 0px; margin: 0 0px;
background-color: transparent; background-color: transparent;
color: #fbf1c7; color: #fbf1c7;
border-top: 3px solid transparent; border-top: 4px solid transparent;
border-bottom: 3px solid transparent; border-bottom: 4px solid transparent;
} }
#workspaces button:hover { #workspaces button:hover {
@@ -45,7 +45,7 @@ tooltip label {
background-image: url("assets/button.svg"); background-image: url("assets/button.svg");
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 18px 15px; background-size: 21px 18px;
} }
#custom-trayicon { #custom-trayicon {

View File

@@ -27,10 +27,10 @@ in
}; };
gtk = { gtk = {
enable = true; enable = true;
theme = { # theme = {
package = pkgs.orchis-theme; # package = pkgs.orchis-theme;
name = "Orchis-Grey-Dark-Compact"; # name = "Orchis-Grey-Dark-Compact";
}; # };
iconTheme = { iconTheme = {
# package = pkgs.adwaita-icon-theme; # package = pkgs.adwaita-icon-theme;
package = pkgs.papirus-icon-theme; package = pkgs.papirus-icon-theme;

View File

@@ -1,22 +1,14 @@
{ {
osConfig, osConfig,
lib, lib,
pkgs,
inputs,
... ...
}: }: let
let
inherit (lib) mkIf; inherit (lib) mkIf;
cfg = osConfig.nixos.programs.hyprland; cfg = osConfig.nixos.programs.hyprland;
in {
hypridleFlake = inputs.hypridle.packages.${pkgs.system}.hypridle;
# hypridlePkg = pkgs.hypridle;
in
{
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.hypridle = { services.hypridle = {
enable = true; enable = true;
package = hypridleFlake;
settings = { settings = {
general = { general = {
lock_cmd = "hyprlock"; lock_cmd = "hyprlock";

View File

@@ -1,18 +1,14 @@
{ {
lib, lib,
pkgs,
inputs,
osConfig, osConfig,
cLib, clib,
... ...
}: }: let
let
inherit (lib) mkIf; inherit (lib) mkIf;
cfg = osConfig.nixos.programs.hyprland; cfg = osConfig.nixos.programs.hyprland;
hyprpaperFlake = inputs.hyprpaper.packages.${pkgs.system}.default;
bg = osConfig.settings.theme.background; bg = osConfig.settings.theme.background;
bgs = cLib.theme.bgs; bgs = clib.theme.bgs;
monitorMappings = [ monitorMappings = [
{ {
@@ -32,12 +28,10 @@ let
bg = bg.primary; bg = bg.primary;
} }
]; ];
in in {
{
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.hyprpaper = { services.hyprpaper = {
enable = true; enable = true;
package = hyprpaperFlake;
settings = { settings = {
ipc = "on"; ipc = "on";

View File

@@ -84,15 +84,15 @@ in
"application/pdf" = "org.pwmt.zathura-pdf-mupdf.desktop"; "application/pdf" = "org.pwmt.zathura-pdf-mupdf.desktop";
"inode/directory" = "thunar.desktop"; "inode/directory" = "thunar.desktop";
"image/apng" = "oculante.desktop"; "image/apng" = "feh.desktop";
"image/avif" = "oculante.desktop"; "image/avif" = "feh.desktop";
"image/bmp" = "oculante.desktop"; "image/bmp" = "feh.desktop";
"image/gif" = "oculante.desktop"; "image/gif" = "feh.desktop";
"image/jpeg" = "oculante.desktop"; "image/jpeg" = "feh.desktop";
"image/png" = "oculante.desktop"; "image/png" = "feh.desktop";
"image/svg+xml" = "oculante.desktop"; "image/svg+xml" = "feh.desktop";
"image/tiff" = "oculante.desktop"; "image/tiff" = "feh.desktop";
"image/webp" = "oculante.desktop"; "image/webp" = "feh.desktop";
"video/H264" = [ "video/H264" = [
"mpv.desktop" "mpv.desktop"

View File

@@ -5,7 +5,12 @@
... ...
}: }:
let let
inherit (lib) mkOption types; inherit (lib)
mkOption
types
mkEnableOption
mkIf
;
cfg = config.nixos.boot.kernel; cfg = config.nixos.boot.kernel;
hasHardware = hw: builtins.elem hw cfg.hardware; hasHardware = hw: builtins.elem hw cfg.hardware;
@@ -37,8 +42,11 @@ in
); );
default = [ ]; default = [ ];
description = "List of hardware types (e.g. GPU and CPU vendors) to configure kernel settings for."; description = "List of hardware types (e.g. GPU and CPU vendors) to configure kernel settings for.";
}; };
amdOverdrive.enable = mkEnableOption "Enable AMD pstate/overdrive";
extraKernelParams = mkOption { extraKernelParams = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ ]; default = [ ];
@@ -74,7 +82,7 @@ in
"quiet" "quiet"
"splash" "splash"
] ]
++ (if hasHardware "amd" then [ "amd_pstate=active" ] else [ ]) ++ (if hasHardware "amd" then [ ] else [ ])
++ (if hasHardware "intel" then [ ] else [ ]) ++ (if hasHardware "intel" then [ ] else [ ])
++ (if hasHardware "nvidia" then [ ] else [ ]) ++ (if hasHardware "nvidia" then [ ] else [ ])
++ cfg.extraKernelParams; ++ cfg.extraKernelParams;
@@ -85,5 +93,6 @@ in
++ (if hasHardware "nvidia" then [ "nouveau" ] else [ ]) ++ (if hasHardware "nvidia" then [ "nouveau" ] else [ ])
++ cfg.extraBlacklistedModules; ++ cfg.extraBlacklistedModules;
}; };
hardware.amdgpu.overdrive.enable = mkIf cfg.amdOverdrive.enable true;
}; };
} }

View File

@@ -19,13 +19,13 @@ let
commonPackages = with pkgs; [ commonPackages = with pkgs; [
libva libva
vaapiVdpau libva-vdpau-driver
libvdpau-va-gl libvdpau-va-gl
]; ];
commonPackages32 = with pkgs.pkgsi686Linux; [ commonPackages32 = with pkgs.pkgsi686Linux; [
libva libva
vaapiVdpau libva-vdpau-driver
libvdpau-va-gl libvdpau-va-gl
]; ];
@@ -89,7 +89,8 @@ in
config = mkIf cfg.enable (mkMerge [ config = mkIf cfg.enable (mkMerge [
{ {
hardware.graphics = { hardware = {
graphics = {
enable = true; enable = true;
enable32Bit = true; enable32Bit = true;
extraPackages = flatten ( extraPackages = flatten (
@@ -121,6 +122,7 @@ in
extraPackages32 = flatten (concatMap (_: commonPackages32) cfg.vendors); extraPackages32 = flatten (concatMap (_: commonPackages32) cfg.vendors);
}; };
};
environment.systemPackages = flatten ( environment.systemPackages = flatten (
concatMap ( concatMap (
@@ -145,10 +147,6 @@ in
); );
} }
(mkIf (hasVendor "amd") {
hardware.amdgpu.overdrive.enable = true;
})
(mkIf (hasVendor "nvidia") { (mkIf (hasVendor "nvidia") {
hardware.nvidia = { hardware.nvidia = {
package = package =

View File

@@ -2,38 +2,47 @@
config, config,
lib, lib,
... ...
}: }: let
let inherit
inherit (lib) (lib)
mkIf mkIf
mkEnableOption mkEnableOption
mkOption mkOption
types types
; ;
cfg = config.nixos.hardware.network; cfg = config.nixos.hardware.network;
in in {
{
options = { options = {
nixos.hardware.network = { nixos.hardware.network = {
enable = mkEnableOption "Enable the custom networking module"; enable = mkEnableOption "Enable the custom networking module";
nameservers = mkOption {
type = types.listOf types.str;
default = [];
description = "The list of nameservers ";
};
search = mkOption {
type = types.listOf types.str;
default = [];
description = "Domain search paths";
};
interfaces = mkOption { interfaces = mkOption {
type = types.attrsOf ( type = types.attrsOf (
types.submodule { types.submodule {
options = { options = {
allowedTCPPorts = mkOption { allowedTCPPorts = mkOption {
type = types.listOf types.int; type = types.listOf types.int;
default = [ ]; default = [];
description = "List of allowed TCP ports for this interface."; description = "List of allowed TCP ports for this interface.";
}; };
allowedUDPPorts = mkOption { allowedUDPPorts = mkOption {
type = types.listOf types.int; type = types.listOf types.int;
default = [ ]; default = [];
description = "List of allowed UDP ports for this interface."; description = "List of allowed UDP ports for this interface.";
}; };
}; };
} }
); );
default = { }; default = {};
description = "Network interface configurations."; description = "Network interface configurations.";
}; };
extraHosts = mkOption { extraHosts = mkOption {
@@ -47,7 +56,7 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
assertions = [ assertions = [
{ {
assertion = cfg.interfaces != { } -> config.networking.networkmanager.enable; assertion = cfg.interfaces != {} -> config.networking.networkmanager.enable;
message = "Network interfaces configured but NetworkManager is not enabled"; message = "Network interfaces configured but NetworkManager is not enabled";
} }
]; ];
@@ -55,6 +64,8 @@ in
networking = { networking = {
networkmanager.enable = true; networkmanager.enable = true;
nftables.enable = true; nftables.enable = true;
nameservers = cfg.nameservers;
search = cfg.search;
firewall = { firewall = {
enable = true; enable = true;
inherit (cfg) interfaces; inherit (cfg) interfaces;
@@ -63,8 +74,8 @@ in
}; };
systemd.services.NetworkManager = { systemd.services.NetworkManager = {
wants = [ "nftables.service" ]; wants = ["nftables.service"];
after = [ "nftables.service" ]; after = ["nftables.service"];
}; };
}; };
} }

View File

@@ -3,14 +3,11 @@
lib, lib,
pkgs, pkgs,
... ...
}: }: let
let
inherit (lib.meta) getExe;
inherit (pkgs) eza bat;
inherit (lib) mkIf mkEnableOption mkMerge; inherit (lib) mkIf mkEnableOption mkMerge;
cfg = config.nixos.programs.fish; cfg = config.nixos.programs.fish;
in in {
{
options = { options = {
nixos.programs.fish = { nixos.programs.fish = {
enable = mkEnableOption "Enables fish shell"; enable = mkEnableOption "Enables fish shell";
@@ -22,6 +19,7 @@ in
(mkIf cfg.enable { (mkIf cfg.enable {
programs.fish = { programs.fish = {
enable = true; enable = true;
useBabelfish = true;
vendor = { vendor = {
completions.enable = true; completions.enable = true;
config.enable = true; config.enable = true;
@@ -37,7 +35,9 @@ in
nixclean = "nh clean all --keep 3"; nixclean = "nh clean all --keep 3";
nixdev = "nix develop ~/.nix-config -c $SHELL"; nixdev = "nix develop ~/.nix-config -c $SHELL";
nixup = "nh os switch -H $hostname"; nixup = "nh os switch -H $hostname";
nixupv = "nh os switch -v -H $hostname"; nixupn = "nh os switch -n -H $hostname";
nixupv = "nh os switch -v --show-trace -H $hostname";
nixupvn = "nh os switch -n -v --show-trace -H $hostname";
flakeup = "nix flake update"; flakeup = "nix flake update";
}; };
shellAliases = { shellAliases = {
@@ -53,12 +53,8 @@ in
nset = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/settings.nix"; nset = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/settings.nix";
nixosmodules = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix"; nixosmodules = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix";
nmod = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix"; nmod = "$EDITOR /home/$USER/.nix-config/hosts/$hostname/modules.nix";
tree = "${getExe eza} --tree --icons=always"; ls = lib.getExe pkgs.eza;
cat = "${getExe bat} --style=plain"; tree = "${lib.getExe pkgs.eza} --tree --icons=always";
ls = "${getExe eza} -h --git --icons --color=auto --group-directories-first -s extension";
ll = "${getExe eza} -l --git --icons --color=auto --group-directories-first -s extension";
lat = "${getExe eza} -lah --tree --color=auto --group-directories-first -s extension";
la = "${getExe eza} -lah --color=auto --group-directories-first -s extension";
# Clear screen and scrollback # Clear screen and scrollback
clear = "printf '\\033[2J\\033[3J\\033[1;1H'"; clear = "printf '\\033[2J\\033[3J\\033[1;1H'";
}; };

View File

@@ -37,9 +37,9 @@ in
}; };
gestures = { gestures = {
workspace_swipe = true; # workspace_swipe = true;
workspace_swipe_distance = 400; workspace_swipe_distance = 400;
workspace_swipe_fingers = 3; # workspace_swipe_fingers = 3;
workspace_swipe_cancel_ratio = 0.2; workspace_swipe_cancel_ratio = 0.2;
workspace_swipe_min_speed_to_force = 5; workspace_swipe_min_speed_to_force = 5;
workspace_swipe_direction_lock = true; workspace_swipe_direction_lock = true;

View File

@@ -49,20 +49,6 @@ in
"$mod, P, pseudo," "$mod, P, pseudo,"
"$mod, J, togglesplit," "$mod, J, togglesplit,"
"$mod, C, exec, hyprctl dispatch exec copyq toggle" "$mod, C, exec, hyprctl dispatch exec copyq toggle"
"$mod, left, movefocus, l"
"$mod, right, movefocus, r"
"$mod, up, movefocus, u"
"$mod, down, movefocus, d"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod SHIFT, 1, movetoworkspace, 1" "$mod SHIFT, 1, movetoworkspace, 1"
"$mod SHIFT, 2, movetoworkspace, 2" "$mod SHIFT, 2, movetoworkspace, 2"
"$mod SHIFT, 3, movetoworkspace, 3" "$mod SHIFT, 3, movetoworkspace, 3"
@@ -75,6 +61,30 @@ in
"$mod SHIFT, 0, movetoworkspace, 10" "$mod SHIFT, 0, movetoworkspace, 10"
"CTRL SHIFT, Escape, exec, ${runOnce "resources"}" "CTRL SHIFT, Escape, exec, ${runOnce "resources"}"
"$mod, 1, workspace, 1"
"$mod, 2, workspace, 2"
"$mod, 3, workspace, 3"
"$mod, 4, workspace, 4"
"$mod, 5, workspace, 5"
"$mod, 6, workspace, 6"
"$mod, 7, workspace, 7"
"$mod, 8, workspace, 8"
"$mod, 9, workspace, 9"
"$mod, 0, workspace, 10"
"$mod, left, movefocus, l"
"$mod, right, movefocus, r"
"$mod, up, movefocus, u"
"$mod, down, movefocus, d"
"$mod SHIFT, left, resizeactive, -20 0"
"$mod SHIFT, right, resizeactive, 20 0"
"$mod SHIFT, up, resizeactive, 0 -20"
"$mod SHIFT, down, resizeactive, 0 20"
"$mod CTRL, left, swapwindow, l"
"$mod CTRL, right, swapwindow, r"
"$mod CTRL, up, swapwindow, u"
"$mod CTRL, down, swapwindow, d"
",XF86AudioLowerVolume, exec, volume-control.sh --dec" ",XF86AudioLowerVolume, exec, volume-control.sh --dec"
",XF86AudioRaiseVolume, exec, volume-control.sh --inc" ",XF86AudioRaiseVolume, exec, volume-control.sh --inc"
",XF86AudioMute, exec, volume-control.sh --toggle" ",XF86AudioMute, exec, volume-control.sh --toggle"
@@ -99,7 +109,7 @@ in
(mkIf (host == "kima") { (mkIf (host == "kima") {
programs.hyprland.settings = { programs.hyprland.settings = {
"$terminal" = "ghostty"; "$terminal" = "alacritty";
"$browser" = "zen"; "$browser" = "zen";
"$browserinc" = "zen --private-window"; "$browserinc" = "zen --private-window";
"$mod" = "SUPER"; "$mod" = "SUPER";
@@ -111,7 +121,7 @@ in
(mkIf (host == "bunk") { (mkIf (host == "bunk") {
programs.hyprland.settings = { programs.hyprland.settings = {
"$terminal" = "foot"; "$terminal" = "alacritty";
"$browser" = "zen"; "$browser" = "zen";
"$browserinc" = "zen --private-window"; "$browserinc" = "zen --private-window";
"$mod" = "ALT_L"; "$mod" = "ALT_L";

View File

@@ -21,7 +21,7 @@ in
let let
resolution = resolution =
if m.width != null && m.height != null then if m.width != null && m.height != null then
"${toString m.width}x${toString m.height}@${toString m.refreshRate}" "${toString m.width}x${toString m.height}@${m.refreshRate}"
else else
"preferred"; "preferred";

View File

@@ -1,6 +1,5 @@
{ {
config, config,
inputs,
lib, lib,
pkgs, pkgs,
... ...
@@ -14,22 +13,22 @@ in
nixos.programs.niri.enable = mkEnableOption "Enables niri"; nixos.programs.niri.enable = mkEnableOption "Enables niri";
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
nixpkgs.overlays = [ inputs.niri.overlays.niri ];
environment = { environment = {
variables = { variables = {
DISPLAY = ":0";
NIXOS_OZONE_WL = "1"; NIXOS_OZONE_WL = "1";
QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
}; };
systemPackages = with pkgs; [ systemPackages = with pkgs; [
xwayland-satellite-unstable xwayland-satellite
wl-clipboard wl-clipboard
wayland-utils wayland-utils
xdg-utils
]; ];
}; };
systemd.user.services.niri-flake-polkit.enable = false; systemd.user.services.niri-flake-polkit.enable = false;
programs.niri = { programs.niri = {
enable = true; enable = true;
package = pkgs.niri-unstable;
}; };
}; };
} }

View File

@@ -78,10 +78,17 @@ in
openssl openssl
xmrig xmrig
ocl-icd ocl-icd
dig
unzip
zip
gnutar
gnused
p7zip
ripgrep
file
] ]
(mkIf cfg.common.enable [ (mkIf cfg.common.enable [
qt6.full
swappy swappy
wayfreeze wayfreeze
imagemagick imagemagick
@@ -96,9 +103,6 @@ in
]) ])
(mkIf cfg.desktop.enable [ (mkIf cfg.desktop.enable [
protonup
winetricks
wine
geekbench geekbench
unigine-heaven unigine-heaven
]) ])
@@ -109,15 +113,13 @@ in
(mkIf cfg.server.enable [ (mkIf cfg.server.enable [
nvtopPackages.intel nvtopPackages.intel
nvtopPackages.amd
dig
helix helix
zfs
zfstools zfstools
]) ])
(mkIf cfg.dev.enable [ (mkIf cfg.dev.enable [
# lldb_20 # some biuld error atm # lldb_20 # some biuld error atm
sqlite
gemini-cli gemini-cli
nfs-utils nfs-utils
gcc gcc
@@ -144,7 +146,6 @@ in
prettierd prettierd
# php84Packages.php-cs-fixer # php84Packages.php-cs-fixer
shfmt shfmt
luaformatter
black black
]) ])
]; ];

View File

@@ -1,6 +1,7 @@
{ {
config, config,
lib, lib,
pkgs,
... ...
}: }:
let let
@@ -17,6 +18,20 @@ in
enable = true; enable = true;
gamescopeSession.enable = true; gamescopeSession.enable = true;
}; };
gamescope = {
enable = true;
capSysNice = true;
args = [
"--rt"
"--expose-wayland"
];
}; };
}; };
environment.systemPackages = with pkgs; [
protonup-ng
wine
winetricks
wine-wayland
];
};
} }

View File

@@ -74,21 +74,11 @@ in {
wgCredentials.file = "${self}/secrets/wgCredentials.age"; wgCredentials.file = "${self}/secrets/wgCredentials.age";
wgSobotkaPrivateKey.file = "${self}/secrets/wgSobotkaPrivateKey.age"; wgSobotkaPrivateKey.file = "${self}/secrets/wgSobotkaPrivateKey.age";
gluetunEnvironment.file = "${self}/secrets/gluetunEnvironment.age"; gluetunEnvironment.file = "${self}/secrets/gluetunEnvironment.age";
keycloakCloudflared.file = "${self}/secrets/keycloakCloudflared.age";
keycloakDbPasswordFile.file = "${self}/secrets/keycloakDbPasswordFile.age";
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
ocisCloudflared.file = "${self}/secrets/ocisCloudflared.age";
vaultwardenCloudflared.file = "${self}/secrets/vaultwardenCloudflared.age";
vaultwardenEnvironment.file = "${self}/secrets/vaultwardenEnvironment.age";
homepageEnvironment.file = "${self}/secrets/homepageEnvironment.age";
pihole.file = "${self}/secrets/pihole.age";
slskd.file = "${self}/secrets/slskd.age";
}; };
}) })
(mkIf cfg.ziggy.enable { (mkIf cfg.ziggy.enable {
secrets = { secrets = {
cloudflareDnsCredentialsZiggy.file = "${self}/secrets/cloudflareDnsCredentialsZiggy.age"; cloudflareDnsCredentialsZiggy.file = "${self}/secrets/cloudflareDnsCredentialsZiggy.age";
piholeZiggy.file = "${self}/secrets/piholeZiggy.age";
}; };
}) })
(mkIf cfg.toothpc.enable { (mkIf cfg.toothpc.enable {

View File

@@ -63,7 +63,7 @@ in
settings = rec { settings = rec {
tuigreet_session = tuigreet_session =
let let
session = "${pkgs.niri-unstable}/bin/niri-session"; session = "${pkgs.niri}/bin/niri-session";
tuigreet = "${lib.getExe pkgs.tuigreet}"; tuigreet = "${lib.getExe pkgs.tuigreet}";
in in
{ {

View File

@@ -16,14 +16,10 @@ in
services.kanata = { services.kanata = {
enable = true; enable = true;
package = pkgs.kanata-with-cmd; package = pkgs.kanata-with-cmd;
keyboards.hhkbse = { keyboards.default = {
extraDefCfg = '' extraDefCfg = ''
process-unmapped-keys yes process-unmapped-keys yes
''; '';
devices = [
"/dev/input/by-id/usb-PFU_Limited_HHKB-Hybrid-event-kbd"
"/dev/input/event2"
];
config = builtins.readFile (./. + "/hhkbse.kbd"); config = builtins.readFile (./. + "/hhkbse.kbd");
}; };
}; };

View File

@@ -18,6 +18,7 @@
2 3 4 5 6 7 8 9 0 + ´ ' § 2 3 4 5 6 7 8 9 0 + ´ ' §
e p ¨ e p ¨
l ö ä l ö ä
-
z x rmet z x rmet
) )
@@ -25,13 +26,16 @@
_ _ _ _ _ _ _ _ _ _ pgdn pgup del _ _ _ _ _ _ _ _ _ _ pgdn pgup del
_ _ ' _ _ '
_ _ _ _ _ _
_
_ _ @level3 _ _ @level3
) )
(deflayer level3 (deflayer level3
RA-2 RA-3 S-4 RA-5 S-¨ RA-7 RA-8 RA-9 RA-0 RA-+ ⇥ ⇤ S-' RA-2 RA-3 S-4 RA-5 S-¨ RA-7 RA-8 RA-9 RA-0 RA-+ ⇥ ⇤ S-'
RA-5 ▲ RA-¨ RA-5 ▲ RA-¨
◀ ▼ ▶ ◀ ▼ ▶
RA-<
RA-S-z RA-S-x @level3 RA-S-z RA-S-x @level3
) )

View File

@@ -1,50 +0,0 @@
{ self, pkgs, ... }:
{
age.secrets.wgCredentials = {
file = "${self}/secrets/wgCredentials.age";
mode = "0400";
owner = "root";
group = "root";
path = "/etc/wireguard/mullvad.conf";
};
systemd.services.mullvad-netns = {
description = "WireGuard Mullvad netns for VMs";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.writeShellScript "mullvad-netns-up" ''
set -euo pipefail
ip netns add mullvad || true
ip link add veth0 type veth peer name veth1 || true
ip link set veth1 netns mullvad
ip addr add 10.250.0.1/24 dev veth0 || true
ip link set veth0 up
ip netns exec mullvad ip addr add 10.250.0.2/24 dev veth1 || true
ip netns exec mullvad ip link set veth1 up
ip netns exec mullvad wg-quick up /etc/wireguard/mullvad.conf
ip netns exec mullvad ip route add default dev wg0 || true
nft add table ip mullvad-nat || true
nft add chain ip mullvad-nat postrouting { type nat hook postrouting priority 100 \; } || true
nft add rule ip mullvad-nat postrouting ip saddr 10.250.0.0/24 oif "wg0" masquerade || true
''}";
ExecStop = "${pkgs.writeShellScript "mullvad-netns-down" ''
set -euo pipefail
ip netns exec mullvad wg-quick down /etc/wireguard/mullvad.conf || true
ip link delete veth0 || true
ip netns delete mullvad || true
nft delete table ip mullvad-nat || true
''}";
};
# no wantedBy here -> won't start at boot
};
}

View File

@@ -0,0 +1,16 @@
{
config,
lib,
...
}:
with lib; let
cfg = config.nixos.services.tailscale;
in {
options.nixos.services.tailscale = {
enable = mkEnableOption "Enable tailscale";
};
config = mkIf cfg.enable {
services.tailscale.enable = true;
};
}

View File

@@ -45,7 +45,6 @@ in
# nodePackages_latest.sql-formatter # nodePackages_latest.sql-formatter
prettierd prettierd
shfmt shfmt
luaformatter
black black
]; ];
}; };

View File

@@ -26,7 +26,7 @@ in
inputs.fonts.packages.${pkgs.system}.vcr-mono inputs.fonts.packages.${pkgs.system}.vcr-mono
noto-fonts noto-fonts
noto-fonts-cjk-sans noto-fonts-cjk-sans
noto-fonts-emoji noto-fonts-color-emoji
liberation_ttf liberation_ttf
fira-code-symbols fira-code-symbols
font-awesome font-awesome

View File

@@ -30,13 +30,19 @@ in
enable = true; enable = true;
xdgOpenUsePortal = cfg.xdgOpenUsePortal; xdgOpenUsePortal = cfg.xdgOpenUsePortal;
config = { config = {
common.default = [ "gtk" ]; common.default = [
"gtk"
"gnome"
];
hyprland.default = [ hyprland.default = [
"gtk" "gtk"
"hyprland" "hyprland"
]; ];
}; };
extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; extraPortals = with pkgs; [
xdg-desktop-portal-gtk
xdg-desktop-portal-gnome
];
}; };
}; };
} }

View File

@@ -1,54 +0,0 @@
{
config,
lib,
...
}:
let
unit = "bazarr";
srv = config.server;
cfg = config.server.${unit};
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${unit}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Bazarr";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Subtitle manager";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "bazarr.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Arr";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString config.services.${unit}.listenPort}
'';
};
};
}

View File

@@ -1,63 +0,0 @@
{
config,
lib,
...
}: let
inherit (lib) mkIf mkEnableOption;
cfg = config.server.caddy;
getCloudflareCredentials = hostname:
if hostname == "ziggy"
then config.age.secrets.cloudflareDnsCredentialsZiggy.path
else if hostname == "sobotka"
then config.age.secrets.cloudflareDnsCredentials.path
else throw "Unknown hostname: ${hostname}";
in {
options = {
server.caddy.enable = mkEnableOption "Enables caddy";
};
config = mkIf cfg.enable {
networking.firewall = let
ports = [
80
443
];
in {
allowedTCPPorts = ports;
};
security.acme = {
acceptTerms = true;
defaults.email = config.server.email;
certs.${config.server.domain} = {
reloadServices = ["caddy.service"];
domain = "${config.server.domain}";
extraDomainNames = ["*.${config.server.domain}"];
dnsProvider = "cloudflare";
dnsResolver = "1.1.1.1:53";
dnsPropagationCheck = true;
group = config.services.caddy.group;
environmentFile = getCloudflareCredentials config.networking.hostName;
};
};
services.caddy = {
enable = true;
globalConfig = ''
auto_https off
'';
virtualHosts = {
"http://${config.server.domain}" = {
extraConfig = ''
redir https://{host}{uri}
'';
};
"http://*.${config.server.domain}" = {
extraConfig = ''
redir https://{host}{uri}
'';
};
};
};
};
}

View File

@@ -1,97 +1,16 @@
{ {
self,
lib, lib,
config,
... ...
}: }: let
let clib = import "${self}/lib/server" {inherit lib;};
inherit (lib) mkOption types; in {
cfg = config.server; imports = [
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups; {
in _module.args.clib = clib;
{ }
options.server = { ./options.nix
enable = lib.mkEnableOption "The server services and configuration variables"; ./infra
email = mkOption { ./services
default = "";
type = types.str;
description = ''
Email name to be used to access the server services via Caddy reverse proxy
'';
};
domain = mkOption {
default = "";
type = types.str;
description = ''
Domain name to be used to access the server services via Caddy reverse proxy
'';
};
user = lib.mkOption {
default = "share";
type = lib.types.str;
description = ''
User to run the server services as
'';
};
group = lib.mkOption {
default = "share";
type = lib.types.str;
description = ''
Group to run the server services as
'';
};
uid = lib.mkOption {
default = 1000;
type = lib.types.int;
description = ''
UID to run the server services as
'';
};
gid = lib.mkOption {
default = 1000;
type = lib.types.int;
description = ''
GID to run the server services as
'';
};
timeZone = lib.mkOption {
default = "Europe/Stockholm";
type = lib.types.str;
description = ''
Time zone to be used for the server services
'';
};
};
config = lib.mkIf cfg.enable {
users = {
groups.${cfg.group} = {
gid = cfg.gid;
};
users.${cfg.user} = {
uid = cfg.uid;
isSystemUser = true;
group = cfg.group;
extraGroups = ifTheyExist [
"audio"
"video"
"docker"
"libvirtd"
"qemu-libvirtd"
"rtkit"
"fail2ban"
"vaultwarden"
"qbittorrent"
"lidarr"
"prowlarr"
"bazarr"
"sonarr"
"radarr"
"media"
"share"
"render"
"input"
]; ];
};
};
};
} }

View File

@@ -1,111 +0,0 @@
# from @notthebee
{
lib,
config,
pkgs,
...
}:
let
cfg = config.server.fail2ban;
in
{
options.server.fail2ban = {
enable = lib.mkEnableOption {
description = "Enable cloudflare fail2ban";
};
apiKeyFile = lib.mkOption {
description = "File containing your API key, scoped to Firewall Rules: Edit";
type = lib.types.str;
example = lib.literalExpression ''
Authorization: Bearer Qj06My1wXJEzcW46QCyjFbSMgVtwIGfX63Ki3NOj79o=
'''
'';
};
zoneId = lib.mkOption {
type = lib.types.str;
};
jails = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
serviceName = lib.mkOption {
example = "vaultwarden";
type = lib.types.str;
};
failRegex = lib.mkOption {
type = lib.types.str;
example = "Login failed from IP: <HOST>";
};
ignoreRegex = lib.mkOption {
type = lib.types.str;
default = "";
};
maxRetry = lib.mkOption {
type = lib.types.int;
default = 3;
};
};
}
);
};
};
config = lib.mkIf cfg.enable {
services.fail2ban = {
enable = true;
extraPackages = [
pkgs.curl
pkgs.jq
];
jails = lib.attrsets.mapAttrs (name: value: {
settings = {
bantime = "30d";
findtime = "1h";
enabled = true;
backend = "systemd";
journalmatch = "_SYSTEMD_UNIT=${value.serviceName}.service";
port = "http,https";
filter = "${name}";
maxretry = 3;
action = "cloudflare-token-agenix";
};
}) cfg.jails;
};
environment.etc = lib.attrsets.mergeAttrsList [
(lib.attrsets.mapAttrs' (
name: value:
(lib.nameValuePair "fail2ban/filter.d/${name}.conf" {
text = ''
[Definition]
failregex = ${value.failRegex}
ignoreregex = ${value.ignoreRegex}
'';
})
) cfg.jails)
{
"fail2ban/action.d/cloudflare-token-agenix.conf".text =
let
notes = "Fail2Ban on ${config.networking.hostName}";
cfapi = "https://api.cloudflare.com/client/v4/zones/${cfg.zoneId}/firewall/access_rules/rules";
in
''
[Definition]
actionstart =
actionstop =
actioncheck =
actionunban = id=$(curl -s -X GET "${cfapi}" \
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
| jq -r '.result[] | select(.notes == "${notes}" and .configuration.target == "ip" and .configuration.value == "<ip>") | .id')
if [ -z "$id" ]; then echo "id for <ip> cannot be found"; exit 0; fi; \
curl -s -X DELETE "${cfapi}/$id" \
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
--data '{"cascade": "none"}'
actionban = curl -X POST "${cfapi}" -H @${cfg.apiKeyFile} -H "Content-Type: application/json" --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"${notes}"}'
[Init]
name = cloudflare-token-agenix
'';
}
];
};
}

View File

@@ -1,117 +0,0 @@
# taken from @jtojnar
{
config,
lib,
...
}:
let
unit = "gitea";
srv = config.server;
cfg = config.server.${unit};
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "git.${srv.domain}";
};
port = lib.mkOption {
type = lib.types.int;
default = 5003;
description = "The port to host Gitea on.";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Gitea";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Git with a cup of tea";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "gitea.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
appName = "cnix code forge";
database = {
type = "postgres";
socket = "/run/postgresql";
name = "gitea";
user = "gitea";
createDatabase = false;
};
lfs = {
enable = true;
};
settings = {
cors = {
ENABLED = true;
SCHEME = "https";
ALLOW_DOMAIN = cfg.url;
};
log = {
MODE = "console";
};
mailer = {
ENABLED = false;
MAILER_TYPE = "sendmail";
FROM = "noreply+adam@cnst.dev";
SENDMAIL_PATH = "/run/wrappers/bin/sendmail";
};
picture = {
DISABLE_GRAVATAR = true;
};
repository = {
DEFAULT_BRANCH = "main";
DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls";
DISABLE_DOWNLOAD_SOURCE_ARCHIVES = true;
};
indexer = {
REPO_INDEXER_ENABLED = true;
};
server = {
DOMAIN = cfg.url;
LANDING_PAGE = "explore";
HTTP_PORT = cfg.port;
ROOT_URL = "https://${cfg.url}/";
};
security = {
DISABLE_GIT_HOOKS = false;
};
service = {
DISABLE_REGISTRATION = true;
};
session = {
COOKIE_SECURE = true;
};
};
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:5003
'';
};
server.postgresql.databases = [
{
database = "gitea";
}
];
};
}

View File

@@ -1,233 +0,0 @@
{
config,
lib,
...
}:
let
unit = "homepage-dashboard";
cfg = config.server.homepage-dashboard;
srv = config.server;
in
{
options.server.homepage-dashboard = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
misc = lib.mkOption {
default = [ ];
type = lib.types.listOf (
lib.types.attrsOf (
lib.types.submodule {
options = {
description = lib.mkOption {
type = lib.types.str;
};
href = lib.mkOption {
type = lib.types.str;
};
siteMonitor = lib.mkOption {
type = lib.types.str;
};
icon = lib.mkOption {
type = lib.types.str;
};
};
}
)
);
};
};
config = lib.mkIf cfg.enable {
services.glances.enable = true;
services.${unit} = {
enable = true;
allowedHosts = srv.domain;
settings = {
layout = [
{
Glances = {
header = false;
style = "row";
columns = 4;
};
}
{
Arr = {
header = true;
style = "column";
};
}
{
Downloads = {
header = true;
style = "column";
};
}
{
Media = {
header = true;
style = "column";
};
}
{
Services = {
header = true;
style = "column";
};
}
];
headerStyle = "clean";
statusStyle = "dot";
hideVersion = "true";
};
widgets = [
{
openmeteo = {
label = "Kalmar";
timezone = "Europe/Stockholm";
units = "metric";
cache = 5;
latitude = 56.707262;
longitude = 16.324541;
};
}
{
datetime = {
text_size = "x1";
format = {
hour12 = false;
timeStyle = "short";
dateStyle = "long";
};
};
}
{
resources = {
label = "";
memory = true;
disk = [ "/" ];
};
}
];
services =
let
homepageCategories = [
"Arr"
"Media"
"Downloads"
"Services"
"Smart Home"
];
hl = config.server;
mergedServices = hl // hl.podman;
homepageServices =
x:
(lib.attrsets.filterAttrs (
name: value: value ? homepage && value.homepage.category == x
) mergedServices);
in
lib.lists.forEach homepageCategories (cat: {
"${cat}" =
lib.lists.forEach
(lib.attrsets.mapAttrsToList (name: value: {
inherit name;
url = value.url;
homepage = value.homepage;
}) (homepageServices "${cat}"))
(x: {
"${x.homepage.name}" = {
icon = x.homepage.icon;
description = x.homepage.description;
href = "https://${x.url}${x.homepage.path or ""}";
siteMonitor = "https://${x.url}${x.homepage.path or ""}";
};
});
})
++ [ { Misc = cfg.misc; } ]
++ [
{
Glances =
let
port = toString config.services.glances.port;
in
[
{
Info = {
widget = {
type = "glances";
url = "http://localhost:${port}";
metric = "info";
chart = false;
version = 4;
};
};
}
{
"CPU Temp" = {
widget = {
type = "glances";
url = "http://localhost:${port}";
metric = "sensor:Tctl";
chart = false;
version = 4;
};
};
}
{
"GPU Radeon" = {
widget = {
type = "glances";
url = "http://localhost:${port}";
metric = "sensor:junction";
chart = false;
version = 4;
};
};
}
{
"GPU Intel" = {
widget = {
type = "glances";
url = "http://localhost:${port}";
metric = "sensor:pkg";
chart = false;
version = 4;
};
};
}
{
Processes = {
widget = {
type = "glances";
url = "http://localhost:${port}";
metric = "process";
chart = false;
version = 4;
};
};
}
{
Network = {
widget = {
type = "glances";
url = "http://localhost:${port}";
metric = "network:enp6s0";
chart = false;
version = 4;
};
};
}
];
}
];
};
services.caddy.virtualHosts."${srv.domain}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString config.services.${unit}.listenPort}
'';
};
};
}

View File

@@ -0,0 +1,133 @@
{
config,
lib,
self,
...
}: let
unit = "authentik";
cfg = config.server.infra.${unit};
srv = config.server.infra;
in {
options.server.infra.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "auth.${srv.www.url}";
};
port = lib.mkOption {
type = lib.types.port;
description = "The local port the service runs on";
};
cloudflared = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
homepage = {
name = "Authentik";
description = "An open-source IdP for modern SSO";
icon = "authentik.svg";
category = "Services";
};
};
config = lib.mkIf cfg.enable {
age.secrets = {
authentikEnv = {
file = "${self}/secrets/authentikEnv.age";
};
authentikCloudflared = {
file = "${self}/secrets/authentikCloudflared.age";
};
};
server.infra = {
fail2ban = {
jails = {
authentik = {
serviceName = "authentik";
failRegex = ''^.*Username or password is incorrect.*IP:\s*<HOST>'';
};
};
};
};
services = {
authentik = {
enable = true;
environmentFile = config.age.secrets.authentikEnv.path;
settings = {
email = {
};
disable_startup_analytics = true;
avatars = "initials";
};
};
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://127.0.0.1:9000";
};
};
traefik = {
dynamicConfigOptions = {
http = {
middlewares = {
authentik = {
forwardAuth = {
address = "https://localhost:9443/outpost.goauthentik.io/auth/traefik";
trustForwardHeader = true;
authResponseHeaders = [
"X-authentik-username"
"X-authentik-groups"
"X-authentik-email"
"X-authentik-name"
"X-authentik-uid"
"X-authentik-jwt"
"X-authentik-meta-jwks"
"X-authentik-meta-outpost"
"X-authentik-meta-provider"
"X-authentik-meta-app"
"X-authentik-meta-version"
];
};
};
};
services = {
auth.loadBalancer.servers = [
{
url = "http://localhost:9000";
}
];
};
routers = {
auth = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.url}`) && PathPrefix(`/outpost.goauthentik.io/`)";
service = "auth";
tls.certResolver = "letsencrypt";
};
};
};
};
};
};
};
}

View File

@@ -0,0 +1,13 @@
{
imports = [
./authentik
./fail2ban
./keepalived
./podman
./postgres
./tailscale
./traefik
./unbound
./www
];
}

View File

@@ -0,0 +1,131 @@
# from @notthebee
{
lib,
config,
pkgs,
...
}: let
cfg = config.server.infra.fail2ban;
in {
options.server.infra.fail2ban = {
enable = lib.mkEnableOption {
description = "Enable cloudflare fail2ban";
};
apiKeyFile = lib.mkOption {
description = "File containing your API key, scoped to Firewall Rules: Edit";
type = lib.types.str;
example = lib.literalExpression ''
Authorization: Bearer vH6-p0y=i4w3n7TjKqZ@x8D_lR!A9b2cOezXgUuJdE5F
'''
'';
};
zoneId = lib.mkOption {
type = lib.types.str;
};
jails = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
serviceName = lib.mkOption {
example = "vaultwarden";
type = lib.types.str;
};
_groupsre = lib.mkOption {
type = lib.types.lines;
example = ''(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)'';
default = "";
};
failRegex = lib.mkOption {
type = lib.types.lines;
example = ''
^Login failed from IP: <HOST>$
^Two-factor challenge failed from <HOST>$
'';
};
ignoreRegex = lib.mkOption {
type = lib.types.str;
default = "";
};
datePattern = lib.mkOption {
type = lib.types.str;
default = "";
example = '',?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"'';
description = "Optional datepattern line for the fail2ban filter.";
};
maxRetry = lib.mkOption {
type = lib.types.int;
default = 3;
};
};
}
);
};
};
config = lib.mkIf cfg.enable {
services.fail2ban = {
enable = true;
extraPackages = [
pkgs.curl
pkgs.jq
];
jails =
lib.attrsets.mapAttrs (name: value: {
settings = {
bantime = "24h";
findtime = "10m";
enabled = true;
backend = "systemd";
journalmatch = "_SYSTEMD_UNIT=${value.serviceName}.service";
port = "http,https";
filter = "${name}";
maxretry = 3;
action = "cloudflare-token-agenix";
};
})
cfg.jails;
};
environment.etc = lib.attrsets.mergeAttrsList [
(lib.attrsets.mapAttrs' (
name: value: (lib.nameValuePair "fail2ban/filter.d/${name}.conf" {
text =
''
[Definition]
failregex = ${value.failRegex}
ignoreregex = ${value.ignoreRegex}
''
+ lib.optionalString (value.datePattern != "") ''
datepattern = ${value.datePattern}
''
+ lib.optionalString (value._groupsre != "") ''
_groupsre = ${value._groupsre}
'';
})
)
cfg.jails)
{
"fail2ban/action.d/cloudflare-token-agenix.conf".text = let
notes = "Fail2Ban on ${config.networking.hostName}";
cfapi = "https://api.cloudflare.com/client/v4/zones/${cfg.zoneId}/firewall/access_rules/rules";
in ''
[Definition]
actionstart =
actionstop =
actioncheck =
actionunban = id=$(curl -s -X GET "${cfapi}" \
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
| jq -r '.result[] | select(.notes == "${notes}" and .configuration.target == "ip" and .configuration.value == "<ip>") | .id')
if [ -z "$id" ]; then echo "id for <ip> cannot be found"; exit 0; fi; \
curl -s -X DELETE "${cfapi}/$id" \
-H @${cfg.apiKeyFile} -H "Content-Type: application/json" \
--data '{"cascade": "none"}'
actionban = curl -X POST "${cfapi}" -H @${cfg.apiKeyFile} -H "Content-Type: application/json" --data '{"mode":"block","configuration":{"target":"ip","value":"<ip>"},"notes":"${notes}"}'
[Init]
name = cloudflare-token-agenix
'';
}
];
};
}

View File

@@ -3,27 +3,24 @@
config, config,
self, self,
... ...
}: }: let
let
unit = "keepalived"; unit = "keepalived";
cfg = config.server.${unit}; cfg = config.server.infra.${unit};
hostCfg = hostCfg = hostname:
hostname: if hostname == "sobotka"
if hostname == "sobotka" then then {
{
ip = "192.168.88.14"; ip = "192.168.88.14";
priority = 20; priority = 20;
state = "MASTER"; state = "MASTER";
} }
else if hostname == "ziggy" then else if hostname == "ziggy"
{ then {
ip = "192.168.88.12"; ip = "192.168.88.12";
priority = 10; priority = 10;
state = "BACKUP"; state = "BACKUP";
} }
else else throw "No keepalived config defined for host ${hostname}";
throw "No keepalived config defined for host ${hostname}";
_self = hostCfg config.networking.hostName; _self = hostCfg config.networking.hostName;
@@ -34,9 +31,8 @@ let
# Remove self from peers # Remove self from peers
peers = builtins.filter (ip: ip != _self.ip) allPeers; peers = builtins.filter (ip: ip != _self.ip) allPeers;
in in {
{ options.server.infra.${unit} = {
options.server.${unit} = {
enable = lib.mkEnableOption { enable = lib.mkEnableOption {
description = "Enable ${unit}"; description = "Enable ${unit}";
}; };

View File

@@ -0,0 +1,6 @@
---
filenames:
- /var/log/traefik/access.log
poll_without_inotify: true
labels:
type: traefik

View File

@@ -1,18 +1,11 @@
{ {
config, config,
lib, lib,
pkgs, self,
... ...
}: let }: let
srv = config.server; infra = config.server.infra;
cfg = config.server.podman; cfg = config.server.services;
piholeUrl =
if config.networking.hostName == "sobotka"
then "pihole0"
else if config.networking.hostName == "ziggy"
then "pihole1"
else throw "Unknown hostname";
getPiholeSecret = hostname: getPiholeSecret = hostname:
if hostname == "ziggy" if hostname == "ziggy"
@@ -21,106 +14,16 @@
then [config.age.secrets.pihole.path] then [config.age.secrets.pihole.path]
else throw "Unknown hostname: ${hostname}"; else throw "Unknown hostname: ${hostname}";
in { in {
options.server.podman = { options.server.infra = {
enable = lib.mkEnableOption "Enables Podman"; podman.enable = lib.mkEnableOption "Enables Podman";
gluetun.enable = lib.mkEnableOption "Enables gluetun"; gluetun.enable = lib.mkEnableOption "Enables gluetun";
qbittorrent = {
enable = lib.mkEnableOption "Enable qBittorrent";
url = lib.mkOption {
type = lib.types.str;
default = "qbt.${srv.domain}";
};
port = lib.mkOption {
type = lib.types.int;
default = 8080;
description = "The port to host qBittorrent on.";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "qBittorrent";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Torrent client";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "qbittorrent.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Downloads";
}; };
config = lib.mkIf infra.podman.enable {
age.secrets = {
pihole.file = "${self}/secrets/${config.networking.hostName}Pihole.age";
slskd.file = "${self}/secrets/slskd.age";
}; };
slskd = {
enable = lib.mkEnableOption "Enable Soulseek";
url = lib.mkOption {
type = lib.types.str;
default = "slskd.${srv.domain}";
};
port = lib.mkOption {
type = lib.types.int;
default = 5030;
description = "The port to host Soulseek webui on.";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "slskd";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Web-based Soulseek client";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "slskd.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Downloads";
};
};
pihole = {
enable = lib.mkEnableOption {
description = "Enable";
};
port = lib.mkOption {
type = lib.types.int;
default = 8053;
description = "The port to host PiHole on.";
};
url = lib.mkOption {
type = lib.types.str;
default = "${piholeUrl}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "PiHole";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Adblocking and DNS service";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "pi-hole.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
homepage.path = lib.mkOption {
type = lib.types.str;
default = "/admin";
description = "Optional path suffix for homepage links (e.g. /admin).";
};
};
};
config = lib.mkIf cfg.enable {
virtualisation = { virtualisation = {
containers.enable = true; containers.enable = true;
podman.enable = true; podman.enable = true;
@@ -137,37 +40,8 @@ in {
]; ];
}; };
services.caddy.virtualHosts = lib.mkMerge [
(lib.mkIf cfg.qbittorrent.enable {
"${cfg.qbittorrent.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString cfg.qbittorrent.port}
'';
};
})
(lib.mkIf cfg.slskd.enable {
"${cfg.slskd.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString cfg.slskd.port}
'';
};
})
(lib.mkIf cfg.pihole.enable {
"${cfg.pihole.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString cfg.pihole.port}
'';
};
})
];
virtualisation.oci-containers.containers = lib.mkMerge [ virtualisation.oci-containers.containers = lib.mkMerge [
(lib.mkIf cfg.gluetun.enable { (lib.mkIf infra.gluetun.enable {
gluetun = { gluetun = {
image = "qmcgaw/gluetun"; image = "qmcgaw/gluetun";
ports = [ ports = [
@@ -260,7 +134,7 @@ in {
(lib.mkIf cfg.pihole.enable { (lib.mkIf cfg.pihole.enable {
pihole = { pihole = {
autoStart = true; autoStart = true;
image = "pihole/pihole:latest"; image = "pihole/pihole:2025.08.0";
volumes = [ volumes = [
"/var/lib/pihole:/etc/pihole/" "/var/lib/pihole:/etc/pihole/"
"/var/lib/dnsmasq.d:/etc/dnsmasq.d/" "/var/lib/dnsmasq.d:/etc/dnsmasq.d/"
@@ -268,9 +142,6 @@ in {
environment = { environment = {
TZ = "Europe/Stockholm"; TZ = "Europe/Stockholm";
CUSTOM_CACHE_SIZE = "0"; CUSTOM_CACHE_SIZE = "0";
# PIHOLE_DNS_ = "10.88.0.1#5335";
# DNSSEC = "false";
# REV_SERVER = "true";
WEBTHEME = "default-darker"; WEBTHEME = "default-darker";
}; };
environmentFiles = getPiholeSecret config.networking.hostName; environmentFiles = getPiholeSecret config.networking.hostName;
@@ -286,6 +157,38 @@ in {
]; ];
}; };
}) })
(lib.mkIf cfg.ollama.enable {
intel-llm = {
autoStart = true;
image = "intelanalytics/ipex-llm-inference-cpp-xpu:latest";
devices = [
"/dev/dri:/dev/dri:rwm"
];
volumes = [
"/var/lib/ollama:/models"
];
environment = {
OLLAMA_ORIGINS = "http://192.168.*";
SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS = "1";
ONEAPI_DEVICE_SELECTOR = "level_zero:0";
OLLAMA_HOST = "[::]:11434";
no_proxy = "localhost,127.0.0.1";
DEVICE = "Arc";
OLLAMA_NUM_GPU = "999";
ZES_ENABLE_SYSMAN = "1";
};
cmd = [
"/bin/sh"
"-c"
"/llm/scripts/start-ollama.sh && echo 'Startup script finished, container is now idling.' && sleep infinity"
];
extraOptions = [
"--net=host"
"--memory=32G"
"--shm-size=16g"
];
};
})
]; ];
}; };
} }

View File

@@ -7,10 +7,10 @@
}: let }: let
inherit (lib) types mkOption; inherit (lib) types mkOption;
cfg = config.server.postgresql; cfg = config.server.infra.postgresql;
in { in {
options = { options = {
server.postgresql = { server.infra.postgresql = {
upgradeTargetPackage = mkOption { upgradeTargetPackage = mkOption {
type = types.nullOr types.package; type = types.nullOr types.package;
default = null; default = null;

View File

@@ -7,7 +7,7 @@
}: let }: let
inherit (lib) types mkOption; inherit (lib) types mkOption;
cfg = config.server.postgresql; cfg = config.server.infra.postgresql;
database = {name, ...}: { database = {name, ...}: {
options = { options = {
@@ -31,7 +31,7 @@
}; };
in { in {
options = { options = {
server.postgresql = { server.infra.postgresql = {
databases = mkOption { databases = mkOption {
type = types.listOf (types.submodule database); type = types.listOf (types.submodule database);
default = []; default = [];

View File

@@ -0,0 +1,26 @@
{
config,
lib,
self,
...
}:
with lib; let
cfg = config.server.infra.tailscale;
in {
options.server.infra.tailscale = {
enable = mkEnableOption "Enable tailscale server configuration";
};
config = mkIf cfg.enable {
age.secrets.sobotkaTsAuth.file = "${self}/secrets/sobotkaTsAuth.age";
services.tailscale = {
enable = true;
openFirewall = true;
useRoutingFeatures = "server";
authKeyFile = config.age.secrets.sobotkaTsAuth.path;
extraSetFlags = [
"--advertise-exit-node"
];
};
};
}

View File

@@ -0,0 +1,183 @@
{
lib,
clib,
config,
pkgs,
self,
...
}: let
inherit (lib) mkEnableOption mkIf types;
cfg = config.server.infra.traefik;
srv = config.server;
generateRouters = services: config:
lib.mapAttrs' (
name: service:
lib.nameValuePair name {
entryPoints = ["websecure"];
# FIX 3: Use backticks for the Host rule and interpolation
rule = "Host(`${clib.server.mkFullDomain config service}`)";
service = name;
tls.certResolver = "letsencrypt";
}
) (lib.filterAttrs (_: s: s.enable) services);
generateServices = services:
lib.mapAttrs' (name: service:
lib.nameValuePair name {
loadBalancer.servers = [{url = "http://localhost:${toString service.port}";}];
}) (lib.filterAttrs (name: service: service.enable) services);
getCloudflareCredentials = hostname:
if hostname == "ziggy"
then config.age.secrets.cloudflareDnsCredentialsZiggy.path
else if hostname == "sobotka"
then config.age.secrets.cloudflareDnsCredentials.path
else throw "Unknown hostname: ${hostname}";
in {
options.server.infra.traefik = {
enable = mkEnableOption "Enable global Traefik reverse proxy with ACME";
};
config = mkIf cfg.enable {
age.secrets = {
traefikEnv = {
file = "${self}/secrets/traefikEnv.age";
mode = "640";
owner = "traefik";
group = "traefik";
};
crowdsecApi.file = "${self}/secrets/crowdsecApi.age";
};
systemd.services.traefik = {
serviceConfig = {
EnvironmentFile = [config.age.secrets.traefikEnv.path];
};
};
networking.firewall.allowedTCPPorts = [80 443];
services = {
tailscale.permitCertUid = "traefik";
traefik = {
enable = true;
staticConfigOptions = {
log = {
level = "DEBUG";
};
accesslog = {filepath = "/var/lib/traefik/logs/access.log";};
tracing = {};
api = {
dashboard = true;
insecure = false;
};
certificatesResolvers = {
vpn.tailscale = {};
letsencrypt = {
acme = {
email = "adam@cnst.dev";
storage = "/var/lib/traefik/cert.json";
dnsChallenge = {
provider = "cloudflare";
resolvers = [
"1.1.1.1:53"
"1.0.0.1:53"
];
};
};
};
};
entryPoints = {
# redis = {
# address = "0.0.0.0:6381";
# };
# postgres = {
# address = "0.0.0.0:5433";
# };
web = {
address = ":80";
forwardedHeaders.insecure = true;
http.redirections.entryPoint = {
to = "websecure";
scheme = "https";
permanent = true;
};
# http.middlewares = "crowdsec@file";
};
websecure = {
address = ":443";
forwardedHeaders.insecure = true;
http.tls = {
certResolver = "letsencrypt";
domains = [
{
main = "cnix.dev";
sans = ["*.cnix.dev"];
}
{
main = "ts.cnst.dev";
sans = ["*ts.cnst.dev"];
}
];
};
# http.middlewares = "crowdsec@file";
};
experimental = {
address = ":1111";
forwardedHeaders.insecure = true;
};
};
experimental = {
# Install the Crowdsec Bouncer plugin
plugins = {
#enabled = "true";
bouncer = {
moduleName = "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin";
version = "v1.4.5";
};
};
};
};
dynamicConfigOptions = {
http = {
services = generateServices srv.services;
routers =
(generateRouters srv.services config)
// {
api = {
entryPoints = ["websecure"];
rule = "Host(`traefik.${srv.domain}`)";
service = "api@internal";
tls.certResolver = "letsencrypt";
};
};
# middlewares = {
# crowdsec = {
# plugin = {
# bouncer = {
# enabled = "true";
# logLevel = "DEBUG";
# crowdsecLapiKeyFile = config.age.secrets.crowdsecApi.path;
# crowdsecMode = "live";
# crowdsecLapiHost = ":4223";
# };
# };
# };
# };
};
};
};
};
};
}

View File

@@ -5,7 +5,20 @@
... ...
}: let }: let
unit = "unbound"; unit = "unbound";
cfg = config.server.${unit}; cfg = config.server.infra.${unit};
srv = config.server;
svcNames = lib.attrNames srv.services;
localARecords = builtins.concatLists (map (
name: let
s = srv.services.${name};
in
if s != null && s.enable && s.subdomain != null
then [''"${s.subdomain}.${srv.domain}. A ${srv.ip}"'']
else []
)
svcNames);
hostIp = hostname: hostIp = hostname:
if hostname == "ziggy" if hostname == "ziggy"
@@ -14,11 +27,12 @@
then "192.168.88.14" then "192.168.88.14"
else throw "No IP defined for host ${hostname}"; else throw "No IP defined for host ${hostname}";
in { in {
options.server.${unit} = { options.server.infra.${unit} = {
enable = lib.mkEnableOption { enable = lib.mkEnableOption {
description = "Enable ${unit}"; description = "Enable ${unit}";
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
services = { services = {
# resolved.enable = lib.mkForce false; # resolved.enable = lib.mkForce false;
@@ -97,6 +111,11 @@ in {
"255.255.255.255/32" "255.255.255.255/32"
"2001:db8::/32" "2001:db8::/32"
]; ];
local-data =
[
''"traefik.${config.settings.accounts.domains.local}. A 192.168.88.14"''
]
++ localARecords;
}; };
}; };
}; };

View File

@@ -0,0 +1,135 @@
{
lib,
config,
self,
...
}: let
inherit (lib) mkIf mkEnableOption mkOption types;
cfg = config.server.infra.www;
in {
options.server.infra.www = {
enable = mkEnableOption {
description = "Enable personal website";
};
url = mkOption {
default = "";
type = types.str;
description = ''
Public domain name to be used to access the server services via Traefik reverse proxy
'';
};
port = lib.mkOption {
type = lib.types.int;
default = 8283;
description = "The port to host webservice on.";
};
cloudflared = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
};
config = mkIf cfg.enable {
age.secrets = {
wwwCloudflared.file = "${self}/secrets/wwwCloudflared.age";
};
server.infra = {
fail2ban = {
jails = {
nginx-404 = {
serviceName = "nginx";
failRegex = ''^.*\[error\].*directory index of.* is forbidden.*client: <HOST>.*$'';
ignoreRegex = '''';
maxRetry = 5;
};
};
};
};
services = {
nginx = {
enable = true;
defaultListen = [
{
addr = "127.0.0.1";
port = 8283;
}
];
virtualHosts."webfinger" = {
forceSSL = false;
serverName = cfg.url;
root = "/var/www/webfinger";
locations."= /.well-known/webfinger" = {
root = "/var/www/webfinger";
extraConfig = ''
default_type application/jrd+json;
try_files /.well-known/webfinger =404;
'';
};
locations."= /robots.txt" = {
root = "/var/www/webfinger";
extraConfig = ''
default_type text/plain;
try_files /robots.txt =404;
'';
};
};
};
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://127.0.0.1:8283";
};
};
};
environment.etc = {
"webfinger/.well-known/webfinger".text = ''
{
"subject": "acct:adam@${cfg.url}",
"links": [
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": "https://auth.${cfg.url}/application/o/tailscale/"
}
]
}
'';
"webfinger/robots.txt".text = ''
User-agent: *
Disallow: /
'';
};
services.traefik.dynamicConfigOptions.http = {
routers.webfinger = {
entryPoints = ["websecure"];
rule = "Host(`${cfg.url}`) && Path(`/.well-known/webfinger`)";
service = "webfinger";
tls.certResolver = "letsencrypt";
};
services.webfinger.loadBalancer.servers = [
{url = "http://127.0.0.1:8283";}
];
};
};
}

View File

@@ -1,58 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
service = "jellyfin";
cfg = config.server.${service};
srv = config.server;
in
{
options.server.${service} = {
enable = lib.mkEnableOption {
description = "Enable ${service}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${service}";
};
url = lib.mkOption {
type = lib.types.str;
default = "jellyfin.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Jellyfin";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "The Free Software Media System";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "jellyfin.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Media";
};
};
config = lib.mkIf cfg.enable {
services.${service} = {
enable = true;
user = srv.user;
group = srv.group;
};
environment.systemPackages = with pkgs; [
jellyfin-ffmpeg
];
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:8096
'';
};
};
}

View File

@@ -1,53 +0,0 @@
{
config,
lib,
...
}:
let
service = "jellyseerr";
srv = config.server;
cfg = config.server.${service};
in
{
options.server.${service} = {
enable = lib.mkEnableOption {
description = "Enable ${service}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${service}.${srv.domain}";
};
port = lib.mkOption {
type = lib.types.port;
default = 5055;
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Jellyseerr";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Media request and discovery manager";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "jellyseerr.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Arr";
};
};
config = lib.mkIf cfg.enable {
services.${service} = {
enable = true;
port = cfg.port;
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:${toString cfg.port}
'';
};
};
}

View File

@@ -1,100 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
unit = "keycloak";
cfg = config.server.${unit};
srv = config.server;
in {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "login.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Keycloak";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Open Source Identity and Access Management";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "keycloak.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
dbPasswordFile = lib.mkOption {
type = lib.types.path;
};
cloudflared = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
};
config = lib.mkIf cfg.enable {
server.postgresql.databases = [
{
database = "keycloak";
}
];
services.cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://127.0.0.1:${
toString config.services.${unit}.settings.http-port
}";
};
};
environment.systemPackages = [
pkgs.keycloak
];
services.${unit} = {
enable = true;
initialAdminPassword = "pwpwpw";
database = {
type = "postgresql";
host = "127.0.0.1";
port = 5432;
name = "keycloak";
username = "keycloak";
passwordFile = cfg.dbPasswordFile;
useSSL = false;
};
settings = {
spi-theme-static-max-age = "-1";
spi-theme-cache-themes = false;
spi-theme-cache-templates = false;
http-port = 8821;
hostname = cfg.url;
hostname-strict = false;
hostname-strict-https = false;
proxy-headers = "xforwarded";
http-enabled = true;
};
};
};
}

View File

@@ -1,54 +0,0 @@
{
config,
lib,
...
}:
let
unit = "lidarr";
srv = config.server;
cfg = config.server.${unit};
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${unit}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Lidarr";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Music collection manager";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "lidarr.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Arr";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:8686
'';
};
};
}

View File

@@ -1,154 +0,0 @@
{
config,
pkgs,
lib,
...
}: let
unit = "ocis";
cfg = config.server.${unit};
srv = config.server;
in {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
adminUser = lib.mkOption {
type = lib.types.str;
default = "cnst";
};
adminPass = lib.mkOption {
type = lib.types.path;
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "cloud.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "OCIS";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "A safe home for all your data";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "owncloud.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
cloudflared = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
};
config = lib.mkIf cfg.enable {
server = {
postgresql.databases = [
{
database = "ocis";
}
];
fail2ban = lib.mkIf config.server.fail2ban.enable {
jails = {
nextcloud = {
serviceName = "phpfm-nextcloud";
failRegex = "^.*Login failed:.*(Remote IP: <HOST>).*$";
};
};
};
};
systemd.services.ocis.preStart = ''
${lib.getExe pkgs.ocis} init || true
'';
services = {
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://${config.services.ocis.address}:${toString config.services.ocis.port}";
};
};
${unit} = {
enable = true;
url = "https://${cfg.url}";
environment = let
cspFormat = pkgs.formats.yaml {};
cspConfig = {
directives = {
child-src = ["'self'"];
connect-src = [
"'self'"
"blob:"
"https://${srv.keycloak.url}"
];
default-src = ["'none'"];
font-src = ["'self'"];
frame-ancestors = ["'none'"];
frame-src = [
"'self'"
"blob:"
"https://embed.diagrams.net"
];
img-src = [
"'self'"
"data:"
"blob:"
];
manifest-src = ["'self'"];
media-src = ["'self'"];
object-src = [
"'self'"
"blob:"
];
script-src = [
"'self'"
"'unsafe-inline'"
];
style-src = [
"'self'"
"'unsafe-inline'"
];
};
};
in {
PROXY_AUTOPROVISION_ACCOUNTS = "true";
PROXY_ROLE_ASSIGNMENT_DRIVER = "oidc";
OCIS_OIDC_ISSUER = "https://${srv.keycloak.url}/realms/OpenCloud";
PROXY_OIDC_REWRITE_WELLKNOWN = "true";
WEB_OIDC_CLIENT_ID = "ocis";
OCIS_LOG_LEVEL = "error";
PROXY_TLS = "false";
PROXY_USER_OIDC_CLAIM = "preferred_username";
PROXY_USER_CS3_CLAIM = "username";
OCIS_ADMIN_USER_ID = "";
OCIS_INSECURE = "false";
OCIS_EXCLUDE_RUN_SERVICES = "idp";
GRAPH_ASSIGN_DEFAULT_USER_ROLE = "false";
PROXY_CSP_CONFIG_FILE_LOCATION = toString (cspFormat.generate "csp.yaml" cspConfig);
GRAPH_USERNAME_MATCH = "none";
PROXY_ROLE_ASSIGNMENT_ENABLED = "true";
PROXY_ROLE_ASSIGNMENT_OIDC_CLAIM = "realm_access.roles";
PROXY_ROLE_ASSIGNMENT_MAPPING = "ocisAdmin:admin,ocisUser:user";
};
};
};
};
}

180
modules/server/options.nix Normal file
View File

@@ -0,0 +1,180 @@
{
lib,
config,
...
}: let
inherit (lib) mkOption types;
ifTheyExist = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
cfg = config.server;
in {
options.server = {
enable = lib.mkEnableOption "The server services and configuration variables";
email = mkOption {
default = "";
type = types.str;
description = ''
Email name to be used to access the server services via Caddy reverse proxy
'';
};
domain = mkOption {
default = "";
type = types.str;
description = ''
Domain name to be used to access the server services via Caddy reverse proxy
'';
};
ip = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "The local IP of the service.";
};
user = lib.mkOption {
default = "share";
type = lib.types.str;
description = ''
User to run the server services as
'';
};
group = lib.mkOption {
default = "share";
type = lib.types.str;
description = ''
Group to run the server services as
'';
};
uid = lib.mkOption {
default = 1000;
type = lib.types.int;
description = ''
UID to run the server services as
'';
};
gid = lib.mkOption {
default = 1000;
type = lib.types.int;
description = ''
GID to run the server services as
'';
};
timeZone = lib.mkOption {
default = "Europe/Stockholm";
type = lib.types.str;
description = ''
Time zone to be used for the server services
'';
};
services = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
options = {
enable = lib.mkEnableOption "the service";
subdomain = lib.mkOption {
type = lib.types.str;
default = "";
description = "The subdomain for the service (e.g., 'jellyfin')";
};
exposure = lib.mkOption {
type = lib.types.enum ["local" "tunnel" "tailscale"];
default = "local";
description = "Controls where the service is exposed";
};
port = lib.mkOption {
type = lib.types.int;
default = 80;
description = "The port to host service on.";
};
configDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/${name}";
description = "Configuration directory for ${name}.";
};
cloudflared = lib.mkOption {
type = lib.types.submodule {
options = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret","TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
};
description = "Cloudflare tunnel configuration for this service.";
};
homepage = lib.mkOption {
type = lib.types.submodule {
options = {
name = lib.mkOption {
type = lib.types.str;
default = "";
description = "Display name on the homepage.";
};
description = lib.mkOption {
type = lib.types.str;
default = "";
description = "A short description for the homepage tile.";
};
icon = lib.mkOption {
type = lib.types.str;
default = "Zervices c00l stuff";
description = "Icon file name for the homepage tile.";
};
category = lib.mkOption {
type = lib.types.str;
default = "";
description = "Homepage category grouping.";
};
path = lib.mkOption {
type = lib.types.str;
default = "";
example = "/admin";
description = "Optional path suffix for homepage links (e.g. /admin).";
};
};
};
description = "Homepage metadata for this service.";
};
};
}));
};
};
config = lib.mkIf cfg.enable {
users = {
groups.${cfg.group} = {
gid = cfg.gid;
};
users.${cfg.user} = {
uid = cfg.uid;
isSystemUser = true;
group = cfg.group;
extraGroups = ifTheyExist [
"audio"
"video"
"docker"
"libvirtd"
"qemu-libvirtd"
"rtkit"
"fail2ban"
"vaultwarden"
"qbittorrent"
"lidarr"
"prowlarr"
"bazarr"
"sonarr"
"radarr"
"media"
"share"
"render"
"input"
"authentik"
"traefik"
];
};
};
};
}

View File

@@ -1,66 +0,0 @@
{
config,
lib,
...
}:
let
unit = "prowlarr";
srv = config.server;
cfg = config.server.${unit};
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${unit}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Prowlarr";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "PVR indexer";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "prowlarr.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Arr";
};
};
config = lib.mkIf cfg.enable {
services = {
${unit} = {
enable = true;
};
flaresolverr = {
enable = true;
};
caddy = {
virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:9696
'';
};
virtualHosts."flaresolverr.${srv.domain}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:8191
'';
};
};
};
};
}

View File

@@ -1,54 +0,0 @@
{
config,
lib,
...
}:
let
unit = "radarr";
srv = config.server;
cfg = config.server.${unit};
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${unit}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Radarr";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Film collection manager";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "radarr.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Arr";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:7878
'';
};
};
}

View File

@@ -0,0 +1,17 @@
{
config,
lib,
...
}: let
unit = "bazarr";
srv = config.server;
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
};
}

View File

@@ -0,0 +1,19 @@
{
imports = [
./bazarr
./flaresolverr
./gitea
./homepage-dashboard
./jellyfin
./jellyseerr
./lidarr
./n8n
./nextcloud
./ollama
./prowlarr
./radarr
./sonarr
./uptime-kuma
./vaultwarden
];
}

View File

@@ -0,0 +1,16 @@
{
config,
lib,
...
}: let
unit = "flaresolverr";
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services = {
${unit} = {
enable = true;
};
};
};
}

View File

@@ -0,0 +1,94 @@
{
config,
lib,
self,
...
}: let
unit = "gitea";
cfg = config.server.services.${unit};
domain = "${cfg.subdomain}.${config.server.infra.www.url}";
in {
config = lib.mkIf cfg.enable {
age.secrets.giteaCloudflared.file = "${self}/secrets/giteaCloudflared.age";
server.infra = {
fail2ban.jails.${unit} = {
serviceName = "${unit}";
failRegex = ''.*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>'';
};
postgresql.databases = [
{database = "gitea";}
];
};
services = {
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${domain}".service = "http://localhost:${toString cfg.port}";
};
};
gitea = {
enable = true;
appName = "cnix code forge";
database = {
type = "postgres";
socket = "/run/postgresql";
name = "gitea";
user = "gitea";
createDatabase = false;
};
lfs.enable = true;
settings = {
cors = {
ENABLED = true;
SCHEME = "https";
ALLOW_DOMAIN = domain;
};
log.MODE = "console";
mailer = {
ENABLED = false;
MAILER_TYPE = "sendmail";
FROM = "noreply+adam@cnst.dev";
SENDMAIL_PATH = "/run/wrappers/bin/sendmail";
};
picture.DISABLE_GRAVATAR = true;
repository = {
DEFAULT_BRANCH = "main";
DEFAULT_REPO_UNITS = "repo.code,repo.issues,repo.pulls";
DISABLE_DOWNLOAD_SOURCE_ARCHIVES = true;
};
indexer.REPO_INDEXER_ENABLED = true;
oauth2_client = {
ENABLE_AUTO_REGISTRATION = true;
ACCOUNT_LINKING = "auto";
};
server = {
DOMAIN = domain;
LANDING_PAGE = "explore";
HTTP_PORT = cfg.port;
ROOT_URL = "https://${domain}/";
};
security.DISABLE_GIT_HOOKS = false;
service.DISABLE_REGISTRATION = true;
session.COOKIE_SECURE = true;
};
};
};
};
}

View File

@@ -0,0 +1,227 @@
{
config,
lib,
self,
clib,
...
}: let
unit = "homepage-dashboard";
cfg = config.server.services.${unit};
srv = config.server;
in {
config = lib.mkIf cfg.enable {
age.secrets = {
homepageEnvironment = {
file = "${self}/secrets/homepageEnvironment.age";
};
};
services = {
glances.enable = true;
${unit} = {
enable = true;
environmentFile = config.age.secrets.homepageEnvironment.path;
settings = {
color = "stone";
theme = "dark";
headerStyle = "clean";
statusStyle = "dot";
hideVersion = true;
useEqualHeights = true;
layout = [
{
Glances = {
header = false;
style = "row";
columns = 4;
};
}
{
Arr = {
header = true;
style = "column";
};
}
{
Downloads = {
header = true;
style = "column";
};
}
{
Media = {
header = true;
style = "column";
};
}
{
Services = {
header = true;
style = "column";
};
}
];
};
widgets = [
{
openmeteo = {
label = "Kalmar";
timezone = "Europe/Stockholm";
units = "metric";
cache = 5;
latitude = 56.707262;
longitude = 16.324541;
};
}
{
resources = {
label = "SYSTEM";
memory = true;
cpu = true;
uptime = false;
};
}
];
services = let
homepageCategories = [
"Arr"
"Media"
"Downloads"
"Services"
];
allServices = srv.services;
getDomain = s: clib.server.mkHostDomain config s;
homepageServicesFor = category:
lib.filterAttrs
(
name: value:
name
!= unit
&& value ? homepage
&& value.homepage.category == category
)
allServices;
in
lib.lists.forEach homepageCategories (cat: {
"${cat}" =
lib.lists.forEach
(lib.attrsets.mapAttrsToList (name: _value: name) (homepageServicesFor cat))
(x: let
service = allServices.${x};
domain = getDomain service;
in {
"${service.homepage.name}" = {
icon = service.homepage.icon;
description = service.homepage.description;
href = "https://${service.subdomain}.${domain}${service.homepage.path or ""}";
siteMonitor = "https://${service.subdomain}.${domain}${x.homepage.path or ""}";
};
});
})
++ [
{
Glances = let
glancesShared = {
type = "glances";
url = "http://localhost:${toString config.services.glances.port}";
chart = true;
version = 4;
};
in [
{
Memory = {
widget =
glancesShared
// {
metric = "memory";
refreshInterval = 2000;
pointsLimit = 30;
};
};
}
{
"CPU Usage" = {
widget =
glancesShared
// {
metric = "cpu";
refreshInterval = 2000;
pointsLimit = 30;
};
};
}
{
"CPU Temp" = {
widget =
glancesShared
// {
metric = "sensor:Tctl";
refreshInterval = 5000;
pointsLimit = 20;
};
};
}
{
"GPU Radeon" = {
widget =
glancesShared
// {
metric = "sensor:junction";
};
};
}
{
"GPU Intel" = {
widget =
glancesShared
// {
metric = "sensor:pkg";
};
};
}
{
"ZFS Pool" = {
widget =
glancesShared
// {
metric = "fs:/mnt/data";
refreshInterval = 30000;
pointsLimit = 20;
diskUnits = "bytes";
};
};
}
{
Processes = {
widget =
glancesShared
// {
metric = "process";
};
};
}
{
Network = {
widget =
glancesShared
// {
metric = "network:enp6s0";
};
};
}
];
}
];
};
};
};
}

View File

@@ -0,0 +1,21 @@
{
config,
lib,
pkgs,
...
}: let
unit = "jellyfin";
cfg = config.server.services.${unit};
srv = config.server;
in {
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
environment.systemPackages = with pkgs; [
jellyfin-ffmpeg
];
};
}

View File

@@ -0,0 +1,15 @@
{
config,
lib,
...
}: let
unit = "jellyseerr";
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
port = cfg.port;
};
};
}

View File

@@ -0,0 +1,17 @@
{
config,
lib,
...
}: let
unit = "lidarr";
srv = config.server;
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
};
}

View File

@@ -0,0 +1,17 @@
{
config,
lib,
...
}: let
unit = "n8n";
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services = {
n8n = {
enable = true;
openFirewall = true;
};
};
};
}

View File

@@ -0,0 +1,101 @@
{
config,
pkgs,
lib,
self,
...
}: let
unit = "nextcloud";
cfg = config.server.services.${unit};
srv = config.server;
in {
config = lib.mkIf cfg.enable {
age.secrets = {
nextcloudAdminPass.file = "${self}/secrets/nextcloudAdminPass.age";
nextcloudCloudflared.file = "${self}/secrets/nextcloudCloudflared.age";
};
server.infra.fail2ban.jails.nextcloud = {
serviceName = "${unit}";
_groupsre = ''(?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)'';
failRegex = ''
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Two-factor challenge failed:
^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error.
'';
datePattern = '',?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"'';
};
services = {
${unit} = {
enable = true;
package = pkgs.nextcloud32;
hostName = "nextcloud";
configureRedis = true;
caching = {
redis = true;
};
phpOptions = {
"opcache.interned_strings_buffer" = "32";
};
maxUploadSize = "50G";
settings = {
maintenance_window_start = "1";
trusted_proxies = [
"127.0.0.1"
"::1"
];
trusted_domains = ["cloud.${srv.domain}"];
overwriteprotocol = "https";
enabledPreviewProviders = [
"OC\\Preview\\BMP"
"OC\\Preview\\GIF"
"OC\\Preview\\JPEG"
"OC\\Preview\\Krita"
"OC\\Preview\\MarkDown"
"OC\\Preview\\MP3"
"OC\\Preview\\OpenDocument"
"OC\\Preview\\PNG"
"OC\\Preview\\TXT"
"OC\\Preview\\XBitmap"
"OC\\Preview\\HEIC"
];
};
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "/run/postgresql";
dbname = "nextcloud";
adminuser = "cnst";
adminpassFile = config.age.secrets.nextcloudAdminPass.path;
};
};
nginx = {
defaultListen = [
{
addr = "127.0.0.1";
port = 8182;
}
{
addr = "127.0.0.1";
port = 8482;
}
];
virtualHosts.nextcloud = {
forceSSL = false;
};
};
};
server.infra.postgresql.databases = [
{
database = "nextcloud";
}
];
systemd.services."nextcloud-setup" = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
};
}

View File

@@ -0,0 +1,28 @@
{
config,
lib,
pkgs,
...
}: let
unit = "ollama";
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
environment.systemPackages = with pkgs; [
ollama
intel-compute-runtime
intel-graphics-compiler
level-zero
];
services.open-webui = {
enable = true;
host = "0.0.0.0";
port = 8001;
environment = {
ANONYMIZED_TELEMETRY = "False";
BYPASS_MODEL_ACCESS_CONTROL = "True";
OLLAMA_BASE_URL = "http://localhost:11434";
};
};
};
}

View File

@@ -0,0 +1,16 @@
{
config,
lib,
...
}: let
unit = "prowlarr";
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services = {
${unit} = {
enable = true;
};
};
};
}

View File

@@ -0,0 +1,17 @@
{
config,
lib,
...
}: let
unit = "radarr";
srv = config.server;
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
};
}

View File

@@ -0,0 +1,17 @@
{
config,
lib,
...
}: let
unit = "sonarr";
srv = config.server;
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
};
}

View File

@@ -0,0 +1,16 @@
{
config,
lib,
...
}: let
unit = "uptime-kuma";
cfg = config.server.services.${unit};
in {
config = lib.mkIf cfg.enable {
services = {
${unit} = {
enable = true;
};
};
};
}

View File

@@ -0,0 +1,59 @@
# from @fufexan & @notthebee
{
config,
lib,
self,
...
}: let
unit = "vaultwarden";
cfg = config.server.services.${unit};
domain = "${cfg.subdomain}.${config.server.infra.www.url}";
in {
config = lib.mkIf cfg.enable {
age.secrets = {
vaultwardenCloudflared.file = "${self}/secrets/vaultwardenCloudflared.age";
vaultwardenEnvironment.file = "${self}/secrets/vaultwardenEnvironment.age";
};
server.infra.fail2ban.jails.${unit} = {
serviceName = "${unit}";
failRegex = ''^.*?Username or password is incorrect\. Try again\. IP: <ADDR>\. Username:.*$'';
};
services = {
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${domain}".service = "http://localhost:${toString cfg.port}";
};
};
vaultwarden = {
enable = true;
environmentFile = config.age.secrets.vaultwardenEnvironment.path;
backupDir = "/var/backup/vaultwarden";
config = {
DOMAIN = "https://${domain}";
SIGNUPS_ALLOWED = false;
ROCKET_ADDRESS = "127.0.0.1";
ROCKET_PORT = cfg.port;
IP_HEADER = "CF-Connecting-IP";
logLevel = "warn";
extendedLogging = true;
useSyslog = true;
invitationsAllowed = true;
showPasswordHint = false;
};
};
};
systemd.services.backup-vaultwarden.serviceConfig = {
User = "root";
Group = "root";
};
};
}

View File

@@ -1,54 +0,0 @@
{
config,
lib,
...
}:
let
unit = "sonarr";
srv = config.server;
cfg = config.server.${unit};
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${unit}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Sonarr";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Series collection manager";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "sonarr.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Arr";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
user = srv.user;
group = srv.group;
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:8989
'';
};
};
}

View File

@@ -1,62 +0,0 @@
{
config,
lib,
...
}: let
unit = "syncthing";
srv = config.server;
cfg = config.server.${unit};
in {
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
url = lib.mkOption {
type = lib.types.str;
default = "${unit}.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Syncthing";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Continuous file synchronization program";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "syncthing.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
};
config = lib.mkIf cfg.enable {
networking.firewall = {
allowedTCPPorts = [
8384
22000
];
allowedUDPPorts = [
22000
21027
];
};
services.${unit} = {
enable = true;
user = srv.user;
guiAddress = "0.0.0.0:8384";
overrideFolders = false;
overrideDevices = false;
dataDir = "/home/${srv.user}/syncthing";
configDir = "/home/${srv.user}/syncthing/.config/syncthing";
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:8384
'';
};
};
}

View File

@@ -1,52 +0,0 @@
{
config,
lib,
...
}:
let
unit = "uptime-kuma";
cfg = config.server.${unit};
srv = config.server;
in
{
options.server.${unit} = {
enable = lib.mkEnableOption {
description = "Enable ${unit}";
};
configDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/uptime-kuma";
};
url = lib.mkOption {
type = lib.types.str;
default = "uptime.${srv.domain}";
};
homepage.name = lib.mkOption {
type = lib.types.str;
default = "Uptime Kuma";
};
homepage.description = lib.mkOption {
type = lib.types.str;
default = "Service monitoring tool";
};
homepage.icon = lib.mkOption {
type = lib.types.str;
default = "uptime-kuma.svg";
};
homepage.category = lib.mkOption {
type = lib.types.str;
default = "Services";
};
};
config = lib.mkIf cfg.enable {
services.${unit} = {
enable = true;
};
services.caddy.virtualHosts."${cfg.url}" = {
useACMEHost = srv.domain;
extraConfig = ''
reverse_proxy http://127.0.0.1:3001
'';
};
};
}

View File

@@ -1,85 +0,0 @@
# from @fufexan & @notthebee
{
config,
lib,
...
}:
let
inherit (lib) mkIf mkEnableOption;
vcfg = config.services.vaultwarden.config;
cfg = config.server.vaultwarden;
in
{
options = {
server.vaultwarden = {
enable = mkEnableOption "Enables vaultwarden";
url = lib.mkOption {
type = lib.types.str;
default = "${cfg.domain}";
};
cloudflared = {
credentialsFile = lib.mkOption {
type = lib.types.str;
example = lib.literalExpression ''
pkgs.writeText "cloudflare-credentials.json" '''
{"AccountTag":"secret"."TunnelSecret":"secret","TunnelID":"secret"}
'''
'';
};
tunnelId = lib.mkOption {
type = lib.types.str;
example = "00000000-0000-0000-0000-000000000000";
};
};
};
};
config = mkIf cfg.enable {
server = {
fail2ban = lib.mkIf config.server.fail2ban.enable {
jails = {
vaultwarden = {
serviceName = "vaultwarden";
failRegex = "^.*Username or password is incorrect. Try again. IP: <HOST>. Username: <F-USER>.*</F-USER>.$";
};
};
};
};
systemd.services.backup-vaultwarden.serviceConfig = {
User = "root";
Group = "root";
};
services = {
vaultwarden = {
enable = true;
environmentFile = config.age.secrets.vaultwardenEnvironment.path;
backupDir = "/var/backup/vaultwarden";
config = {
DOMAIN = "https://${cfg.url}";
SIGNUPS_ALLOWED = false;
ROCKET_ADDRESS = "127.0.0.1";
ROCKET_PORT = 8222;
IP_HEADER = "CF-Connecting-IP";
logLevel = "warn";
extendedLogging = true;
useSyslog = true;
invitationsAllowed = false;
showPasswordHint = false;
};
};
cloudflared = {
enable = true;
tunnels.${cfg.cloudflared.tunnelId} = {
credentialsFile = cfg.cloudflared.credentialsFile;
default = "http_status:404";
ingress."${cfg.url}".service = "http://${vcfg.ROCKET_ADDRESS}:${toString vcfg.ROCKET_PORT}";
};
};
};
};
}

View File

@@ -2,8 +2,7 @@
lib, lib,
config, config,
... ...
}: }: let
let
inherit (lib) mkOption types; inherit (lib) mkOption types;
sshKeys = { sshKeys = {
@@ -16,14 +15,14 @@ let
keyName = config.settings.accounts.sshUser or null; keyName = config.settings.accounts.sshUser or null;
selectedKey = selectedKey =
if keyName != null then if keyName != null
then
lib.attrByPath [ lib.attrByPath [
keyName keyName
] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'") sshKeys ] (builtins.abort "No SSH key defined for hostname/key '${toString keyName}'")
else sshKeys
builtins.abort "No accounts.sshUser provided, cannot select SSH key."; else builtins.abort "No accounts.sshUser provided, cannot select SSH key.";
in in {
{
options.settings.accounts = { options.settings.accounts = {
username = mkOption { username = mkOption {
type = types.str; type = types.str;
@@ -46,5 +45,21 @@ in
default = null; default = null;
description = "Optional override for selecting an SSH key by name"; description = "Optional override for selecting an SSH key by name";
}; };
domains = lib.mkOption {
type = lib.types.submodule {
options = {
local = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "The local domain of the host";
};
public = lib.mkOption {
type = lib.types.str;
default = "example.com";
description = "The public domain of the host";
};
};
};
};
}; };
} }

View File

@@ -21,8 +21,8 @@ in
example = 1080; example = 1080;
}; };
refreshRate = mkOption { refreshRate = mkOption {
type = types.int; type = types.str;
default = 60; default = "60";
}; };
transform = mkOption { transform = mkOption {
type = types.int; type = types.int;

View File

@@ -4,5 +4,8 @@
allowUnfree = true; allowUnfree = true;
input-fonts.acceptLicense = true; input-fonts.acceptLicense = true;
}; };
overlays = [
];
}; };
} }

Some files were not shown because too many files have changed in this diff Show More