update: system update & refactor

# Breaking Changes
- sops location movod to "system/dev/<dev-name>/sops/sops-conf.nix"
- flake devices declaration changes
- whole flake update
This commit is contained in:
danny 2025-10-14 16:49:03 +08:00
parent 321f740af0
commit 6a71b601f5
116 changed files with 2576 additions and 3634 deletions

View file

@ -5,20 +5,21 @@ keys:
- &skydrive_lap age1ar5h06qv72pduau043r04kschwcq0x0lm33wqvxzdh9grmp3cq3sy0ngnz
creation_rules:
- path_regex: system/dev/dn-server/secret.yaml
- path_regex: system/dev/dn-server/sops/secret.yaml
key_groups:
- age:
- *dn_server
- *dn_pre7780
- path_regex: system/dev/dn-pre7780/secret.yaml
- path_regex: system/dev/dn-pre7780/sops/secret.yaml
key_groups:
- age:
- *dn_pre7780
- path_regex: system/dev/dn-lap/secret.yaml
- path_regex: system/dev/dn-lap/sops/secret.yaml
key_groups:
- age:
- *dn_server
- *dn_lap
- path_regex: system/dev/skydrive-lap/secret.yaml
- path_regex: system/dev/skydrive-lap/sops/secret.yaml
key_groups:
- age:
- *skydrive_lap

716
flake.lock generated

File diff suppressed because it is too large Load diff

478
flake.nix
View file

@ -1,9 +1,13 @@
{
description = "DACHXY NixOS with hyprland";
description = "DACHXY's NixOS with hyprland";
inputs = {
nixpkgs-stable = {
url = "github:nixos/nixpkgs/nixos-25.05";
};
nixpkgs = {
url = "github:nixos/nixpkgs/nixos-unstable";
url = "github:nixos/nixpkgs/nixpkgs-unstable";
};
firefox = {
@ -68,10 +72,12 @@
nix-minecraft = {
url = "github:Infinidoge/nix-minecraft";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-tmodloader = {
url = "github:andOrlando/nix-tmodloader";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = {
@ -85,6 +91,7 @@
swww = {
url = "github:LGFae/swww";
inputs.nixpkgs.follows = "nixpkgs";
};
zen-browser = {
@ -132,416 +139,117 @@
attic = {
url = "github:zhaofengli/attic";
inputs.nixpkgs.follows = "nixpkgs";
};
kaiu-font = {
url = "https://files.net.dn/kaiu.ttf";
flake = false;
inputs.nixpkgs.follows = "nixpkgs-stable";
};
actual-budget-server = {
url = "github:dachxy/actual-budget-flake";
inputs.nixpkgs.follows = "nixpkgs";
};
mail-server = {
url = "github:dachxy/nix-mail-server";
inputs.nixpkgs.follows = "nixpkgs";
};
nix-search-tv.url = "github:3timeslazy/nix-search-tv";
};
outputs =
{
self,
nixpkgs,
nix-index-database,
lanzaboote,
home-manager,
nixpkgs-stable,
...
}@inputs:
let
system = "x86_64-linux";
nix-version = "25.05";
inherit (builtins) mapAttrs;
hosts = {
dn-pre7780 = {
system = "x86_64-linux";
path = ./system/dev/dn-pre7780;
};
dn-server = {
system = "x86_64-linux";
path = ./system/dev/dn-server;
};
dn-lap = {
system = "x86_64-linux";
path = ./system/dev/dn-lap;
};
skydrive-lap = {
system = "x86_64-linux";
path = ./system/dev/skydrive-lap;
};
};
in
{
# ==== NixOS Configuration ==== #
nixosConfigurations = mapAttrs (
hostname: conf:
let
inherit (conf) path system;
pkgs = import nixpkgs {
inherit system;
};
inherit (pkgs) lib;
helper = import ./helper { inherit pkgs lib; };
# Declare COMMON modules here
common-settings = {
pkgs-stable = import nixpkgs-stable {
inherit system;
};
helper = import ./helper {
inherit
pkgs
;
lib = pkgs.lib;
};
in
nixpkgs.lib.nixosSystem {
specialArgs = {
inherit (conf) system;
inherit
helper
inputs
self
pkgs-stable
;
};
modules = [
home-manager.nixosModules.default
nix-index-database.nixosModules.nix-index
# ==== Common Configuration ==== #
{
nixpkgs.hostPlatform = system;
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = [
inputs.mail-server.overlay
inputs.nix-minecraft.overlay
inputs.nix-tmodloader.overlay
]
++ (import ./pkgs/overlays);
}
# ==== Common Modules ==== #
inputs.home-manager.nixosModules.default
inputs.nix-index-database.nixosModules.nix-index
inputs.disko.nixosModules.disko
inputs.sops-nix.nixosModules.sops
inputs.nix-minecraft.nixosModules.minecraft-servers
inputs.nix-tmodloader.nixosModules.tmodloader
inputs.chaotic.nixosModules.default
inputs.actual-budget-api.nixosModules.default
inputs.stylix.nixosModules.stylix
inputs.attic.nixosModules.atticd
];
args = {
inherit
helper
inputs
system
nix-version
self
;
};
};
inputs.mail-server.nixosModules.default
./options
# Declaring All Devices
devices = {
# Home Computer
dn-pre7780 = {
hostname = "dn-pre7780";
domain = "net.dn";
username = "danny";
extra-modules = [
lanzaboote.nixosModules.lanzaboote
./system/dev/dn-pre7780
# VM
inputs.microvm.nixosModules.host
{
networking.useNetworkd = true;
systemd.network.enable = true;
systemd.network.networks."10-lan" = {
matchConfig.Name = [
"enp0s31f6"
"vm-*"
];
networkConfig = {
Bridge = "br0";
};
};
systemd.network.netdevs."br0" = {
netdevConfig = {
Name = "br0";
Kind = "bridge";
};
};
systemd.network.networks."10-lan-bridge" = {
matchConfig.Name = "br0";
networkConfig = {
Address = [ "192.168.0.5/24" ];
Gateway = "192.168.0.1";
DNS = [ "192.168.0.1" ];
};
linkConfig.RequiredForOnline = "routable";
};
microvm.vms = {
vm-1 = {
flake = self;
updateFlake = "git+file:///etc/nixos";
autostart = false;
};
vm-2 = {
flake = self;
updateFlake = "git+file:///etc/nixos";
autostart = false;
};
};
}
];
overlays = [ ];
};
# Laptop
dn-lap = {
hostname = "dn-lap";
username = "danny";
domain = "net.dn";
extra-modules = [
lanzaboote.nixosModules.lanzaboote
./system/dev/dn-lap
];
overlays = [
];
};
# Server
dn-server = {
hostname = "dn-server";
username = "danny";
domain = "net.dn";
extra-modules = [
inputs.nix-minecraft.nixosModules.minecraft-servers
inputs.nix-tmodloader.nixosModules.tmodloader
./system/dev/dn-server
./pkgs/options/dovecot.nix
];
overlays = [
inputs.nix-minecraft.overlay
inputs.nix-tmodloader.overlay
(import ./pkgs/overlays/dovecot.nix)
];
};
# Skydrive
skydrive-lap = {
hostname = "skydrive-lap";
username = "skydrive";
domain = "sky.dn";
extra-modules = [
inputs.nix-minecraft.nixosModules.minecraft-servers
inputs.nix-tmodloader.nixosModules.tmodloader
inputs.disko.nixosModules.disko
./system/dev/skydrive-lap
];
overlays = [
inputs.nix-minecraft.overlay
inputs.nix-tmodloader.overlay
];
};
};
in
{
nixosConfigurations =
(builtins.mapAttrs (
dev: conf:
let
domain = if conf.domain != null then conf.domain else "local";
inherit (conf) username hostname;
in
nixpkgs.lib.nixosSystem {
modules = [
{
environment.systemPackages = [
inputs.attic.packages.${system}.attic
];
system.stateVersion = nix-version;
home-manager = {
backupFileExtension = "backup-hm";
useUserPackages = true;
useGlobalPkgs = true;
extraSpecialArgs = {
inherit
helper
inputs
system
nix-version
devices
username
;
};
users."${username}" = lib.mkIf (!((conf ? isVM) && (conf.isVM))) {
imports = [
inputs.hyprland.homeManagerModules.default
inputs.caelestia-shell.homeManagerModules.default
inputs.zen-browser.homeManagerModules.${system}.default
inputs.nvf.homeManagerModules.default
{
home = {
homeDirectory = "/home/${username}";
stateVersion = nix-version;
};
# Let Home Manager install and manage itself.
programs.home-manager.enable = true;
}
];
};
};
networking = {
inherit domain;
hostName = hostname;
};
nixpkgs.hostPlatform = system;
nixpkgs.config.allowUnfree = true;
nixpkgs.overlays = (import ./pkgs/overlays) ++ conf.overlays;
}
]
++ common-settings.modules
++ conf.extra-modules;
specialArgs = {
inherit username;
}
// common-settings.args;
}
) devices)
//
# VM For k8s
(
let
vmList =
let
kubeMasterIP = "192.168.0.6";
kubeMasterHostname = "api.kube";
kubeMasterAPIServerPort = 6443;
kubeApi = "https://${kubeMasterHostname}:${toString kubeMasterAPIServerPort}";
in
{
# master
vm-1 = {
ip = "192.168.0.6";
mac = "02:00:00:00:00:01";
extraConfig = {
networking.extraHosts = "${kubeMasterIP} ${kubeMasterHostname}";
environment.systemPackages = with pkgs; [
kompose
kubectl
kubernetes
];
services.kubernetes = {
roles = [
"master"
"node"
];
masterAddress = kubeMasterHostname;
apiserverAddress = kubeApi;
easyCerts = true;
apiserver = {
securePort = kubeMasterAPIServerPort;
advertiseAddress = kubeMasterIP;
};
addons.dns.enable = true;
};
systemd.services.link-kube-config = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.writeShellScript "link-kube-config.sh" ''
target="/etc/kubernetes/cluster-admin.kubeconfig"
if [ -e "$target" ]; then
[ ! -d "/root/.kube" ] && mkdir -p "/root/.kube"
ln -sf $target /root/.kube/config
fi
''}";
};
};
};
};
# Node
vm-2 = {
ip = "192.168.0.7";
mac = "02:00:00:00:00:02";
extraConfig = {
networking.extraHosts = "${kubeMasterIP} ${kubeMasterHostname}";
environment.systemPackages = with pkgs; [
kompose
kubectl
kubernetes
];
services.kubernetes = {
roles = [ "node" ];
masterAddress = kubeMasterHostname;
easyCerts = true;
kubelet.kubeconfig.server = kubeApi;
apiserverAddress = kubeApi;
addons.dns.enable = true;
};
};
};
};
mkMicrovm = name: value: {
hypervisor = "qemu";
vcpu = 4;
mem = 8192;
interfaces = [
{
type = "tap";
id = "${name}";
mac = value.mac;
}
];
shares = [
{
tag = "ro-store";
source = "/nix/store";
mountPoint = "/nix/.ro-store";
}
];
};
in
lib.mapAttrs' (
name: value:
lib.nameValuePair name (
nixpkgs.lib.nixosSystem {
inherit system;
modules = [
inputs.microvm.nixosModules.microvm
value.extraConfig
{
microvm = mkMicrovm name value;
system.stateVersion = lib.trivial.release;
networking.hostName = name;
networking.domain = "kube";
networking.firewall.enable = false;
users.users.root.password = "";
services.getty.autologinUser = "root";
programs.fish.enable = true;
programs.bash = {
shellInit = ''
if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]]
then
shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=""
exec ${pkgs.fish}/bin/fish $LOGIN_OPTION
fi
'';
};
systemd.network.enable = true;
systemd.network.networks."20-lan" = {
matchConfig.Type = "ether";
networkConfig = {
Address = [ "${value.ip}/24" ];
Gateway = "192.168.0.1";
DNS = [ "192.168.0.1" ];
DHCP = "no";
};
};
systemd.services.br-netfilter = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "/run/current-system/sw/bin/modprobe br_netfilter";
};
};
environment.systemPackages = with pkgs; [
dig.dnsutils
openssl
fishPlugins.done
fishPlugins.fzf-fish
fishPlugins.forgit
fishPlugins.hydro
fzf
fishPlugins.grc
grc
git
# ==== Private Configuration ==== #
(import path { inherit hostname; })
];
}
];
}
)
) vmList
)
// {
vps = nixpkgs.lib.nixosSystem {
inherit system;
specialArgs = common-settings.args;
modules = [
inputs.disko.nixosModules.disko
./system/dev/generic
];
};
};
) hosts;
packages."${system}" = {
vm-1 = self.nixosConfigurations.vm-1.config.microvm.declaredRunner;
vm-2 = self.nixosConfigurations.vm-2.config.microvm.declaredRunner;
};
# ==== MicroVM Packages ==== #
# packages."${system}" = {
# vm-1 = self.nixosConfigurations.vm-1.config.microvm.declaredRunner;
# vm-2 = self.nixosConfigurations.vm-2.config.microvm.declaredRunner;
# };
};
}

View file

@ -34,7 +34,7 @@ in
systemctl --user start "$SERVICE_NAME"
notify-send ${
optionalString (notify-icon != "") "-i ${notify-icon}"
}"${icon} ''\${SERVICE_NAME^}" "starting"
} "${icon} ''\${SERVICE_NAME^}" "starting"
fi
esac
@ -48,4 +48,47 @@ in
jq -nc --argjson a "$json1" --argjson b "$EXTRA_JSON" '$a + $b'
'';
grafana = {
mkDashboard =
{
name,
src,
templateList,
conf ? { },
}:
let
template = toJSON templateList;
in
pkgs.stdenvNoCC.mkDerivation (
{
inherit src;
pname = "${name}-grafana-dashboard-srouce";
version = "1.0";
dontBuild = true;
nativeBuildInputs = with pkgs; [ jq ];
installPhase = ''
PROM_TEMPLATE='${template}'
OUTPUT_PATH="$out"
mkdir -p $out
if [ -f "$src" ]; then
echo "adding template filename: $(basename $src)"
jq --argjson TEMPLATE "$PROM_TEMPLATE" '.templating.list += $TEMPLATE' \
"$src" > "$OUTPUT_PATH/$(basename $src)"
else
find . -name "*.json" | while read DASHBOARD_FILE; do
echo "adding template filename: $DASHBOARD_FILE"
jq --argjson TEMPLATE "$PROM_TEMPLATE" '
.templating.list += $TEMPLATE
' "$DASHBOARD_FILE" > "$OUTPUT_PATH/$DASHBOARD_FILE"
done
fi
'';
}
// conf
);
};
}

View file

@ -1,14 +1,15 @@
{ mainMod }:
{
mainMod,
osConfig,
config,
nvidia-offload-enabled,
lib,
pkgs,
monitors ? [ ],
...
}:
with builtins;
let
inherit (lib) optionalString;
inherit (osConfig.systemConf.hyprland) monitors;
nvidia-offload-enabled = osConfig.hardware.nvidia.prime.offload.enableOffloadCmd;
notransTag = "notrans";
@ -41,7 +42,8 @@ let
in
toString (if (monitorsNum == 0) then 1 else monitorsNum);
in
[
{
wayland.windowManager.hyprland.settings.bind = [
''${mainMod}, F, exec, ${browser}''
''${mainMod}, RETURN, exec, ${terminal}''
''CTRL ALT, T, exec, ${terminal}''
@ -106,8 +108,8 @@ in
''${mainMod}, G, workspace, ${toString gamingWorkspace}''
''${mainMod} SHIFT, G, movetoworkspace, ${toString gamingWorkspace}''
]
++ (
]
++ (
# workspaces
# binds $mainMod + [shift +] {1..9} to [move to] workspace {1..9}
builtins.concatLists (
@ -122,4 +124,5 @@ in
]
) 9
)
)
);
}

View file

@ -1,4 +1,6 @@
{ ... }:
{
wayland.windowManager.hyprland.settings = {
input = {
kb_layout = "us";
@ -28,8 +30,8 @@
no_hardware_cursors = true;
};
gestures = {
workspace_swipe = true;
workspace_swipe_fingers = 3;
gesture = [
"3, horizontal, workspace"
];
};
}

View file

@ -1,5 +1,6 @@
{ lib }:
{ lib, ... }:
{
wayland.windowManager.hyprland.settings = {
xwayland = {
force_zero_scaling = true;
};
@ -66,12 +67,8 @@
new_on_top = true;
};
gestures = {
workspace_swipe = true;
workspace_swipe_cancel_ratio = 0.15;
};
misc = {
force_default_wallpaper = 0;
};
};
}

View file

@ -1,10 +1,11 @@
{ ... }:
let
inherit (builtins) map concatLists;
top = "60";
right = "100%-w-10";
notransTag = "notrans";
in
{
wayland.windowManager.hyprland.settings = {
windowrule = [
"pseudo, class:(org.fcitx.)"
"float, class:file_progress"
@ -83,21 +84,17 @@ in
"animation slide top 20%, class: ^(blueberry.py)$"
# Steam
"workspace: 7 silent, class: ^(steam)$"
"workspace: unset, class: ^(steam)$, floating: 1"
"workspace 7 silent, class: ^(steam)$"
"workspace unset, class: ^(steam)$, floating: 1"
# steam game
"workspace: 7 silent, class: ^(steam_app_)(.*)"
# Line
"workspace: 2, initialTitle: ^(LINE)$"
"float, initialTitle: ^(LINE)$"
"workspace 7 silent, class: ^(steam_app_)(.*)"
# VLC
"workspace: 3, initialClass: ^(vlc), floating: 0"
"workspace 3, initialClass: ^(vlc), floating: 0"
# discord
"workspace: 4 silent, initialClass: ^(discord), floating: 0"
"workspace 4 silent, initialClass: ^(discord), floating: 0"
# Davinci resolve
"center 1, initialClass: ^(resolve), floating: 1"
@ -122,4 +119,5 @@ in
"ignorealpha 0.1, swaync-control-center"
"ignorealpha 0.1, swaync-notification-window"
];
};
}

View file

@ -1,5 +1,6 @@
{ monitors }:
{ osConfig, ... }:
let
inherit (osConfig.systemConf.hyprland) monitors;
inherit (builtins)
length
genList
@ -14,7 +15,9 @@ let
currentNum = index - (monitorNum * (index / monitorNum));
default = if index < monitorNum then "true" else "false";
in
"${toString (index + 1)}, monitor:${elemAt monitors currentNum}, default:${default}"
"${toString (index + 1)}, monitor:desc:${(elemAt monitors currentNum).desc}, default:${default}"
) workspaceNum;
in
if (monitorNum > 0) then workspaceList else [ ]
{
wayland.windowManager.hyprland.settings.workspace = if (monitorNum > 0) then workspaceList else [ ];
}

View file

@ -1,16 +1,13 @@
{
monitors ? [ ],
}:
{
pkgs,
lib,
config,
inputs,
system,
osConfig,
...
}:
let
inherit (osConfig.systemConf.hyprland) monitors;
terminal = "ghostty";
execOnceScript = pkgs.writeShellScript "hyprlandExecOnce" ''
@ -40,6 +37,14 @@ in
sunsetr
];
imports = [
(import ./hypr/bind.nix { inherit mainMod; })
./hypr/workspace.nix
./hypr/window.nix
./hypr/windowrule.nix
./hypr/input.nix
];
wayland.windowManager.hyprland = {
enable = true;
xwayland.enable = true;
@ -60,22 +65,12 @@ in
settings = {
"$mainMod" = mainMod;
debug = {
disable_logs = true;
};
bind = (
import ./hypr/bind.nix {
inherit
mainMod
pkgs
monitors
config
lib
;
nvidia-offload-enabled = osConfig.hardware.nvidia.prime.offload.enableOffloadCmd;
}
);
ecosystem.no_update_news = true;
bindm = [
# Move/resize windows with mainMod + LMB/RMB and dragging
@ -102,7 +97,8 @@ in
monitor = [
", prefered, 0x0, 1"
];
]
++ (map (x: "desc:${x.desc},${x.props}") osConfig.systemConf.hyprland.monitors);
plugin = {
hyprwinrap = {
@ -128,16 +124,12 @@ in
''GDK_PIXBUF_MODULE_FILE, ${pkgs.librsvg}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache''
];
workspace = (import ./hypr/workspace.nix { inherit monitors; });
misc = {
disable_hyprland_logo = true;
force_default_wallpaper = 0;
disable_splash_rendering = true;
};
}
// (import ./hypr/window.nix { inherit lib; })
// (import ./hypr/windowrule.nix)
// (import ./hypr/input.nix);
};
};
# === Swww === #
@ -161,7 +153,8 @@ in
let
font = "CaskaydiaCove Nerd Font";
font2 = "SF Pro Display Bold";
mainMonitor = if ((builtins.length monitors) > 0) then builtins.elemAt monitors 0 else "";
mainMonitor =
if ((builtins.length monitors) > 0) then "desc:${(builtins.elemAt monitors 0).desc}" else "";
in
{
background = {
@ -270,7 +263,6 @@ in
valign = "center";
}
];
};
};
@ -546,10 +538,10 @@ in
# === rofi === #
programs.rofi = {
enable = true;
package = pkgs.rofi-wayland;
package = pkgs.rofi;
plugins = with pkgs; [
rofi-emoji-wayland
(rofi-calc.override { rofi-unwrapped = rofi-wayland-unwrapped; })
rofi-emoji
rofi-calc
];
};

5
options/default.nix Normal file
View file

@ -0,0 +1,5 @@
{
imports = [
./systemconf.nix
];
}

129
options/systemconf.nix Normal file
View file

@ -0,0 +1,129 @@
{
inputs,
system,
config,
helper,
lib,
...
}:
let
inherit (lib)
mkOption
mkEnableOption
types
mkIf
optionals
;
stateVersion = "25.05";
cfg = config.systemConf;
monitorType =
with types;
submodule {
options = {
desc = mkOption {
type = str;
description = "Hyprland monitor description";
example = "ASUSTek COMPUTER INC ASUS VG32VQ1B 0x00002271";
};
output = mkOption {
type = str;
description = "Hyprland monitor output";
example = "DP-6";
};
props = mkOption {
type = str;
description = "Hyprland monitor properties";
default = "prefered, 0x0, 1";
example = "2560x1440@180, -1440x-600, 1, transform, 1";
};
};
};
in
{
options.systemConf = {
hostname = mkOption {
type = types.str;
description = "Hostname for system";
};
domain = mkOption {
type = types.str;
default = "local";
description = ''Domain for system'';
};
username = mkOption {
type = types.str;
description = "Main username";
};
hyprland = {
enable = (mkEnableOption "Enable hyprland") // {
default = false;
};
monitors = mkOption {
type = with types; listOf monitorType;
default = [ ];
example = [
{
desc = "ASUSTek COMPUTER INC ASUS VG32VQ1B 0x00002271";
output = "DP-6";
props = "2560x1440@165, 0x0, 1";
}
];
description = "Monitors used for hyprland and waybar";
};
};
enableHomeManager = (mkEnableOption "Home manager") // {
default = true;
};
nvidia = {
enable = true;
};
};
config = {
# ==== System ==== #
networking = {
inherit (cfg) domain;
hostName = cfg.hostname;
};
environment.systemPackages = [
inputs.attic.packages.${system}.attic
];
system.stateVersion = stateVersion;
# ==== Home Manager ==== #
home-manager = mkIf cfg.enableHomeManager {
backupFileExtension = "backup-hm";
useUserPackages = true;
useGlobalPkgs = true;
extraSpecialArgs = {
inherit helper inputs system;
inherit (cfg) username;
};
users."${cfg.username}" = {
imports = [
inputs.hyprland.homeManagerModules.default
inputs.caelestia-shell.homeManagerModules.default
inputs.zen-browser.homeManagerModules.${system}.default
inputs.nvf.homeManagerModules.default
{
home = {
homeDirectory = "/home/${cfg.username}";
stateVersion = stateVersion;
};
programs.home-manager.enable = true;
}
]
++ (optionals cfg.hyprland.enable [
../home/user/hyprland.nix
]);
};
};
};
}

View file

@ -1,868 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
attrValues
concatMapStringsSep
concatStrings
concatStringsSep
flatten
imap1
literalExpression
mapAttrsToList
mkEnableOption
mkIf
mkOption
optional
optionalAttrs
optionalString
singleton
types
nameValuePair
mapAttrs'
listToAttrs
filter
;
inherit (lib.strings) match hasPrefix;
cfg = config.services.dovecot;
dovecotPkg = pkgs.dovecot;
pversion = dovecotPkg.version;
isVersion24 = hasPrefix "2.4" pversion;
baseDir = "/run/dovecot";
stateDir = "/var/lib/dovecot";
sieveScriptSettings = mapAttrs' (
to: _: nameValuePair "sieve_${to}" "${stateDir}/sieve/${to}"
) cfg.sieve.scripts;
imapSieveMailboxSettings = listToAttrs (
flatten (
imap1 (
idx: el:
singleton {
name = "imapsieve_mailbox${toString idx}_name";
value = el.name;
}
++ optional (el.from != null) {
name = "imapsieve_mailbox${toString idx}_from";
value = el.from;
}
++ optional (el.causes != [ ]) {
name = "imapsieve_mailbox${toString idx}_causes";
value = concatStringsSep "," el.causes;
}
++ optional (el.before != null) {
name = "imapsieve_mailbox${toString idx}_before";
value = "file:${stateDir}/imapsieve/before/${baseNameOf el.before}";
}
++ optional (el.after != null) {
name = "imapsieve_mailbox${toString idx}_after";
value = "file:${stateDir}/imapsieve/after/${baseNameOf el.after}";
}
) cfg.imapsieve.mailbox
)
);
mkExtraConfigCollisionWarning = term: ''
You referred to ${term} in `services.dovecot.extraConfig`.
Due to gradual transition to structured configuration for plugin configuration, it is possible
this will cause your plugin configuration to be ignored.
Consider setting `services.dovecot.pluginSettings.${term}` instead.
'';
# Those settings are automatically set based on other parts
# of this module.
automaticallySetPluginSettings = [
"sieve_plugins"
"sieve_extensions"
"sieve_global_extensions"
"sieve_pipe_bin_dir"
]
++ (builtins.attrNames sieveScriptSettings)
++ (builtins.attrNames imapSieveMailboxSettings);
# The idea is to match everything that looks like `$term =`
# but not `# $term something something`
# or `# $term = some value` because those are comments.
configContainsSetting = lines: term: (match "[[:blank:]]*${term}[[:blank:]]*=.*" lines) != null;
warnAboutExtraConfigCollisions = map mkExtraConfigCollisionWarning (
filter (configContainsSetting cfg.extraConfig) automaticallySetPluginSettings
);
sievePipeBinScriptDirectory = pkgs.linkFarm "sieve-pipe-bins" (
map (el: {
name = builtins.unsafeDiscardStringContext (baseNameOf el);
path = el;
}) cfg.sieve.pipeBins
);
dovecotConf = concatStrings [
(optionalString isVersion24 ''
dovecot_config_version = ${pversion}
dovecot_storage_version = ${pversion}
'')
''
base_dir = ${baseDir}
protocols = ${(concatStringsSep " " cfg.protocols)}
sendmail_path = /run/wrappers/bin/sendmail
mail_plugin_dir = /run/current-system/sw/lib/dovecot/modules
# defining mail_plugins must be done before the first protocol {} filter because of https://doc.dovecot.org/configuration_manual/config_file/config_file_syntax/#variable-expansion
mail_plugins = ${concatStringsSep " " cfg.mailPlugins.globally.enable}
''
(concatStringsSep "\n" (
mapAttrsToList (protocol: plugins: ''
protocol ${protocol} {
mail_plugins = $mail_plugins ${concatStringsSep " " plugins.enable}
}
'') cfg.mailPlugins.perProtocol
))
(
if cfg.sslServerCert == null then
''
ssl = no
auth_allow_cleartext = yes
''
else
''
ssl_server_cert_file = ${cfg.sslServerCert}
ssl_server_key_file = ${cfg.sslServerKey}
${optionalString (cfg.sslCACert != null) ("ssl_server_ca_file = " + cfg.sslCACert)}
${optionalString cfg.enableDHE ''ssl_server_dh_file = ${config.security.dhparams.params.dovecot.path}''}
auth_allow_cleartext = no
''
)
''
default_internal_user = ${cfg.user}
default_internal_group = ${cfg.group}
${optionalString (cfg.mailUser != null) "mail_uid = ${cfg.mailUser}"}
${optionalString (cfg.mailGroup != null) "mail_gid = ${cfg.mailGroup}"}
mail_driver = maildir
mail_path = ${cfg.mailLocation}
mail_inbox_path = ${cfg.mailLocation}/.INBOX
maildir_copy_with_hardlinks = yes
${
if isVersion24 then
''
pop3_uidl_format = %{uidvalidity | hex(8)}%{user | hex(8)}
''
else
''
pop3_uidl_format = %08Xv%08Xu
''
}
auth_mechanisms = plain login
service auth {
user = root
}
''
(optionalString cfg.enablePAM ''
userdb passwd {
}
passdb pam {
session = yes
service_name = dovecot
${optionalString cfg.showPAMFailure "failure_show_msg=yes"}
}
'')
(optionalString (cfg.mailboxes != { }) ''
namespace inbox {
inbox=yes
${concatStringsSep "\n" (map mailboxConfig (attrValues cfg.mailboxes))}
}
'')
(optionalString cfg.enableQuota ''
service quota-status {
executable = ${dovecotPkg}/libexec/dovecot/quota-status -p postfix
inet_listener quota {
port ${cfg.quotaPort}
}
client_limit = 1
}
quota "User quota" {
driver = count
storage = {
size = ${cfg.quotaGlobalPerUser}
grace = 10M
}
status {
success = DUNNO
nouser = DUNNO
overquota = "552 5.2.2 Mailbox is full"
}
}
'')
# General plugin settings:
# - sieve is mostly generated here, refer to `pluginSettings` to follow
# the control flow.
''
${concatStringsSep "\n" (
mapAttrsToList (
key: value:
if (key == "sieve_extensions") then
''
${key} {
${value}
}
''
else
"${key} = ${value}"
) cfg.pluginSettings
)}
''
(optionalString cfg.enableHealthCheck (
let
healthCheckWrapper = pkgs.writeShellScript "health-check-wrapper.sh" ''
export PATH="${pkgs.coreutils}/bin:${pkgs.gnused}/bin:$PATH"
${pkgs.dovecot}/libexec/dovecot/health-check.sh
'';
in
''
service health-check {
executable = script -p ${healthCheckWrapper}
inet_listener health-check {
port = ${toString cfg.healthCheckPort}
}
}
''
))
cfg.extraConfig
];
mailboxConfig =
mailbox:
''
mailbox "${mailbox.name}" {
auto = ${toString mailbox.auto}
''
+ optionalString (mailbox.autoexpunge != null) ''
autoexpunge = ${mailbox.autoexpunge}
''
+ optionalString (mailbox.specialUse != null) ''
special_use = \${toString mailbox.specialUse}
''
+ "}";
mailboxes =
{ name, ... }:
{
options = {
name = mkOption {
type = types.strMatching ''[^"]+'';
example = "Spam";
default = name;
readOnly = true;
description = "The name of the mailbox.";
};
auto = mkOption {
type = types.enum [
"no"
"create"
"subscribe"
];
default = "no";
example = "subscribe";
description = "Whether to automatically create or create and subscribe to the mailbox or not.";
};
specialUse = mkOption {
type = types.nullOr (
types.enum [
"All"
"Archive"
"Drafts"
"Flagged"
"Junk"
"Sent"
"Trash"
]
);
default = null;
example = "Junk";
description = "Null if no special use flag is set. Other than that every use flag mentioned in the RFC is valid.";
};
autoexpunge = mkOption {
type = types.nullOr types.str;
default = null;
example = "60d";
description = ''
To automatically remove all email from the mailbox which is older than the
specified time.
'';
};
};
};
in
{
options.services.dovecot = {
enable = mkEnableOption "the dovecot POP3/IMAP server";
enablePop3 = mkEnableOption "starting the POP3 listener (when Dovecot is enabled)";
enableImap = mkEnableOption "starting the IMAP listener (when Dovecot is enabled)" // {
default = true;
};
enableLmtp = mkEnableOption "starting the LMTP listener (when Dovecot is enabled)";
enableHealthCheck = mkEnableOption "starting the HealthCheck listener (when Dovecot is enabled)";
healthCheckPort = mkOption {
type = types.int;
default = 5001;
description = "Listen port for health check service";
};
protocols = mkOption {
type = types.listOf types.str;
default = [ ];
description = "Additional listeners to start when Dovecot is enabled.";
};
user = mkOption {
type = types.str;
default = "dovecot";
description = "Dovecot user name.";
};
group = mkOption {
type = types.str;
default = "dovecot";
description = "Dovecot group name.";
};
extraConfig = mkOption {
type = types.lines;
default = "";
example = "mail_debug = yes";
description = "Additional entries to put verbatim into Dovecot's config file.";
};
mailPlugins =
let
plugins =
hint:
types.submodule {
options = {
enable = mkOption {
type = types.listOf types.str;
default = [ ];
description = "mail plugins to enable as a list of strings to append to the ${hint} `$mail_plugins` configuration variable";
};
};
};
in
mkOption {
type =
with types;
submodule {
options = {
globally = mkOption {
description = "Additional entries to add to the mail_plugins variable for all protocols";
type = plugins "top-level";
example = {
enable = [ "virtual" ];
};
default = {
enable = [ ];
};
};
perProtocol = mkOption {
description = "Additional entries to add to the mail_plugins variable, per protocol";
type = attrsOf (plugins "corresponding per-protocol");
default = { };
example = {
imap = [ "imap_acl" ];
};
};
};
};
description = "Additional entries to add to the mail_plugins variable, globally and per protocol";
example = {
globally.enable = [ "acl" ];
perProtocol.imap.enable = [ "imap_acl" ];
};
default = {
globally.enable = [ ];
perProtocol = { };
};
};
configFile = mkOption {
type = types.nullOr types.path;
default = null;
description = "Config file used for the whole dovecot configuration.";
apply = v: if v != null then v else pkgs.writeText "dovecot.conf" dovecotConf;
};
mailLocation = mkOption {
type = types.str;
default = "/var/spool/mail/%{user}"; # Same as inbox, as postfix
example = "~/mail";
description = ''
Location that dovecot will use for mail folders. Dovecot mail_location option.
'';
};
mailUser = mkOption {
type = types.nullOr types.str;
default = null;
description = "Default user to store mail for virtual users.";
};
mailGroup = mkOption {
type = types.nullOr types.str;
default = null;
description = "Default group to store mail for virtual users.";
};
createMailUser =
mkEnableOption ''
automatically creating the user
given in {option}`services.dovecot.user` and the group
given in {option}`services.dovecot.group`''
// {
default = true;
};
sslCACert = mkOption {
type = types.nullOr types.str;
default = null;
description = "Path to the server's CA certificate key.";
};
sslServerCert = mkOption {
type = types.nullOr types.str;
default = null;
description = "Path to the server's public key.";
};
sslServerKey = mkOption {
type = types.nullOr types.str;
default = null;
description = "Path to the server's private key.";
};
enablePAM = mkEnableOption "creating a own Dovecot PAM service and configure PAM user logins" // {
default = true;
};
enableDHE = mkEnableOption "ssl_dh and generation of primes for the key exchange" // {
default = true;
};
showPAMFailure = mkEnableOption "showing the PAM failure message on authentication error (useful for OTPW)";
mailboxes = mkOption {
type =
with types;
coercedTo (listOf unspecified) (
list:
listToAttrs (
map (entry: {
name = entry.name;
value = removeAttrs entry [ "name" ];
}) list
)
) (attrsOf (submodule mailboxes));
default = { };
example = literalExpression ''
{
Spam = { specialUse = "Junk"; auto = "create"; };
}
'';
description = "Configure mailboxes and auto create or subscribe them.";
};
enableQuota = mkEnableOption "the dovecot quota service";
quotaPort = mkOption {
type = types.str;
default = "12340";
description = ''
The Port the dovecot quota service binds to.
If using postfix, add check_policy_service inet:localhost:12340 to your smtpd_recipient_restrictions in your postfix config.
'';
};
quotaGlobalPerUser = mkOption {
type = types.str;
default = "100G";
example = "10G";
description = "Quota limit for the user in bytes. Supports suffixes b, k, M, G, T and %.";
};
pluginSettings = mkOption {
# types.str does not coerce from packages, like `sievePipeBinScriptDirectory`.
type = types.attrsOf (
types.oneOf [
types.str
types.package
]
);
default = { };
example = literalExpression ''
{
sieve = "file:~/sieve;active=~/.dovecot.sieve";
}
'';
description = ''
Plugin settings for dovecot in general, e.g. `sieve`, `sieve_default`, etc.
Some of the other knobs of this module will influence by default the plugin settings, but you
can still override any plugin settings.
If you override a plugin setting, its value is cleared and you have to copy over the defaults.
'';
};
imapsieve.mailbox = mkOption {
default = [ ];
description = "Configure Sieve filtering rules on IMAP actions";
type = types.listOf (
types.submodule (
{ config, ... }:
{
options = {
name = mkOption {
description = ''
This setting configures the name of a mailbox for which administrator scripts are configured.
The settings defined hereafter with matching sequence numbers apply to the mailbox named by this setting.
This setting supports wildcards with a syntax compatible with the IMAP LIST command, meaning that this setting can apply to multiple or even all ("*") mailboxes.
'';
example = "Junk";
type = types.str;
};
from = mkOption {
default = null;
description = ''
Only execute the administrator Sieve scripts for the mailbox configured with services.dovecot.imapsieve.mailbox.<name>.name when the message originates from the indicated mailbox.
This setting supports wildcards with a syntax compatible with the IMAP LIST command, meaning that this setting can apply to multiple or even all ("*") mailboxes.
'';
example = "*";
type = types.nullOr types.str;
};
causes = mkOption {
default = [ ];
description = ''
Only execute the administrator Sieve scripts for the mailbox configured with services.dovecot.imapsieve.mailbox.<name>.name when one of the listed IMAPSIEVE causes apply.
This has no effect on the user script, which is always executed no matter the cause.
'';
example = [
"COPY"
"APPEND"
];
type = types.listOf (
types.enum [
"APPEND"
"COPY"
"FLAG"
]
);
};
before = mkOption {
default = null;
description = ''
When an IMAP event of interest occurs, this sieve script is executed before any user script respectively.
This setting each specify the location of a single sieve script. The semantics of this setting is similar to sieve_before: the specified scripts form a sequence together with the user script in which the next script is only executed when an (implicit) keep action is executed.
'';
example = literalExpression "./report-spam.sieve";
type = types.nullOr types.path;
};
after = mkOption {
default = null;
description = ''
When an IMAP event of interest occurs, this sieve script is executed after any user script respectively.
This setting each specify the location of a single sieve script. The semantics of this setting is similar to sieve_after: the specified scripts form a sequence together with the user script in which the next script is only executed when an (implicit) keep action is executed.
'';
example = literalExpression "./report-spam.sieve";
type = types.nullOr types.path;
};
};
}
)
);
};
sieve = {
plugins = mkOption {
default = [ ];
example = [ "sieve_extprograms" ];
description = "Sieve plugins to load";
type = types.listOf types.str;
};
extensions = mkOption {
default = [ ];
description = "Sieve extensions for use in user scripts";
example = [
"notify"
"imapflags"
"vnd.dovecot.filter"
];
type = types.listOf types.str;
};
globalExtensions = mkOption {
default = [ ];
example = [ "vnd.dovecot.environment" ];
description = "Sieve extensions for use in global scripts";
type = types.listOf types.str;
};
scripts = mkOption {
type = types.attrsOf types.path;
default = { };
description = "Sieve scripts to be executed. Key is a sequence, e.g. 'before2', 'after' etc.";
};
pipeBins = mkOption {
default = [ ];
example = literalExpression ''
map lib.getExe [
(pkgs.writeShellScriptBin "learn-ham.sh" "exec ''${pkgs.rspamd}/bin/rspamc learn_ham")
(pkgs.writeShellScriptBin "learn-spam.sh" "exec ''${pkgs.rspamd}/bin/rspamc learn_spam")
]
'';
description = "Programs available for use by the vnd.dovecot.pipe extension";
type = types.listOf types.path;
};
};
};
config = mkIf cfg.enable {
security.pam.services.dovecot = mkIf cfg.enablePAM { };
security.dhparams = mkIf (cfg.sslServerCert != null && cfg.enableDHE) {
enable = true;
params.dovecot = { };
};
services.dovecot = {
protocols =
optional cfg.enableImap "imap" ++ optional cfg.enablePop3 "pop3" ++ optional cfg.enableLmtp "lmtp";
mailPlugins = mkIf cfg.enableQuota {
globally.enable = [ "quota" ];
perProtocol.imap.enable = [ "imap_quota" ];
};
sieve.plugins =
optional (cfg.imapsieve.mailbox != [ ]) "sieve_imapsieve"
++ optional (cfg.sieve.pipeBins != [ ]) "sieve_extprograms";
sieve.globalExtensions = optional (cfg.sieve.pipeBins != [ ]) "vnd.dovecot.pipe";
pluginSettings = lib.mapAttrs (n: lib.mkDefault) (
{
# sieve_plugins = concatStringsSep " " cfg.sieve.plugins;
# sieve_extensions = concatMapStrings (p: p + " = yes\n") cfg.sieve.extensions;
# sieve_global_extensions = concatStringsSep " " (map (el: "+${el}") cfg.sieve.globalExtensions);
# sieve_pipe_bin_dir = sievePipeBinScriptDirectory;
}
// sieveScriptSettings
// imapSieveMailboxSettings
);
};
users.users = {
dovenull = {
uid = config.ids.uids.dovenull2;
description = "Dovecot user for untrusted logins";
group = "dovenull";
};
}
// optionalAttrs (cfg.user == "dovecot") {
dovecot = {
uid = config.ids.uids.dovecot;
description = "Dovecot user";
group = cfg.group;
};
}
// optionalAttrs (cfg.createMailUser && cfg.mailUser != null) {
${cfg.mailUser} = {
description = "Virtual Mail User";
isSystemUser = true;
}
// optionalAttrs (cfg.mailGroup != null) { group = cfg.mailGroup; };
};
users.groups = {
dovenull.gid = config.ids.gids.dovenull2;
}
// optionalAttrs (cfg.group == "dovecot") {
dovecot.gid = config.ids.gids.dovecot;
}
// optionalAttrs (cfg.createMailUser && cfg.mailGroup != null) {
${cfg.mailGroup} = { };
};
environment.etc."dovecot/dovecot.conf".source = cfg.configFile;
systemd.services.dovecot = {
description = "Dovecot IMAP/POP3 server";
documentation = [
"man:dovecot(1)"
"https://doc.dovecot.org"
];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
restartTriggers = [ cfg.configFile ];
startLimitIntervalSec = 60; # 1 min
serviceConfig = {
Type = "notify";
ExecStart = "${dovecotPkg}/sbin/dovecot -F";
ExecReload = "${dovecotPkg}/sbin/doveadm reload";
CapabilityBoundingSet = [
"CAP_CHOWN"
"CAP_DAC_OVERRIDE"
"CAP_FOWNER"
"CAP_KILL" # Required for child process management
"CAP_NET_BIND_SERVICE"
"CAP_SETGID"
"CAP_SETUID"
"CAP_SYS_CHROOT"
"CAP_SYS_RESOURCE"
];
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = false; # e.g for sendmail
OOMPolicy = "continue";
PrivateTmp = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = lib.mkDefault false;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "full";
PrivateDevices = true;
Restart = "on-failure";
RestartSec = "1s";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK" # e.g. getifaddrs in sieve handling
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = false; # sets sgid on maildirs
RuntimeDirectory = [ "dovecot" ];
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service @resources"
"~@privileged"
"@chown @setuid capset chroot"
];
};
# When copying sieve scripts preserve the original time stamp
# (should be 0) so that the compiled sieve script is newer than
# the source file and Dovecot won't try to compile it.
preStart = ''
rm -rf ${stateDir}/sieve ${stateDir}/imapsieve
''
+ optionalString (cfg.sieve.scripts != { }) ''
mkdir -p ${stateDir}/sieve
${concatStringsSep "\n" (
mapAttrsToList (to: from: ''
if [ -d '${from}' ]; then
mkdir '${stateDir}/sieve/${to}'
cp -p "${from}/"*.sieve '${stateDir}/sieve/${to}'
else
cp -p '${from}' '${stateDir}/sieve/${to}'
fi
${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/sieve/${to}'
'') cfg.sieve.scripts
)}
chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/sieve'
''
+ optionalString (cfg.imapsieve.mailbox != [ ]) ''
mkdir -p ${stateDir}/imapsieve/{before,after}
${concatMapStringsSep "\n" (
el:
optionalString (el.before != null) ''
cp -p ${el.before} ${stateDir}/imapsieve/before/${baseNameOf el.before}
${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/imapsieve/before/${baseNameOf el.before}'
''
+ optionalString (el.after != null) ''
cp -p ${el.after} ${stateDir}/imapsieve/after/${baseNameOf el.after}
${pkgs.dovecot_pigeonhole}/bin/sievec '${stateDir}/imapsieve/after/${baseNameOf el.after}'
''
) cfg.imapsieve.mailbox}
${optionalString (
cfg.mailUser != null && cfg.mailGroup != null
) "chown -R '${cfg.mailUser}:${cfg.mailGroup}' '${stateDir}/imapsieve'"}
'';
};
environment.systemPackages = [ dovecotPkg ];
warnings = warnAboutExtraConfigCollisions;
assertions = [
{
assertion =
(cfg.sslServerCert == null) == (cfg.sslServerKey == null)
&& (cfg.sslCACert != null -> !(cfg.sslServerCert == null || cfg.sslServerKey == null));
message = "dovecot needs both sslServerCert and sslServerKey defined for working crypto";
}
{
assertion = cfg.showPAMFailure -> cfg.enablePAM;
message = "dovecot is configured with showPAMFailure while enablePAM is disabled";
}
{
assertion = cfg.sieve.scripts != { } -> (cfg.mailUser != null && cfg.mailGroup != null);
message = "dovecot requires mailUser and mailGroup to be set when `sieve.scripts` is set";
}
];
};
meta.maintainers = [ lib.maintainers.dblsaiko ];
}

View file

@ -1,34 +0,0 @@
final: prev: {
dovecot = prev.dovecot.overrideAttrs (oldAttrs: rec {
version = "2.4.0";
src = prev.fetchurl {
url = "https://dovecot.org/releases/${prev.lib.versions.majorMinor version}/${oldAttrs.pname}-${version}.tar.gz";
hash = "sha256-6Q5J+MMbCaUIJJpP7oYF+qZf4yCBm/ytryUkEmJT1a4=";
};
# Dovecot 2.4 Not need this patch anymore
patches = builtins.filter (
patch: (!(prev.lib.hasInfix "Support-openssl-3.0.patch" (toString patch)))
) oldAttrs.patches;
# Dovecot 2.4 Not need this patch anymore
postPatch =
prev.lib.replaceStrings
[
# bash
''
# DES-encrypted passwords are not supported by NixPkgs anymore
sed '/test_password_scheme("CRYPT"/d' -i src/auth/test-libpassword.c
''
]
[
# bash
''
# DES-encrypted passwords are not supported by NixPkgs anymore
sed '/test_password_scheme("CRYPT"/d' -i src/lib-auth/test-password-scheme.c
''
]
oldAttrs.postPatch;
});
}

View file

@ -1,113 +0,0 @@
{
username,
config,
lib,
pkgs,
...
}:
let
faceIcon = pkgs.fetchurl {
url = "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRwExkFtlGxRWflUTcPCfneHSC8E0WuIWNbvkQ4-5_R8x4BXCYx";
hash = "sha256-OXP3iv7JOz/uhw4P90m54yY5j79gDBBVdoySFZmYAZY=";
};
monitors = [
];
in
{
imports = [
./hardware-configuration.nix
../../modules/presets/basic.nix
# Nvidia GPU Driver
(import ../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:59:0:0";
})
./boot.nix # Extra Boot Options
../../modules/gaming.nix
../../modules/wine.nix
../../modules/localsend.nix
(import ../../modules/airplay.nix { hostname = config.networking.hostName; })
# (import ../../modules/virtualization.nix { inherit username; })
# ../../modules/wireguard.nix
];
home-manager = {
users."${username}" = {
imports = [
../../../home/presets/basic.nix
{
home.file.".face" = {
source = lib.mkForce faceIcon;
};
}
# Hyprland
(import ../../../home/user/hyprland.nix { inherit monitors; })
{
wayland.windowManager.hyprland = {
settings = {
input = {
kb_options = lib.mkForce [ ];
};
};
};
}
(import ../../../home/user/waybar.nix {
settings = [
# monitor 1
{
output = "eDP-1";
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"custom/cava"
"mpris"
];
modules-right = (
[
"wlr/taskbar"
]
++ (
if config.programs.gamemode.enable then
[
"custom/gamemode"
]
else
[ ]
)
++ [
# "custom/bitwarden"
"custom/airplay"
"custom/wallRand"
"custom/recording"
"idle_inhibitor"
"network"
"cpu"
"memory"
"pulseaudio"
"custom/swaync"
]
);
}
];
})
# Git
(import ../../../home/user/git.nix {
inherit username;
email = "skyblocksians@gmail.com";
})
];
};
};
users.users."${username}".openssh.authorizedKeys.keys = [
];
}

View file

@ -0,0 +1,6 @@
{
imports = [
./boot.nix
./hardware-configuration.nix
];
}

View file

@ -1,86 +1,38 @@
{ hostname }:
{
username,
config,
...
}:
let
monitors = [
''desc:LG Display 0x0665''
];
username = "danny";
in
{
imports = [
./hardware-configuration.nix
./boot.nix
./sops-conf.nix
../../modules/printer.nix
../../modules/presets/basic.nix
../../modules/gaming.nix
../../modules/virtualization.nix
../../modules/wine.nix
../../modules/wireguard.nix
(import ../../modules/airplay.nix { })
# ../../modules/battery-life.nix
];
home-manager = {
users."${username}" = {
imports = [
../../../home/presets/basic.nix
(import ../../../home/user/bitwarden.nix {
email = "danny@dn-server.net.dn";
baseUrl = "https://bitwarden.net.dn";
})
# Hyprland
(import ../../../home/user/hyprland.nix { inherit monitors; })
{
wayland.windowManager.hyprland = {
settings = {
monitor = [
''desc:LG Display 0x0665, preferred, 0x0, 1.25''
];
};
};
}
# waybar
(import ../../../home/user/waybar.nix {
settings = [
systemConf = {
inherit hostname username;
domain = "net.dn";
hyprland = {
enable = true;
monitors = [
{
desc = "LG Display 0x0665";
output = "eDP-1";
height = 46;
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"mpris"
];
modules-right = [
"wlr/taskbar"
"temperature"
"custom/wallRand"
"custom/wireguard"
"custom/recording"
"idle_inhibitor"
"network"
"pulseaudio"
"battery"
"custom/swaync"
];
props = "preferred, 0x0, 1.25";
}
];
})
};
};
# Git
(import ../../../home/user/git.nix {
inherit username;
email = "danny10132024@gmail.com";
})
imports = [
../../modules/presets/basic.nix
./common
./games
./home
./office
./services
./sops
./utility
./virtualisation
];
};
};
users.users."${username}".openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSHkPa6vmr5WBPXAazY16+Ph1Mqv9E24uLIf32oC2oH danny@phone.dn"

View file

@ -0,0 +1,5 @@
{
imports = [
../../../modules/gaming.nix
];
}

View file

@ -0,0 +1,51 @@
{ config, ... }:
let
inherit (config.systemConf) username;
in
{
home-manager = {
users."${username}" = {
imports = [
../../../../home/presets/basic.nix
(import ../../../../home/user/bitwarden.nix {
email = "danny@dn-server.net.dn";
baseUrl = "https://bitwarden.net.dn";
})
# waybar
(import ../../../../home/user/waybar.nix {
settings = [
{
output = "eDP-1";
height = 46;
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"mpris"
];
modules-right = [
"wlr/taskbar"
"temperature"
"custom/wallRand"
"custom/wireguard"
"custom/recording"
"idle_inhibitor"
"network"
"pulseaudio"
"battery"
"custom/swaync"
];
}
];
})
# Git
(import ../../../../home/user/git.nix {
inherit username;
email = "danny10132024@gmail.com";
})
];
};
};
}

View file

@ -0,0 +1,5 @@
{
imports = [
../../../modules/printer.nix
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
../../../modules/wireguard.nix
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
./sops-conf.nix
];
}

View file

@ -1,22 +1,26 @@
wireguard:
conf: ENC[AES256_GCM,data:GKUlc2K+pJCZHrasZtC/ql8ojYOyIqquOa6gTD3BycvCIU62OO0X0Zi1XW858AzQokHNd3vE+m18XPk1/am5I9FBc0+vGlVctNZgcPLKYObsxF40aZU+NU+Ip1wjNP/V6t0zyt6ur7R7Si9HePhZZqDEpdyBzR2Jjl8DrfC9NiRTVQaHw1D72yjwOGZCkeY7n8PRW9wW9UkzuJNmFHDxF4nUaeP3k3fpfLFEOVyyjvy8Ba995tVWOfJgkMng57VgIr36jzMXWlkpSTB06wWEIfgVpbQpzkFyxWwA4sxhMJfp4JvO3IvzUvkGn3W14Z/SVcg5km7q5aXff9m1/Srn,iv:Oxa377J9Wufm036iFcm+RvitNiWWNPXmUrm9BwrUfBo=,tag:kM4PR/u+j1RkET2Z7FTIPA==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1z6f643a6vqm7cqh6fna5dhmxfkgwxgqy8kg9s0vf9uxhaswtngtspmqsjw
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkczZGckdvWVdlaFFxQmox
eWM5eGtoOHIvbTlEc0RnSVN1REVMSTBXZURrCktDeUxMZUY1cHRtKzRLTDNDUU9E
aldkcFZ2a0ZzUXdOSjZWeHVPZ1FJY1UKLS0tIGZZTlk4OWtZcERXME5YNk96cmc5
M3RPbkRxSFRXeEU5MFZxLzl4clpabDAKiCaiEKZwaCUGi6DRtzb786c8qB+EiiCn
YHrCvm5F72vAmDAozqtTjZM1Dt4yQDxPNMWKFyUzxY0TDpboGrgBHA==
-----END AGE ENCRYPTED FILE-----
- recipient: age17rjcght2y5p4ryr76ysnxpy2wff62sml7pyc5udcts48985j05vqpwdfq2
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1ankwMFc5R3lRK2svRzBL
VVRUMjNRYisyRTNxM1hHeDNsbGVGT2hFUkEwCkpoVWR4MXVuWlJpZEt3eGJiYm5t
SUZubUJqSUEwNnk1K1RsWFVucmFoVEkKLS0tIFd1TitJMHNxc2xwWCtwWnJSWWhN
SnFxQ2Z0MVZ6Nm5oRy96TjFKR0Y3dEkKsT9FjBvrjUZCAx0XKb5Vj5I7VsJixdtf
LTNIAxt20mkyuddr6AaFFN8xsjz0TlwEQRgSGAmm3As2KGKohduMsQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1SzNGcVFkSS93VnQyUlZw
YkM0U1BUTTF4ajY5VU5LOHpYbTBaYnBsUFZnCmx2a0R1VCtkcTUrT2VNMGRRc29H
R1hVSHNDSjlwdk1RUXZYdkpFeUFkY1EKLS0tIDdVdU92STZIN0JmK0ZPeldsYlRG
eWFnVWcrUVpRVDQveTloWk9LVm4yd28KppalVePvXwPks+2TKHqG8a+uZjpgQo3I
edhrdNan56Ly5mLFyXmGlww88nqQMTZq4DODtyfF4+rRlyv0i4AEEg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-04-22T05:44:47Z"
mac: ENC[AES256_GCM,data:DODaAnKe5ExNhXxfOq874bXGy44A3aw+KWnpeDr3OAbocVMvM0uE55r0x9JEbMakVWiDZq0SCP2K6XiTT74hX90tmwvl8jr9HYqAqscOZ75mRfc2NmZJRWuxJj6nA0U+4/A6dm2ftSXP09rH/WjKGpLObLbpOKQledM+U5Ggzjo=,iv:WEhgMOX+L471+ZrBicoBsJAlTxLl9Nc608SPJ3p6XpY=,tag:e/eKKmy4Z8+mC9Ixg0X6+A==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.9.4

View file

@ -0,0 +1,5 @@
{
imports = [
(import ../../../modules/airplay.nix { })
];
}

View file

@ -0,0 +1,6 @@
{
imports = [
../../../modules/virtualization.nix
../../../modules/wine.nix
];
}

View file

@ -0,0 +1,7 @@
{
imports = [
./boot.nix
./nvidia.nix
./hardware-configuration.nix
];
}

View file

@ -0,0 +1,16 @@
{ lib, config, ... }:
let
inherit (lib) mkForce;
in
{
imports = [
(import ../../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:1:0:0";
})
];
hardware.nvidia.package = mkForce config.boot.kernelPackages.nvidiaPackages.latest;
hardware.nvidia.open = mkForce true;
}

View file

@ -1,19 +1,37 @@
{ hostname }:
{
self,
inputs,
pkgs,
username,
config,
lib,
...
}:
let
inherit (lib) optionalString;
protonGEVersion = "10-15";
monitors = [
"desc:ASUSTek COMPUTER INC ASUS VG32VQ1B 0x00002271"
"desc:Acer Technologies XV272U V3 1322131231233"
];
username = "danny";
in
{
systemConf = {
inherit hostname username;
domain = "net.dn";
enableHomeManager = true;
hyprland = {
enable = true;
monitors = [
{
desc = "ASUSTek COMPUTER INC ASUS VG32VQ1B 0x00002271";
output = "DP-6";
props = "2560x1440@165, 0x0, 1";
}
{
desc = "Acer Technologies XV272U V3 1322131231233";
output = "DP-5";
props = "2560x1440@180, -1440x-600, 1, transform, 1";
}
];
};
};
networking.firewall.allowedTCPPortRanges = [
{
from = 8000;
@ -25,57 +43,15 @@ in
}
];
hardware.nvidia.package = lib.mkForce config.boot.kernelPackages.nvidiaPackages.latest;
hardware.nvidia.open = lib.mkForce true;
imports = [
./boot.nix # Extra Boot Options
./sops-conf.nix # Secret
./nginx.nix
./mail.nix
# (import ./netbird.nix {
# domain = "pre7780.dn";
# coturnPassFile = config.sops.secrets."netbird/coturn/password".path;
# idpSecret = config.sops.secrets."netbird/oidc/secret".path;
# dataStoreEncryptionKey = config.sops.secrets."netbird/dataStoreKey".path;
# })
./hardware-configuration.nix
../../modules/presets/basic.nix
../../modules/sunshine.nix
# Nvidia GPU Driver
(import ../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:1:0:0";
})
../../modules/gaming.nix
# ../../modules/secure-boot.nix
../../modules/virtualization.nix
../../modules/wine.nix
../../modules/wireguard.nix
../../modules/localsend.nix
(import ../../modules/airplay.nix { hostname = "pre7780"; })
(import ../../modules/rustdesk-server.nix {
relayHosts = [
"10.0.0.0/24"
"192.168.0.0/24"
];
})
(import ../../modules/nextcloud.nix {
hostname = "nextcloud.pre7780.dn";
configureACME = true;
https = true;
adminpassFile = config.sops.secrets."nextcloud/adminPassword".path;
trusted = [ "nextcloud.daccc.info" ];
})
../../modules/davinci-resolve.nix
../../modules/webcam.nix
../../modules/postgresql.nix
./common
./games
./home
./services
./sops
./utility
./virtualisation
];
# Live Sync D
@ -84,151 +60,9 @@ in
ensureDatabases = [ "livesyncd" ];
};
# Power Management
services.tlp = {
enable = true;
settings = {
INTEL_GPU_MIN_FREQ_ON_AC = 500;
};
};
environment.systemPackages = with pkgs; [
rustdesk
((blender.override { cudaSupport = true; }).overrideAttrs (prev: {
postInstall = ''
sed -i 's|Exec=blender %f|Exec=/run/current-system/sw/bin/nvidia-offload blender %f|' $out/share/applications/blender.desktop
'';
}))
];
services.openssh = {
settings = {
UseDns = false;
};
};
users.users = {
${username} = {
openssh.authorizedKeys.keys = [
users.users.${username}.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJFQA42R3fZmjb9QnUgzzOTIXQBC+D2ravE/ZLvdjoOQ danny@lap.dn"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSHkPa6vmr5WBPXAazY16+Ph1Mqv9E24uLIf32oC2oH danny@phone.dn"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMj/LeB3i/vca3YwGNpAjf922FgiY2svro48fUSQAjOv Shortcuts on :D"
];
};
};
home-manager = {
users."${username}" = {
imports = [
../../../home/presets/basic.nix
# Bitwarden client
(import ../../../home/user/bitwarden.nix {
email = "danny@net.dn";
baseUrl = "https://bitwarden.net.dn";
})
# waybar
(import ../../../home/user/waybar.nix {
settings = [
# monitor 1
{
output = "DP-6";
height = 48;
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"custom/cava"
"mpris"
];
modules-right = [
"wlr/taskbar"
(optionalString config.programs.gamemode.enable "custom/gamemode")
"custom/bitwarden"
"custom/airplay"
"custom/wallRand"
"custom/wireguard"
"custom/recording"
"idle_inhibitor"
"network"
"cpu"
"memory"
"pulseaudio"
"custom/swaync"
];
}
# monitor 2
{
output = "DP-5";
height = 54;
modules-left = [
"clock"
"mpris"
];
modules-right = [
"wlr/taskbar"
"temperature"
"cpu"
"memory"
"pulseaudio"
];
}
];
})
# Hyprland
(import ../../../home/user/hyprland.nix { inherit monitors; })
./hyprland.nix
# Git
(import ../../../home/user/git.nix {
inherit username;
email = "danny10132024@gmail.com";
})
# (import ../../../home/user/wallpaper-engine.nix {
# monitorIdPairs = [
# {
# monitor = "DP-6";
# id = "3050040845";
# }
# {
# monitor = "DP-5";
# id = "2665674743";
# }
# ];
# })
];
home.file = {
# CS go
".steam/steam/steamapps/common/Counter-Strike Global Offensive/game/csgo/cfg/autoexec.cfg".text = ''
fps_max "250"
# Wheel Jump
bind "mwheeldown" "+jump"
bind "mwheelup" "+jump"
bind "space" "+jump"
echo "AUTOEXEC LOADED SUCCESSFULLY!"
host_writeconfig
'';
# Proton GE
".steam/root/compatibilitytools.d/GE-Proton${protonGEVersion}" = {
source = fetchTarball {
url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton${protonGEVersion}/GE-Proton${protonGEVersion}.tar.gz";
sha256 = "sha256:0iv7vak4a42b5m772gqr6wnarswib6dmybfcdjn3snvwxcb6hbsm";
};
};
".steam/root/compatibilitytools.d/CachyOS-Proton10-0_v3" = {
source = fetchTarball {
url = "https://github.com/CachyOS/proton-cachyos/releases/download/cachyos-10.0-20250714-slr/proton-cachyos-10.0-20250714-slr-x86_64_v3.tar.xz";
sha256 = "sha256:0hp22hkfv3f1p75im3xpif0pmixkq2i3hq3dhllzr2r7l1qx16iz";
};
};
};
};
};
}

View file

@ -0,0 +1,5 @@
{
imports = [
./netbird.nix
];
}

View file

@ -9,6 +9,7 @@ let
port = 51820;
in
{
services.netbird = {
server = {
enable = true;

View file

@ -0,0 +1,169 @@
{
pkgs,
lib,
inputs,
system,
}:
let
vmList =
let
kubeMasterIP = "192.168.0.6";
kubeMasterHostname = "api.kube";
kubeMasterAPIServerPort = 6443;
kubeApi = "https://${kubeMasterHostname}:${toString kubeMasterAPIServerPort}";
in
{
# master
vm-1 = {
ip = "192.168.0.6";
mac = "02:00:00:00:00:01";
extraConfig = {
networking.extraHosts = "${kubeMasterIP} ${kubeMasterHostname}";
environment.systemPackages = with pkgs; [
kompose
kubectl
kubernetes
];
services.kubernetes = {
roles = [
"master"
"node"
];
masterAddress = kubeMasterHostname;
apiserverAddress = kubeApi;
easyCerts = true;
apiserver = {
securePort = kubeMasterAPIServerPort;
advertiseAddress = kubeMasterIP;
};
addons.dns.enable = true;
};
systemd.services.link-kube-config = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.writeShellScript "link-kube-config.sh" ''
target="/etc/kubernetes/cluster-admin.kubeconfig"
if [ -e "$target" ]; then
[ ! -d "/root/.kube" ] && mkdir -p "/root/.kube"
ln -sf $target /root/.kube/config
fi
''}";
};
};
};
};
# Node
vm-2 = {
ip = "192.168.0.7";
mac = "02:00:00:00:00:02";
extraConfig = {
networking.extraHosts = "${kubeMasterIP} ${kubeMasterHostname}";
environment.systemPackages = with pkgs; [
kompose
kubectl
kubernetes
];
services.kubernetes = {
roles = [ "node" ];
masterAddress = kubeMasterHostname;
easyCerts = true;
kubelet.kubeconfig.server = kubeApi;
apiserverAddress = kubeApi;
addons.dns.enable = true;
};
};
};
};
mkMicrovm = name: value: {
hypervisor = "qemu";
vcpu = 4;
mem = 8192;
interfaces = [
{
type = "tap";
id = "${name}";
mac = value.mac;
}
];
shares = [
{
tag = "ro-store";
source = "/nix/store";
mountPoint = "/nix/.ro-store";
}
];
};
in
lib.mapAttrs' (
name: value:
lib.nameValuePair name (
lib.nixosSystem {
inherit system;
modules = [
inputs.microvm.nixosModules.microvm
value.extraConfig
{
microvm = mkMicrovm name value;
system.stateVersion = lib.trivial.release;
networking.hostName = name;
networking.domain = "kube";
networking.firewall.enable = false;
users.users.root.password = "";
services.getty.autologinUser = "root";
programs.fish.enable = true;
programs.bash = {
shellInit = ''
if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]]
then
shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=""
exec ${pkgs.fish}/bin/fish $LOGIN_OPTION
fi
'';
};
systemd.network.enable = true;
systemd.network.networks."20-lan" = {
matchConfig.Type = "ether";
networkConfig = {
Address = [ "${value.ip}/24" ];
Gateway = "192.168.0.1";
DNS = [ "192.168.0.1" ];
DHCP = "no";
};
};
systemd.services.br-netfilter = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "/run/current-system/sw/bin/modprobe br_netfilter";
};
};
environment.systemPackages = with pkgs; [
dig.dnsutils
openssl
fishPlugins.done
fishPlugins.fzf-fish
fishPlugins.forgit
fishPlugins.hydro
fzf
fishPlugins.grc
grc
git
];
}
];
}
)
) vmList

View file

@ -0,0 +1,44 @@
self: {
networking.useNetworkd = true;
systemd.network.enable = true;
systemd.network.networks."10-lan" = {
matchConfig.Name = [
"enp0s31f6"
"vm-*"
];
networkConfig = {
Bridge = "br0";
};
};
systemd.network.netdevs."br0" = {
netdevConfig = {
Name = "br0";
Kind = "bridge";
};
};
systemd.network.networks."10-lan-bridge" = {
matchConfig.Name = "br0";
networkConfig = {
Address = [ "192.168.0.5/24" ];
Gateway = "192.168.0.1";
DNS = [ "192.168.0.1" ];
};
linkConfig.RequiredForOnline = "routable";
};
microvm.vms = {
vm-1 = {
flake = self;
updateFlake = "git+file:///etc/nixos";
autostart = false;
};
vm-2 = {
flake = self;
updateFlake = "git+file:///etc/nixos";
autostart = false;
};
};
}

View file

@ -0,0 +1,6 @@
{
imports = [
../../../modules/gaming.nix
./game.nix
];
}

View file

@ -0,0 +1,59 @@
{
pkgs,
pkgs-stable,
config,
inputs,
...
}:
let
protonGEVersion = "10-15";
# ==== Needed for special import ==== #
shadps4-7 = pkgs.shadps4.overrideAttrs (_: rec {
version = "0.7.0";
src = pkgs.fetchFromGitHub {
owner = "shadps4-emu";
repo = "shadPS4";
rev = "v.${version}";
hash = "sha256-g55Ob74Yhnnrsv9+fNA1+uTJ0H2nyH5UT4ITHnrGKDo=";
fetchSubmodules = true;
};
});
in
{
environment.systemPackages = [
pkgs-stable.shadps4
];
home-manager = {
users."${config.systemConf.username}" = {
home.file = {
# CS go
".steam/steam/steamapps/common/Counter-Strike Global Offensive/game/csgo/cfg/autoexec.cfg".text = ''
fps_max "250"
# Wheel Jump
bind "mwheeldown" "+jump"
bind "mwheelup" "+jump"
bind "space" "+jump"
echo "AUTOEXEC LOADED SUCCESSFULLY!"
host_writeconfig
'';
# Proton GE
".steam/root/compatibilitytools.d/GE-Proton${protonGEVersion}" = {
source = fetchTarball {
url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton${protonGEVersion}/GE-Proton${protonGEVersion}.tar.gz";
sha256 = "sha256:0iv7vak4a42b5m772gqr6wnarswib6dmybfcdjn3snvwxcb6hbsm";
};
};
".steam/root/compatibilitytools.d/CachyOS-Proton10-0_v3" = {
source = fetchTarball {
url = "https://github.com/CachyOS/proton-cachyos/releases/download/cachyos-10.0-20250714-slr/proton-cachyos-10.0-20250714-slr-x86_64_v3.tar.xz";
sha256 = "sha256:0hp22hkfv3f1p75im3xpif0pmixkq2i3hq3dhllzr2r7l1qx16iz";
};
};
};
};
};
}

View file

@ -0,0 +1,74 @@
{ config, lib, ... }:
let
inherit (lib) optionalString;
inherit (config.systemConf) username;
in
{
home-manager.users."${username}" = {
imports = [
../../../../home/presets/basic.nix
./wm
# Bitwarden client
(import ../../../../home/user/bitwarden.nix {
email = "danny@net.dn";
baseUrl = "https://bitwarden.net.dn";
})
# waybar
(import ../../../../home/user/waybar.nix {
settings = [
# monitor 1
{
output = "DP-6";
height = 48;
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"custom/cava"
"mpris"
];
modules-right = [
"wlr/taskbar"
(optionalString config.programs.gamemode.enable "custom/gamemode")
"custom/bitwarden"
"custom/airplay"
"custom/wallRand"
"custom/wireguard"
"custom/recording"
"idle_inhibitor"
"network"
"cpu"
"memory"
"pulseaudio"
"custom/swaync"
];
}
# monitor 2
{
output = "DP-5";
height = 54;
modules-left = [
"clock"
"mpris"
];
modules-right = [
"wlr/taskbar"
"temperature"
"cpu"
"memory"
"pulseaudio"
];
}
];
})
# Git
(import ../../../../home/user/git.nix {
inherit username;
email = "danny10132024@gmail.com";
})
];
};
}

View file

@ -0,0 +1,5 @@
{
imports = [
./hyprland.nix
];
}

View file

@ -1,6 +1,6 @@
{ pkgs, ... }:
let
memeSelector = pkgs.callPackage ../../../home/scripts/memeSelector.nix {
memeSelector = pkgs.callPackage ../../../../../home/scripts/memeSelector.nix {
url = "https://nextcloud.net.dn/public.php/dav/files/pygHoPB5LxDZbeY/";
};
in
@ -11,10 +11,6 @@ in
wayland.windowManager.hyprland = {
settings = {
monitor = [
''desc:ASUSTek COMPUTER INC ASUS VG32VQ1B 0x00002271, 2560x1440@165, 0x0, 1''
''desc:Acer Technologies XV272U V3 1322131231233, 2560x1440@180, -1440x-600, 1, transform, 1''
];
misc = {
vrr = 0;
};

View file

@ -0,0 +1,9 @@
{
imports = [
../../../modules/postgresql.nix
./mail.nix
./nginx.nix
./wireguard.nix
# ./netbird.nix
];
}

View file

@ -1,4 +1,7 @@
{ config, ... }:
{
config,
...
}:
let
domain = "daccc.info";
fqdn = "mx1.daccc.info";
@ -6,7 +9,7 @@ in
{
networking.firewall.allowedTCPPorts = [ 8080 ];
imports = [
(import ../../modules/stalwart.nix {
(import ../../../modules/stalwart.nix {
inherit domain;
enableNginx = false;
@ -30,9 +33,10 @@ in
};
ldapConf = {
type = "ldap";
url = "ldap://10.0.0.1:389";
url = "ldaps://ldap.net.dn";
tls.enable = true;
timeout = "30s";
base-dn = "dc=net,dc=dn";
base-dn = "ou=people,dc=net,dc=dn";
attributes = {
name = "uid";
email = "mail";
@ -44,28 +48,18 @@ in
class = "objectClass";
};
filter = {
name = "(&(objectClass=inetOrgPerson)(uid=?))";
name = "(&(objectClass=inetOrgPerson)(|(uid=?)(mail=?)))";
email = "(&(objectClass=inetOrgPerson)(mail=?))";
};
bind = {
dn = "cn=admin,dc=net,dc=dn";
secret = "%{file:${config.sops.secrets."stalwart/ldap".path}}%";
auth = {
method = "lookup";
method = "default";
};
};
};
oidcConf = {
type = "oidc";
timeout = "1s";
endpoint.url = "https://keycloak.net.dn/realms/master/protocol/openid-connect/userinfo";
endpoint.method = "userinfo";
fields = {
email = "email";
username = "preferred_username";
full-name = "name";
};
};
})
];
}

View file

@ -0,0 +1,11 @@
{ config, ... }:
{
imports = [
(import ../expr/netbird.nix {
domain = "pre7780.dn";
coturnPassFile = config.sops.secrets."netbird/coturn/password".path;
idpSecret = config.sops.secrets."netbird/oidc/secret".path;
dataStoreEncryptionKey = config.sops.secrets."netbird/dataStoreKey".path;
})
];
}

View file

@ -9,9 +9,11 @@
acceptTerms = true;
defaults = {
validMinDays = 2;
webroot = null;
server = "https://ca.net.dn/acme/acme/directory";
renewInterval = "daily";
email = "danny@net.dn";
email = "danny@pre7780.dn";
dnsResolver = "10.0.0.1:53";
dnsProvider = "pdns";
dnsPropagationCheck = false;
environmentFile = config.sops.secrets."acme/pdns".path;

View file

@ -0,0 +1,5 @@
{
imports = [
../../../modules/wireguard.nix
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
./sops-conf.nix
];
}

View file

@ -15,13 +15,17 @@ stalwart:
dkimKey: ENC[AES256_GCM,data:oi+XvZ9hMMsgMtFnGPMbVBGagkwQzcPQDi1b0Zd54615V5yuOLHZxpLT5Z3LYlCOQmOcrCaIwn8lQKIZbAuAq6HDUVlNabjgnHeoq3XRIvcswO/B9pljL/22JCZleSrWSBh+WE+RwQIcqUIr0eNerXCUaAQLTE8lYn6mJMa/OoHJJ3R498OGyM/8rbuIMfKj5eqJnctsd9lRWeNmiq7hpQKJ8syLXMsRM9y79NJTPGJrIAJ/5F8SfUJ256/S2N25Cq61pkaXWxTcZzXFgAGU/sa3zsY86BRwEnFEVRMnygJWrVZW/ABYgRjL99r6OBQM8WTFpE8cK9GZTpylTm+QCS9lHsAA2rnUfLTs/09z41klbGSAu5jfokM5jhyFIjmDm9h3hEk4l0F4KTWgQ7avWqGVx4yVPktrVS6eh6W7+I0V6BOUhzH0Pp9xXWwhbFrMPYAYK5MQSLAS5nd3RCQWrxZwWh//ATiWdngUeWPyObxXSTmoV254k230sT39jQmqmTK5zIkOBvokPps9q3nPq1i3UIkSAXo0ZWI+GHiL1rnzJkMMGViugJdGEwUf8nWlYMcYkHmDRUZam6DIxzkf5svtd+kbDTxRa4GzeJrOYizgwDGpD5vRA9u8i7MYBS1Rhw3UVqZ9gkjtv8mqoOkDqVnHVnS2UPtsircecvjHmhu4Tq4hn8phX3F+2I8lhXUIalzPng5zjPGNUcDT+SoCbNeHuSWDDmMYQtzM3/xwae9quP9FXhr9IGGygmFUPGsl3cuxSJ3+Cq9/Hhd7bnTYnxYfv781qTmZsFclMUWNxUJQWLJ+5BQz6u1zW64wh+5SHUGrw7CHFsdgNAKv7YN+GJMNTHOjZr9RTL9R8opDm8Iho5IyQjMP401+DY30mOCq03WKJiC8qehgoaH16ssNV6ZuoHldu2N6JKmiwywgTRq8zQEo8jPnro772CQ9Tg0/5PnkhdlLdphDEIp60IbM+XWqMNwHY57fm6U+81PcgtsoRmI5OklrrhQjv+1aRgz0vRM80FOHMv7kxgEdNkb1x15B4g0ocBXEdLuxJEVaW4uWlP9EIivXOWwaPZf1QjT8ISuUQlFMXvtNj/V3SraW3K1bErJL5JnI16z803kdoAqYijf3IrRK49SKoCq6B2V8yo8iCRod2GFt1P3ADKb/uvJ6iCBSlFRFwiJYr8qu7TPXFCpsoySEmr1edBQdAkzXxFZLDMczHq2BzUo2RPfwtDubG1GMWxzrbZ1T6N3j1+GXiyTX7XuKdpSpFlXtPuJcCIrX4D4xnjv1SqqXEcKJO9oUcdMK6+Eem7wtVDBDDYpWellT+bLmtouvdEgjYE8VG5UGJJ5NpYoJAce9c7RE5/ozuvUH+uMfqfb8igZQlBMl6hbqO7j8m11i+ijS9T6Wu2DCSVIqqBHu8bouz1vyfq8l/whJCl1BkaZtiE5+NLkHoYSOuXGtVvEuXwMhvCWdnkxJtHZxxXQuCcBcVkD9Edg0YTslGv+XUvaYRlfZUqypqYZ9zJ21en9XPK3zafZ5gRLdY0xhXN4OKbGrXXL4cm5jfroTeez9iIL4fJGcA80PRHUGoLfK7ht2z0Lq3U91F4jz5KEhbaDtWDcMryr1Bwb6UXgLrezNM290g8J3GpXLBAdvqDXK79jSdPNqptGYt++VDeCdtA+P3z9K6aMWZzPURkLXxZ1bWy5YXP03MIkUpZWsc5lQmccUiyFe/Y+d9RSAZClmVxsQAY5y90d42EhkrOag06geziV9aaxgr57LdoPJQabD48bIbFFvimhV2DS3Gf/7gFtCXlm9oZiIqSHG+1TMKRp8XVwn6f70d76/Ba5Uiu0EX8V2x0Dsnin6GGynMBFCPKPXssHRe71SfRVxPJrzlLjtfTdPuzW5Q2k/U//z9SWd6Ao3+mzsbTC8MAYGeIzeE4GdsTs4ViEQWg5sSMSfjeKOFfgpTQi20LGomjF4gtTfnchEUBcUAarV6+hT/inYG2SlglyWwr2+LE3Ua5FWRXsZu4tBHcfE0axIb6Ju5KeogPVPo6cNoJCR2XLPNQakB9ONniCxPTW6zOx8h/A2UeIWMgbAn/jNYdd4kFu1IWBAQaZg5kSg1KmSAtnKgFmhb8A0Ope8h5fKfdX5tf0ulW0bjBz+rqNf2FQwcB/ScuEc65LSX+b0bzvIILuZfSRytFQpaQ4svjjA6mP4VIRoPRkkRl+gTEO+Ue4No4VZGE9+YdRFZ7OmtH6S1e5vu1rBiLuTVayHjuSWRu0OmxDiErP6uXPy8Q==,iv:Q5g9kxJKEKLHge2mcgk/UnTNMDFjzeLFLNjlY8KWe60=,tag:yL03NWRK2whOxNjcR3cPyA==,type:str]
ldap: ENC[AES256_GCM,data:ygOPMCNIxvWxE9dPBeKGbA==,iv:t+p1/vjEZNDTw7LcaitzYv2xCPtlf/mmQhqXT1OFKXs=,tag:uPYp259FHZu5fut+Bc9eSA==,type:str]
acme:
pdns: ENC[AES256_GCM,data:+InGSnaGIFVtDRlVltzWbZfquzodHUQrPeMRBnVNB9mrajlKr5dFK6DD8dXAvN7UjZFBfrgZefOPkmLR2ncLXGOV2Kl7jorVw50Y0f0iKl7mqwHaZKaQdk7cpGDkCrt/LvfbP9x7gVrs6pQpsU+c/P5rbBLRyejchh/WtiyzgowYIJxYohggeG09+l7YI3FR6U5wiymIRISpNBGEhwG0q17qdAhdtc49qP/K,iv:JcSlxAwHwU528S7iSpAnSbUZw7iO+LMjR3qGwRHp+Zk=,tag:twf2WOQb/yZ3GtN/hlikMA==,type:str]
pdns: ENC[AES256_GCM,data:eKnahc8HWboYCUpBuEUrdCMhN8A2N2VN0wrmzcyU2OfMeQaswIYSWV4sBzUbj/pono8PaVxK1FBKsn+Ycd4Y6tcxsAkbPfnPkOsbe0FJpz4t9RFLJBLw3U0YTE/TaURiDYipHnvPGYgyq3AziH/xa4WXZxLHGI0x+a/y3PpWy37rT87DWUT2kktPshdO7Mbwn7nSC78WByXmyaUMkT74Sc0FNmCgfijrHk/ATXGb,iv:y3eRZXFbqqf4VuuqHHYdIoiEa1zqRU1XIlEqooJ28lU=,tag:2bIALJFGZyIZT7fyo/y5Nw==,type:str]
cloudflare:
secret: ENC[AES256_GCM,data:tritGdt3bWm/YtfdF2kO8qIBisa2rGF9/Dpl8R79e6REe//YKZFqFg==,iv:UG53JZ55+gDCPJzKjbVaWnpgOdvqcRoDUg8ef9xOV9A=,tag:JD3s28dsA9G2fqtz4soATA==,type:str]
netbird:
oidc:
secret: ENC[AES256_GCM,data:hSVMUEBL0kCvRLD3zd57SLhNIAFOR4eaJPcIIIIUJng=,iv:VhfseftQNlXSDCWuaYQUIklMUCkUbChyWbJl3qgD75M=,tag:vbqov0VgA0XNZfzcr3FZgA==,type:str]
dataStoreKey: ENC[AES256_GCM,data:vV2wgo5qFS+DC1NmOjVddZW9HAsRMpUFH+t/70iQ3A5YXkhbWoCeSxZDyAg=,iv:tKqh28qj8gqHfcb44Ej731w6NKi29X4iEwIOQ4ZcCzA=,tag:ObAxVrUctm6pbmXSQw7j5w==,type:str]
crowdsec:
lapi.yaml: ENC[AES256_GCM,data:BpDlz/liFYVZTA66TMWDifGfT4R9l0W9/LOU33rrPVC4YKeFbB1gIxqkUOEDl8fxsou5Jx/MQivyz90lE8yxbcGV/Zzx4ZJaHN+jz6mfM6mADEWp/nUcfO9tECijOhPPYt/8aE3py38NlFZuafZ2CwdL7RmDX7YCjpiIYxXaIjSv61WPD1SLkOkusnoA7bJZ2xmJ/dfEMXEA4LCCOfGQ,iv:922rrz94pD3/R1kGlQyIFkoq/fRSyxaIQ5qllldQMCY=,tag:AAPlwiQP4KMzHZmcMH76AQ==,type:str]
capi.yaml: ENC[AES256_GCM,data:UuBESeHfKEPSIzP7RPNES0BVWwJsmPqLP3QJbAeAcm6eQ3sRzUSrVxY8A2yoiLD2lnuJPy2BbYHJpBR7VSfs7oUCc7LljgAp1uB2GH1y8YE46xJLo0TDp873bZJdcsO00ozsbtmWlGWJm7HLrzIUEe0mAjBzZeXe1WDJByGeVqupNLwpXSMaos2ktHjXA6hTGAdE5iIxBAXI6qjldWjRnlqE,iv:hZ2nUaOipU7Top0vsn23yU0XWP9SKcoj85xFo5hD/mU=,tag:32E2o+FOJXM9aMnLQA6KYA==,type:str]
consoleToken: ENC[AES256_GCM,data:Q6QWWwcvLd8+ddwPMBzyB+X4gh8I53qSLA==,iv:JD48L59nQYttglAfuKL/lNBzWgBfj01rkIeP8pqmo70=,tag:6cxsQViDGuzjScKkBuO4Bw==,type:str]
sops:
age:
- recipient: age1uvsvf5ljaezh5wze32p685kfentyle0l2mvysc67yvgct2h4850qqph9lv
@ -33,7 +37,7 @@ sops:
MEdmWkFwNXZoR1ZVRnQ0aWlkYzZwSmsK0EFecUIdqlDKX08oRCoDQQ3QCX1wzb8w
lghDJhWlfuKr+X24GoE4UK04aJVLqVMRRI4BJW+LQXeHS+dWKu3mQA==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-10-01T05:31:13Z"
mac: ENC[AES256_GCM,data:a3CkOEZUYSeRa6Zj+2EQnusgkOu2xHvGXhW9Pr5ny9sEiUF+S9jLQeS9vZpDNnQc5F/BRf/r0K7BTSwyoaAGZn3vsm3ruTGpajqV43Ji8PzG8BEApV0USwAn+gM8K4mMAEU9AjiqQ6k4Zf/dbYzv/rDtxVTdSbwcpM8KjIBv//Q=,iv:aCk+M3wigrbhCEHtf1K9vwByIYnTxBi7VD1XEIYgiL8=,tag:PtJN8KlPZbed0bgEcgSY0w==,type:str]
lastmodified: "2025-10-13T06:51:06Z"
mac: ENC[AES256_GCM,data:1+X8f7lPwN+ELJ4DmkTN71Kzvvh4V3yiMilOOnz4NCqLRPdtpiQQz8W4VXkOkBONV5816IOCU2Br4kiQnPAkPEiwpJZzWQItqomZTp4gErSGmmMpVf2lbCRfsU2Eg1tgAaS1ZRQx8/o1vSIJtoPVKiqYdYSsNDx2zbafWqn9+Rk=,iv:uZ4BWoJB6LazGy+RAzdhB8uUCSa109R4TdE6PguryR8=,tag:5G0GRihPQKl9n/fJjZr/Jw==,type:str]
unencrypted_suffix: _unencrypted
version: 3.10.2
version: 3.11.0

View file

@ -10,17 +10,8 @@ in
owner = "nextcloud";
group = "nextcloud";
};
"openldap/adminPassword" = mkIf config.services.openldap.enable {
owner = config.users.users.openldap.name;
group = config.users.users.openldap.group;
mode = "0660";
};
"lam/env" = { };
"dovecot/openldap" = mkIf (config.services.postfix.enable && config.services.openldap.enable) {
owner = config.services.dovecot2.user;
group = config.services.dovecot2.group;
mode = "0660";
};
"netbird/oidc/secret" = mkIf config.services.netbird.server.dashboard.enable {
owner = "netbird";
@ -36,6 +27,18 @@ in
"acme/pdns" = mkIf (hasAttr "acme" config.users.users) {
owner = "acme";
};
"crowdsec/lapi.yaml" = mkIf config.services.crowdsec.enable {
owner = "crowdsec";
mode = "0600";
};
"crowdsec/capi.yaml" = mkIf config.services.crowdsec.enable {
owner = "crowdsec";
mode = "0600";
};
"crowdsec/consoleToken" = mkIf config.services.crowdsec.enable {
owner = "crowdsec";
mode = "0600";
};
}
// (optionalAttrs config.services.stalwart-mail.enable (
let

View file

@ -0,0 +1,5 @@
{
imports = [
(import ../../../modules/airplay.nix { hostname = "pre7780"; })
];
}

View file

@ -0,0 +1,11 @@
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
rustdesk
((blender.override { cudaSupport = true; }).overrideAttrs (prev: {
postInstall = ''
sed -i 's|Exec=blender %f|Exec=/run/current-system/sw/bin/nvidia-offload blender %f|' $out/share/applications/blender.desktop
'';
}))
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
../../../modules/davinci-resolve.nix
];
}

View file

@ -0,0 +1,8 @@
{
imports = [
../../../modules/localsend.nix
./airplay.nix
./davinci-resolve.nix
./blender.nix
];
}

View file

@ -0,0 +1,6 @@
{
imports = [
../../../modules/virtualization.nix
../../../modules/wine.nix
];
}

View file

@ -0,0 +1,14 @@
{
imports = [
../../../modules/presets/minimal.nix
../../../modules/bluetooth.nix
../../../modules/gc.nix
../../../modules/stylix.nix
../../../modules/postgresql.nix
./backup.nix
./boot.nix
./hardware-configuration.nix
./networking.nix
./nvidia.nix
];
}

View file

@ -4,7 +4,6 @@
{
config,
lib,
pkgs,
modulesPath,
...
}:

View file

@ -2,18 +2,11 @@
with lib;
{
networking = {
domain = "net.dn";
networkmanager = {
enable = true;
insertNameservers = mkForce [ "127.0.0.1" ];
};
enableIPv6 = true;
firewall = {
enable = true;
allowedTCPPorts = [
443
80
];
};
firewall.enable = true;
};
}

View file

@ -0,0 +1,9 @@
{
imports = [
(import ../../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:1:0:0";
})
];
}

View file

@ -1,157 +1,33 @@
{ hostname }:
{
pkgs,
lib,
inputs,
system,
username,
config,
...
}:
let
inherit (lib) optionalAttrs;
inherit (builtins) toString;
username = "danny";
in
{
systemConf = {
inherit hostname username;
domain = "net.dn";
hyprland.enable = false;
};
imports = [
(import ../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:1:0:0";
})
./backup.nix
./security.nix
./sops-conf.nix
./boot.nix
./hardware-configuration.nix
./networking.nix
./services.nix
./nginx.nix
./step-ca.nix
./atticd.nix
../../modules/presets/minimal.nix
../../modules/bluetooth.nix
../../modules/gc.nix
../../modules/mail-server
../../modules/stylix.nix
(import ../../modules/paperless-ngx.nix {
domain = "paperless.net.dn";
passwordFile = config.sops.secrets."paperless/adminPassword".path;
})
(import ../../modules/prometheus.nix {
fqdn = "metrics.net.dn";
selfMonitor = true;
configureNginx = true;
scrapes = [
(optionalAttrs config.services.pdns-recursor.enable {
job_name = "powerdns_recursor";
static_configs = [
{
targets = [ "localhost:${toString config.services.pdns-recursor.api.port}" ];
}
];
})
];
})
(import ../../modules/actual {
fqdn = "actual.net.dn";
})
(import ../../modules/nextcloud.nix {
hostname = "nextcloud.net.dn";
adminpassFile = config.sops.secrets."nextcloud/adminPassword".path;
trusted = [ "nextcloud.daccc.info" ];
})
(import ../../modules/vaultwarden.nix {
domain = "bitwarden.net.dn";
})
(import ../../modules/grafana.nix {
domain = "grafana.net.dn";
passFile = config.sops.secrets."grafana/password".path;
smtpHost = config.mail-server.domain;
smtpDomain = config.mail-server.domain;
extraSettings = {
"auth.generic_oauth" =
let
OIDCBaseUrl = "https://keycloak.net.dn/realms/master/protocol/openid-connect";
in
{
enabled = true;
allow_sign_up = true;
client_id = "grafana";
client_secret = ''$__file{${config.sops.secrets."grafana/client_secret".path}}'';
scopes = "openid email profile offline_access roles";
email_attribute_path = "email";
login_attribute_path = "username";
name_attribute_path = "full_name";
auth_url = "${OIDCBaseUrl}/auth";
token_url = "${OIDCBaseUrl}/token";
api_url = "${OIDCBaseUrl}/userinfo";
role_attribute_path = "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'";
};
};
})
../../modules/postgresql.nix
./common
./home
./network
./nix
./security
./services
./sops
];
environment.systemPackages = with pkgs; [
openssl
];
mail-server = {
enable = true;
configureACME = true;
mailDir = "~/Maildir";
caFile = "" + ../../extra/ca.crt;
virtualMailDir = "/var/mail/vhosts";
domain = "net.dn";
rootAlias = "${username}";
networks = [
"127.0.0.0/8"
"10.0.0.0/24"
];
virtual = ''
admin@net.dn ${username}@net.dn
postmaster@net.dn ${username}@net.dn
'';
openFirewall = true;
oauth = {
passwordFile = config.sops.secrets."oauth/password".path;
};
ldap = {
passwordFile = config.sops.secrets."ldap/password".path;
webEnv = config.sops.secrets."ldap/env".path;
};
rspamd = {
trainerSecret = config.sops.secrets."rspamd-trainer".path;
};
};
home-manager = {
users."${username}" = {
imports = [
../../../home/user/config.nix
../../../home/user/direnv.nix
../../../home/user/environment.nix
../../../home/user/nvf
../../../home/user/shell.nix
../../../home/user/tmux.nix
../../../home/user/yazi.nix
{
home.packages = with pkgs; [
inputs.ghostty.packages.${system}.default
(python3.withPackages (
p: with p; [
pip
]
))
];
}
# Git
(import ../../../home/user/git.nix {
inherit username;
email = "danny10132024@gmail.com";
})
];
};
};
}

View file

@ -0,0 +1,34 @@
{
inputs,
config,
pkgs,
...
}:
let
inherit (config.systemConf) username;
in
{
home-manager = {
users."${username}" = {
imports = [
../../../../home/user/config.nix
../../../../home/user/direnv.nix
../../../../home/user/environment.nix
../../../../home/user/nvf
../../../../home/user/shell.nix
../../../../home/user/yazi.nix
{
home.packages = with pkgs; [
inputs.ghostty.packages.${system}.default
];
}
# Git
(import ../../../../home/user/git.nix {
inherit username;
email = "danny10132024@gmail.com";
})
];
};
};
}

View file

@ -0,0 +1,7 @@
{
imports = [
./nginx.nix
./services.nix
./step-ca.nix
];
}

View file

@ -1,11 +1,10 @@
{
config,
lib,
username,
...
}:
let
inherit username;
inherit (config.systemConf) username;
ethInterface = "enp0s31f6";
sshPorts = [ 30072 ];
@ -319,6 +318,7 @@ in
gpgsql-host=/var/run/postgresql
gpgsql-dbname=pdns
gpgsql-user=pdns
gpgsql-dnssec=yes
webserver=yes
webserver-port=8081
local-port=5359
@ -372,6 +372,9 @@ in
};
};
systemd.services.pdns-recursor.before = [ "acme-setup.service" ];
systemd.services.pdns.before = [ "acme-setup.service" ];
users.users = {
root.openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJSAOufpee7f8D8ONIIGU3qsN+8+DGO7BfZnEOTYqtQ5 danny@pre7780.dn"
@ -386,7 +389,7 @@ in
virtualisation = {
oci-containers = {
backend = "podman";
backend = "docker";
containers = {
uptime-kuma = {
extraOptions = [ "--network=host" ];

View file

@ -0,0 +1,5 @@
{
imports = [
./atticd.nix
];
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
{ config, ... }:
{
imports = [
(import ../../../modules/crowdsec.nix {
lapiCred = config.sops.secrets."crowdsec/lapi.yaml".path;
capiCred = config.sops.secrets."crowdsec/capi.yaml".path;
consoleToken = config.sops.secrets."crowdsec/consoleToken".path;
enableServer = true;
enablePrometheus = true;
})
];
}

View file

@ -0,0 +1,6 @@
{
imports = [
./fail2ban.nix
./crowdsec.nix
];
}

View file

@ -1,9 +1,6 @@
{
...
}:
{
imports = [
(import ../../modules/fail2ban.nix {
(import ../../../modules/fail2ban.nix {
extraAllowList = [
"10.0.0.0/24"
"122.117.215.55"

View file

@ -0,0 +1,7 @@
{
imports = [
(import ../../../modules/actual {
fqdn = "actual.net.dn";
})
];
}

View file

@ -0,0 +1,7 @@
{
imports = [
(import ../../../modules/vaultwarden.nix {
domain = "bitwarden.net.dn";
})
];
}

View file

@ -0,0 +1,11 @@
{
imports = [
./actual-budget.nix
./bitwarden.nix
./docmost.nix
./mail-server.nix
./nextcloud.nix
./paperless-ngx.nix
./metrics.nix
];
}

View file

@ -0,0 +1,12 @@
{ config, ... }:
{
imports = [
(import ../../../modules/docmost.nix {
fqdn = "docmost.net.dn";
extraConf = {
MAIL_DRIVER = "smtp";
};
envFile = config.sops.secrets."docmost".path;
})
];
}

View file

@ -0,0 +1,58 @@
{ config, ... }:
let
inherit (config.systemConf) username;
in
{
mail-server =
let
domain = "net.dn";
in
{
inherit domain;
enable = true;
openFirewall = true;
configureNginx = true;
hostname = "mx1";
extraDomains = [
"mail.${domain}"
];
caFile = "" + ../../../extra/ca.crt;
rootAlias = "${username}";
networks = [
"127.0.0.0/8"
"10.0.0.0/24"
];
virtual = ''
admin@${domain} ${username}@${domain}
postmaster@${domain} ${username}@${domain}
'';
webmail = {
enable = true;
hostname = "mail.${domain}";
};
keycloak = {
dbSecretFile = config.sops.secrets."oauth/password".path;
adminAccountFile = config.sops.secrets."oauth/adminEnv".path;
};
ldap = {
filter = "(&(objectClass=inetOrgPerson)(objectClass=mailRoutingObject)(uid=%{user | username}))";
extraAuthConf = ''
auth_username_format = %{user | lower}
fields {
user = %{ldap:mail}
password = %{ldap:userPassword}
}
'';
secretFile = config.sops.secrets."ldap/password".path;
webSecretFile = config.sops.secrets."ldap/env".path;
};
rspamd = {
secretFile = config.sops.secrets."rspamd".path;
trainerSecretFile = config.sops.secrets."rspamd-trainer".path;
};
dovecot.oauth = {
enable = true;
};
};
}

View file

@ -0,0 +1,157 @@
{
config,
lib,
helper,
pkgs,
...
}:
let
inherit (helper.grafana) mkDashboard;
inherit (lib) optionalAttrs;
inherit (config.networking) hostName;
datasourceTemplate = [
{
current = {
text = "Prometheus";
value = "prometheus-dn-server";
};
label = "DS_PROMETHEUS";
name = "DS_PROMETHEUS";
options = [ ];
query = "prometheus";
refresh = 1;
regex = "";
type = "datasource";
}
];
crowdsecSrc = fetchTarball {
url = "https://github.com/crowdsecurity/grafana-dashboards/archive/c89d8476b32ea76e924c488db7d0afd0306fc609.tar.gz";
sha256 = "sha256:1s7v03hzss22dkl3hw9qf0qc86qn98wx8x13rvy73wc5mgxv9wnk";
};
crowdsecDashboard = mkDashboard {
name = "crowdsec";
src = "${crowdsecSrc}/dashboards_v5";
templateList = datasourceTemplate;
};
pdnsRecursorSrc = pkgs.fetchurl {
name = "pdns-recursor-grafana-dashboard.json";
url = "https://grafana.com/api/dashboards/20448/revisions/3/download";
sha256 = "sha256-8lgo+A3dnFLanhGJWCKAo/iPYSMiove17xvMolgq9nI=";
};
pdnsRecursorDashboard = mkDashboard {
name = "pdns-recursor";
src = "${pdnsRecursorSrc}";
templateList = datasourceTemplate;
conf = {
dontUnpack = true;
};
};
in
{
imports = [
(import ../../../modules/prometheus.nix {
fqdn = "metrics.net.dn";
selfMonitor = true;
configureNginx = true;
scrapes = [
(optionalAttrs config.services.pdns-recursor.enable {
job_name = "powerdns_recursor";
static_configs = [
{
targets = [ "localhost:${toString config.services.pdns-recursor.api.port}" ];
labels = {
machine = "${hostName}";
};
}
];
relabel_configs = [
{
source_labels = [ "__address__" ];
target_label = "instance";
regex = "(.*):[0-9]+";
replacement = "PDNS Recursor - \${1}";
}
];
})
(optionalAttrs config.services.crowdsec.settings.general.prometheus.enabled {
job_name = "crowdsec";
static_configs = [
{
targets = [
"localhost:${toString config.services.crowdsec.settings.general.prometheus.listen_port}"
];
labels = {
machine = "${hostName}";
};
}
];
relabel_configs = [
{
source_labels = [ "__address__" ];
target_label = "instance";
regex = "(.*):[0-9]+";
replacement = "CrowdSec - \${1}";
}
];
})
];
})
(import ../../../modules/grafana.nix {
domain = "grafana.net.dn";
passFile = config.sops.secrets."grafana/password".path;
smtpHost = "${config.mail-server.hostname}.${config.mail-server.domain}:465";
smtpDomain = config.mail-server.domain;
extraSettings = {
"auth.generic_oauth" =
let
OIDCBaseUrl = "https://keycloak.net.dn/realms/master/protocol/openid-connect";
in
{
enabled = true;
allow_sign_up = true;
client_id = "grafana";
client_secret = ''$__file{${config.sops.secrets."grafana/client_secret".path}}'';
scopes = "openid email profile offline_access roles";
email_attribute_path = "email";
login_attribute_path = "username";
name_attribute_path = "username";
auth_url = "${OIDCBaseUrl}/auth";
token_url = "${OIDCBaseUrl}/token";
api_url = "${OIDCBaseUrl}/userinfo";
role_attribute_path = "contains(roles[*], 'admin') && 'Admin' || contains(roles[*], 'editor') && 'Editor' || 'Viewer'";
};
};
extraConf = {
provision.datasources.settings = {
prune = true;
datasources = [
{
uid = "prometheus-dn-server";
name = "Prometheus";
url = "https://metrics.net.dn";
type = "prometheus";
}
];
};
provision.dashboards.settings.providers = [
{
name = "CrowdSec";
type = "file";
options.path = "${crowdsecDashboard}";
}
{
name = "PDNSRecursor";
type = "file";
options.path = "${pdnsRecursorDashboard}";
}
];
};
})
];
}

View file

@ -0,0 +1,11 @@
{ config, ... }:
{
imports = [
(import ../../../modules/nextcloud.nix {
hostname = "nextcloud.net.dn";
adminpassFile = config.sops.secrets."nextcloud/adminPassword".path;
trusted-domains = [ "nextcloud.daccc.info" ];
trusted-proxies = [ "10.0.0.0/24" ];
})
];
}

View file

@ -0,0 +1,9 @@
{ config, ... }:
{
imports = [
(import ../../../modules/paperless-ngx.nix {
domain = "paperless.net.dn";
passwordFile = config.sops.secrets."paperless/adminPassword".path;
})
];
}

View file

@ -1,69 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) mkIf;
in
{
sops = {
secrets = {
"wireguard/privateKey" = { };
"nextcloud/adminPassword" = { };
"step_ca/password" = { };
vaultwarden = { };
"oauth/password" = { };
"ldap/password" = lib.mkIf config.mail-server.enable {
mode = "0660";
owner = config.services.openldap.user;
group = config.services.openldap.group;
};
"ldap/env" = lib.mkIf config.mail-server.enable {
mode = "0660";
group = config.users.groups.docker.name;
};
"powerdns-admin/secret" = {
mode = "0660";
owner = "powerdnsadmin";
group = "powerdnsadmin";
};
"powerdns-admin/salt" = {
mode = "0660";
owner = "powerdnsadmin";
group = "powerdnsadmin";
};
powerdns = {
mode = "0660";
owner = "pdns";
group = "pdns";
};
rspamd-trainer = { };
"acme/env" = mkIf config.security.acme.acceptTerms {
mode = "0660";
owner = "acme";
group = "acme";
};
"postsrsd/secret" = mkIf config.services.postsrsd.enable {
mode = "0660";
owner = config.services.postsrsd.user;
group = config.services.postsrsd.group;
};
"grafana/password" = mkIf config.services.grafana.enable {
mode = "0660";
owner = "grafana";
group = "grafana";
};
"grafana/client_secret" = mkIf config.services.grafana.enable {
mode = "0660";
owner = "grafana";
group = "grafana";
};
"prometheus/powerdns/password" = mkIf config.services.prometheus.enable {
mode = "0660";
owner = "prometheus";
group = config.users.users.prometheus.group;
};
"paperless/adminPassword" = mkIf config.services.paperless.enable {
owner = config.services.paperless.user;
};
"atticd/secret" = mkIf config.services.atticd.enable { };
};
};
}

View file

@ -0,0 +1,5 @@
{
imports = [
./sops-conf.nix
];
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,85 @@
{ config, lib, ... }:
let
inherit (lib) mkIf;
in
{
sops.secrets = {
"wireguard/privateKey" = { };
"nextcloud/adminPassword" = { };
"step_ca/password" = { };
vaultwarden = { };
"oauth/password" = { };
"oauth/adminEnv" = { };
"ldap/password" = lib.mkIf config.mail-server.enable {
mode = "0660";
owner = config.services.openldap.user;
group = config.services.openldap.group;
};
"ldap/env" = lib.mkIf config.mail-server.enable {
mode = "0660";
group = config.users.groups.docker.name;
};
"powerdns-admin/secret" = {
mode = "0660";
owner = "powerdnsadmin";
group = "powerdnsadmin";
};
"powerdns-admin/salt" = {
mode = "0660";
owner = "powerdnsadmin";
group = "powerdnsadmin";
};
powerdns = {
mode = "0660";
owner = "pdns";
group = "pdns";
};
rspamd-trainer = {
};
rspamd = mkIf config.services.rspamd.enable {
owner = config.services.rspamd.user;
};
"acme/env" = mkIf config.security.acme.acceptTerms {
mode = "0660";
owner = "acme";
group = "acme";
};
"postsrsd/secret" = mkIf config.services.postsrsd.enable {
mode = "0660";
owner = config.services.postsrsd.user;
group = config.services.postsrsd.group;
};
"grafana/password" = mkIf config.services.grafana.enable {
mode = "0660";
owner = "grafana";
group = "grafana";
};
"grafana/client_secret" = mkIf config.services.grafana.enable {
mode = "0660";
owner = "grafana";
group = "grafana";
};
"prometheus/powerdns/password" = mkIf config.services.prometheus.enable {
mode = "0660";
owner = "prometheus";
group = config.users.users.prometheus.group;
};
"paperless/adminPassword" = mkIf config.services.paperless.enable {
owner = config.services.paperless.user;
};
"atticd/secret" = mkIf config.services.atticd.enable { };
"docmost" = { };
"crowdsec/lapi.yaml" = mkIf config.services.crowdsec.enable {
owner = "crowdsec";
mode = "0600";
};
"crowdsec/capi.yaml" = mkIf config.services.crowdsec.enable {
owner = "crowdsec";
mode = "0600";
};
"crowdsec/consoleToken" = mkIf config.services.crowdsec.enable {
owner = "crowdsec";
mode = "0600";
};
};
}

View file

@ -0,0 +1,8 @@
{
imports = [
./boot.nix
./disk.nix
./nvidia.nix
./hardware-configuration.nix
];
}

View file

@ -0,0 +1,10 @@
{
imports = [
# Nvidia GPU Driver
(import ../../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:1:0:0";
})
];
}

View file

@ -1,151 +1,41 @@
{ hostname }:
{
username,
config,
lib,
pkgs,
...
}:
let
inherit (lib) optionalString;
geVersion = "10-15";
faceIcon = pkgs.fetchurl {
url = "https://files.net.dn/skydrive.jpg";
hash = "sha256-aMjl6VL1Zy+r3ElfFyhFOlJKWn42JOnAFfBXF+GPB/Q=";
curlOpts = "-k";
};
memeSelector = pkgs.callPackage ../../../home/scripts/memeSelector.nix {
url = "https://nextcloud.net.dn/public.php/dav/files/pygHoPB5LxDZbeY/";
};
monitors = [
"desc:AU Optronics 0x82ED"
"desc:AOC 24B30HM2 27ZQ4HA00101"
];
username = "skydrive";
in
{
imports = [
./hardware-configuration.nix
../../modules/presets/basic.nix
# Nvidia GPU Driver
(import ../../modules/nvidia.nix {
nvidia-mode = "offload";
intel-bus-id = "PCI:0:2:0";
nvidia-bus-id = "PCI:1:0:0";
})
./boot.nix # Extra Boot Options
./disk.nix
./sops-conf.nix
../../modules/printer.nix
../../modules/gaming.nix
../../modules/wine.nix
../../modules/localsend.nix
(import ../../modules/airplay.nix { hostname = config.networking.hostName; })
# (import ../../modules/virtualization.nix { inherit username; })
../../modules/wireguard.nix
];
home-manager = {
users."${username}" = {
imports = [
../../../home/presets/basic.nix
{
home.file.".face" = {
source = lib.mkForce faceIcon;
};
}
# Hyprland
(import ../../../home/user/hyprland.nix { inherit monitors; })
{
wayland.windowManager.hyprland = {
settings = {
input = {
kb_options = lib.mkForce [ ];
};
monitor = [
''desc:AU Optronics 0x82ED, prefered, 0x0, 1''
''desc:AOC 24B30HM2 27ZQ4HA00101, prefered, 1920x540, 1''
];
bind = [
"$mainMod ctrl, M, exec, ${memeSelector}/bin/memeSelector"
];
};
};
}
(import ../../../home/user/waybar.nix {
settings = [
# monitor 1
systemConf = {
inherit hostname username;
domain = "net.dn";
hyprland = {
enable = true;
monitors = [
{
desc = "AU Optronics 0x82ED";
props = "prefered, 0x0, 1";
output = "eDP-1";
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"custom/cava"
"mpris"
];
modules-right = [
"wlr/taskbar"
(optionalString config.programs.gamemode.enable "custom/gamemode")
"custom/airplay"
"custom/wallRand"
"custom/wireguard"
"custom/recording"
"idle_inhibitor"
"network"
"cpu"
"memory"
"pulseaudio"
"custom/swaync"
];
}
{
desc = "AOC 24B30HM2 27ZQ4HA00101";
props = "prefered, 1920x540, 1";
output = "HDMI-A-2";
modules-left = [
"clock"
"mpris"
];
modules-right = [
"wlr/taskbar"
"temperature"
"cpu"
"memory"
"pulseaudio"
];
}
];
})
];
home.file = {
# Proton GE
".steam/root/compatibilitytools.d/GE-Proton${geVersion}" = {
source = fetchTarball {
url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton${geVersion}/GE-Proton${geVersion}.tar.gz";
sha256 = "sha256:0iv7vak4a42b5m772gqr6wnarswib6dmybfcdjn3snvwxcb6hbsm";
};
};
".steam/root/compatibilitytools.d/CachyOS-Proton10-0_v3" = {
source = fetchTarball {
url = "https://github.com/CachyOS/proton-cachyos/releases/download/cachyos-10.0-20250714-slr/proton-cachyos-10.0-20250714-slr-x86_64_v3.tar.xz";
sha256 = "sha256:0hp22hkfv3f1p75im3xpif0pmixkq2i3hq3dhllzr2r7l1qx16iz";
};
};
};
};
};
environment.systemPackages = map lib.lowPrio [
pkgs.curl
pkgs.gitMinimal
memeSelector
imports = [
../../modules/presets/basic.nix
./common
./games
./services
./sops
./utility
];
users.users.root.openssh.authorizedKeys.keys = [

View file

@ -0,0 +1,6 @@
{
imports = [
../../../modules/gaming.nix
../../../modules/wine.nix
];
}

View file

@ -0,0 +1,118 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (config.systemConf) username;
inherit (lib) mkForce optionalString;
geVersion = "10-15";
memeSelector = pkgs.callPackage ../../../../home/scripts/memeSelector.nix {
url = "https://nextcloud.net.dn/public.php/dav/files/pygHoPB5LxDZbeY/";
};
faceIcon = pkgs.fetchurl {
url = "https://files.net.dn/skydrive.jpg";
hash = "sha256-aMjl6VL1Zy+r3ElfFyhFOlJKWn42JOnAFfBXF+GPB/Q=";
curlOpts = "-k";
};
in
{
environment.systemPackages = map lib.lowPrio [
pkgs.curl
pkgs.gitMinimal
memeSelector
];
home-manager = {
users."${username}" = {
imports = [
../../../../home/presets/basic.nix
{
home.file.".face" = {
source = mkForce faceIcon;
};
}
{
wayland.windowManager.hyprland = {
settings = {
input = {
kb_options = lib.mkForce [ ];
};
bind = [
"$mainMod ctrl, M, exec, ${memeSelector}/bin/memeSelector"
];
};
};
}
(import ../../../../home/user/waybar.nix {
settings = [
# monitor 1
{
output = "eDP-1";
modules-left = [
"custom/os"
"hyprland/workspaces"
"clock"
"custom/cava"
"mpris"
];
modules-right = [
"wlr/taskbar"
(optionalString config.programs.gamemode.enable "custom/gamemode")
"custom/airplay"
"custom/wallRand"
"custom/wireguard"
"custom/recording"
"idle_inhibitor"
"network"
"cpu"
"memory"
"pulseaudio"
"custom/swaync"
];
}
{
output = "HDMI-A-2";
modules-left = [
"clock"
"mpris"
];
modules-right = [
"wlr/taskbar"
"temperature"
"cpu"
"memory"
"pulseaudio"
];
}
];
})
];
home.file = {
# Proton GE
".steam/root/compatibilitytools.d/GE-Proton${geVersion}" = {
source = fetchTarball {
url = "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/GE-Proton${geVersion}/GE-Proton${geVersion}.tar.gz";
sha256 = "sha256:0iv7vak4a42b5m772gqr6wnarswib6dmybfcdjn3snvwxcb6hbsm";
};
};
".steam/root/compatibilitytools.d/CachyOS-Proton10-0_v3" = {
source = fetchTarball {
url = "https://github.com/CachyOS/proton-cachyos/releases/download/cachyos-10.0-20250714-slr/proton-cachyos-10.0-20250714-slr-x86_64_v3.tar.xz";
sha256 = "sha256:0hp22hkfv3f1p75im3xpif0pmixkq2i3hq3dhllzr2r7l1qx16iz";
};
};
};
};
};
}

View file

@ -0,0 +1,5 @@
{
imports = [
./wireguard.nix
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
../../../modules/wireguard.nix
];
}

View file

@ -0,0 +1,5 @@
{
imports = [
./sops-conf.nix
];
}

View file

@ -0,0 +1,8 @@
{ config, ... }:
{
imports = [
../../../modules/printer.nix
../../../modules/localsend.nix
(import ../../../modules/airplay.nix { hostname = config.networking.hostName; })
];
}

View file

@ -0,0 +1,99 @@
{
lapiCred,
capiCred,
consoleToken,
trusted_ips ? [ ],
extraAcq ? [ ],
extraJournal ? [ ],
enableServer ? false,
enablePrometheus ? true,
}:
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkDefault mkIf;
mkJournalFilter = service: {
journalctl_filter = [
"_SYSTEMD_UNIT=${service}"
];
labels = {
type = "syslog";
};
source = "journalctl";
};
# ==== Default Services ==== #
services = map (x: mkJournalFilter x) [
"sshd.service"
];
extraServices = map (x: mkJournalFilter x) extraJournal;
in
{
services.postgresql = {
enable = mkDefault true;
ensureDatabases = [ config.services.crowdsec.user ];
ensureUsers = [
{
name = config.services.crowdsec.user;
ensureDBOwnership = true;
}
];
};
services.crowdsec = {
enable = true;
settings.general = {
prometheus = {
enabled = enablePrometheus;
};
db_config = {
type = "postgresql";
db_name = config.services.crowdsec.user;
db_path = "/var/run/postgresql";
user = config.services.crowdsec.user;
sslmode = "disable";
flush.max_items = 5000;
flush.max_age = "7d";
};
api.client = {
insecure_skip_verify = false;
};
api.server = mkIf enableServer {
enable = true;
listen_uri = "127.0.0.1:31005";
trusted_ips = [
"127.0.0.1"
"10.0.0.0/24"
"::1"
]
++ trusted_ips;
};
};
settings = {
lapi.credentialsFile = lapiCred;
capi.credentialsFile = capiCred;
console.tokenFile = consoleToken;
};
localConfig = {
acquisitions = services ++ extraServices ++ extraAcq;
};
hub = {
scenarios = [
"crowdsecurity/ssh-bf"
"crowdsecurity/ssh-generic-test"
"crowdsecurity/http-generic-test"
];
postOverflows = [ "crowdsecurity/auditd-nix-wrappers-whitelist-process" ];
parsers = [ "crowdsecurity/sshd-logs" ];
collections = [ "crowdsecurity/linux" ];
appSecRules = [ "crowdsecurity/base-config" ];
appSecConfigs = [ "crowdsecurity/appsec-default" ];
};
autoUpdateService = true;
};
}

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