tab 替换为空格

This commit is contained in:
2023-09-01 21:05:26 +08:00
parent 0d46532922
commit 3e029b25a5
33 changed files with 4764 additions and 4768 deletions

1344
flake.nix

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +1,35 @@
lib:
{
attrsToList = Attrs: builtins.map ( name: { inherit name; value = Attrs.${name}; } ) ( builtins.attrNames Attrs );
mkConditional = condition: trueResult: falseResult: let inherit (lib) mkMerge mkIf; in
mkMerge [ ( mkIf condition trueResult ) ( mkIf (!condition) falseResult ) ];
attrsToList = Attrs: builtins.map ( name: { inherit name; value = Attrs.${name}; } ) ( builtins.attrNames Attrs );
mkConditional = condition: trueResult: falseResult: let inherit (lib) mkMerge mkIf; in
mkMerge [ ( mkIf condition trueResult ) ( mkIf (!condition) falseResult ) ];
# Behaviors of these two NixOS modules would be different:
# { pkgs, ... }@inputs: { environment.systemPackages = [ pkgs.hello ]; }
# inputs: { environment.systemPackages = [ pkgs.hello ]; }
# The second one would failed to evaluate because nixpkgs would not pass pkgs to it.
# So that we wrote a wrapper to make it always works like the first one.
mkModules = moduleList:
(builtins.map
(
let handle = module:
if ( builtins.typeOf module ) == "path" then (handle (import module))
else if ( builtins.typeOf module ) == "lambda" then ({ pkgs, utils, ... }@inputs: (module inputs))
else module;
in handle
)
moduleList);
# Behaviors of these two NixOS modules would be different:
# { pkgs, ... }@inputs: { environment.systemPackages = [ pkgs.hello ]; }
# inputs: { environment.systemPackages = [ pkgs.hello ]; }
# The second one would failed to evaluate because nixpkgs would not pass pkgs to it.
# So that we wrote a wrapper to make it always works like the first one.
mkModules = moduleList:
(builtins.map
(
let handle = module:
if ( builtins.typeOf module ) == "path" then (handle (import module))
else if ( builtins.typeOf module ) == "lambda" then ({ pkgs, utils, ... }@inputs: (module inputs))
else module;
in handle
)
moduleList);
# from: https://github.com/NixOS/nix/issues/3759
stripeTabs = text:
let
# Whether all lines start with a tab (or is empty)
shouldStripTab = lines: builtins.all (line: (line == "") || (lib.strings.hasPrefix " " line)) lines;
# Strip a leading tab from all lines
stripTab = lines: builtins.map (line: lib.strings.removePrefix " " line) lines;
# Strip tabs recursively until there are none
stripTabs = lines: if (shouldStripTab lines) then (stripTabs (stripTab lines)) else lines;
in
# Split into lines. Strip leading tabs. Concat back to string.
builtins.concatStringsSep "\n" (stripTabs (lib.strings.splitString "\n" text));
# from: https://github.com/NixOS/nix/issues/3759
stripeTabs = text:
let
# Whether all lines start with a tab (or is empty)
shouldStripTab = lines: builtins.all (line: (line == "") || (lib.strings.hasPrefix " " line)) lines;
# Strip a leading tab from all lines
stripTab = lines: builtins.map (line: lib.strings.removePrefix " " line) lines;
# Strip tabs recursively until there are none
stripTabs = lines: if (shouldStripTab lines) then (stripTabs (stripTab lines)) else lines;
in
# Split into lines. Strip leading tabs. Concat back to string.
builtins.concatStringsSep "\n" (stripTabs (lib.strings.splitString "\n" text));
}

View File

@@ -1,12 +1,12 @@
{ lib, pkgs }: with pkgs;
{
typora = callPackage ./typora {};
upho = python3Packages.callPackage ./upho {};
spectral = python3Packages.callPackage ./spectral {};
vesta = callPackage ./vesta {};
oneapi = callPackage ./oneapi {};
send = callPackage ./send {};
rsshub = callPackage ./rsshub {};
misskey = callPackage ./misskey {};
mk-meili-mgn = callPackage ./mk-meili-mgn {};
typora = callPackage ./typora {};
upho = python3Packages.callPackage ./upho {};
spectral = python3Packages.callPackage ./spectral {};
vesta = callPackage ./vesta {};
oneapi = callPackage ./oneapi {};
send = callPackage ./send {};
rsshub = callPackage ./rsshub {};
misskey = callPackage ./misskey {};
mk-meili-mgn = callPackage ./mk-meili-mgn {};
}

View File

@@ -1,70 +1,70 @@
{
lib, stdenv, mkPnpmPackage, fetchFromGitHub, nodejs_20, writeShellScript, buildFHSEnv,
bash, cypress, vips, pkg-config
lib, stdenv, mkPnpmPackage, fetchFromGitHub, nodejs_20, writeShellScript, buildFHSEnv,
bash, cypress, vips, pkg-config
}:
let
pname = "misskey";
version = "13.14.2";
pname = "misskey";
version = "13.14.2";
src = fetchFromGitHub
{
owner = "CHN-beta";
repo = "misskey";
rev = "e02ecb3819f6f05352d43b64ae59fa1bd683e2e0";
hash = "sha256-zsYM67LYUn+bI6kbdW9blftxw5TUxCdzlfaOOEgZz+Q=";
fetchSubmodules = true;
};
originalPnpmPackage = mkPnpmPackage
{
inherit pname version src;
nodejs = nodejs_20;
copyPnpmStore = true;
};
startScript = writeShellScript "misskey"
''
export PATH=${lib.makeBinPath [ bash nodejs_20 nodejs_20.pkgs.pnpm nodejs_20.pkgs.gulp cypress ]}:$PATH
export CYPRESS_RUN_BINARY="${cypress}/bin/Cypress"
export NODE_ENV=production
pnpm run migrateandstart
'';
{
owner = "CHN-beta";
repo = "misskey";
rev = "e02ecb3819f6f05352d43b64ae59fa1bd683e2e0";
hash = "sha256-zsYM67LYUn+bI6kbdW9blftxw5TUxCdzlfaOOEgZz+Q=";
fetchSubmodules = true;
};
originalPnpmPackage = mkPnpmPackage
{
inherit pname version src;
nodejs = nodejs_20;
copyPnpmStore = true;
};
startScript = writeShellScript "misskey"
''
export PATH=${lib.makeBinPath [ bash nodejs_20 nodejs_20.pkgs.pnpm nodejs_20.pkgs.gulp cypress ]}:$PATH
export CYPRESS_RUN_BINARY="${cypress}/bin/Cypress"
export NODE_ENV=production
pnpm run migrateandstart
'';
in
stdenv.mkDerivation
{
inherit version src pname;
nativeBuildInputs =
[ bash nodejs_20 nodejs_20.pkgs.typescript nodejs_20.pkgs.pnpm nodejs_20.pkgs.gulp cypress vips pkg-config ];
CYPRESS_RUN_BINARY = "${cypress}/bin/Cypress";
NODE_ENV = "production";
configurePhase =
''
export HOME=$NIX_BUILD_TOP # Some packages need a writable HOME
export npm_config_nodedir=${nodejs_20}
stdenv.mkDerivation
{
inherit version src pname;
nativeBuildInputs =
[ bash nodejs_20 nodejs_20.pkgs.typescript nodejs_20.pkgs.pnpm nodejs_20.pkgs.gulp cypress vips pkg-config ];
CYPRESS_RUN_BINARY = "${cypress}/bin/Cypress";
NODE_ENV = "production";
configurePhase =
''
export HOME=$NIX_BUILD_TOP # Some packages need a writable HOME
export npm_config_nodedir=${nodejs_20}
runHook preConfigure
runHook preConfigure
store=$(pnpm store path)
mkdir -p $(dirname $store)
store=$(pnpm store path)
mkdir -p $(dirname $store)
cp -f ${originalPnpmPackage.passthru.patchedLockfileYaml} pnpm-lock.yaml
cp -RL ${originalPnpmPackage.passthru.pnpmStore} $store
chmod -R +w $store
pnpm install --frozen-lockfile --offline
cp -f ${originalPnpmPackage.passthru.patchedLockfileYaml} pnpm-lock.yaml
cp -RL ${originalPnpmPackage.passthru.pnpmStore} $store
chmod -R +w $store
pnpm install --frozen-lockfile --offline
runHook postConfigure
'';
buildPhase =
''
runHook preBuild
pnpm run build
runHook postBuild
'';
installPhase =
''
runHook preInstall
mkdir -p $out
mv * .* $out
mkdir -p $out/bin
cp ${startScript} $out/bin/misskey
mkdir -p $out/files
runHook postInstall
'';
}
runHook postConfigure
'';
buildPhase =
''
runHook preBuild
pnpm run build
runHook postBuild
'';
installPhase =
''
runHook preInstall
mkdir -p $out
mv * .* $out
mkdir -p $out/bin
cp ${startScript} $out/bin/misskey
mkdir -p $out/files
runHook postInstall
'';
}

View File

@@ -1,16 +1,16 @@
{ lib, fetchFromGitHub, rustPlatform, pkg-config, openssl }:
rustPlatform.buildRustPackage rec
{
pname = "mk-meili-mgn";
version = "20230827";
src = fetchFromGitHub
{
owner = "CHN-beta";
repo = "mk-meili-mgn";
rev = "53e282c992293ec735c9bc964f097b5bdbc3e48a";
hash = "sha256-KBSoEGfWKDXZHSzSzak1v0nxtQQGI15DQTyNAPhsIB4=";
};
cargoHash = "sha256-wNdMPPl2H2iSrNYjoij0Qg/c2S5RjTHpOMV1RfHU27g=";
nativeBuildInputs = [ pkg-config ];
buildInputs = [ openssl ];
pname = "mk-meili-mgn";
version = "20230827";
src = fetchFromGitHub
{
owner = "CHN-beta";
repo = "mk-meili-mgn";
rev = "53e282c992293ec735c9bc964f097b5bdbc3e48a";
hash = "sha256-KBSoEGfWKDXZHSzSzak1v0nxtQQGI15DQTyNAPhsIB4=";
};
cargoHash = "sha256-wNdMPPl2H2iSrNYjoij0Qg/c2S5RjTHpOMV1RfHU27g=";
nativeBuildInputs = [ pkg-config ];
buildInputs = [ openssl ];
}

View File

@@ -1,58 +1,58 @@
{
lib, stdenv, mkPnpmPackage, fetchFromGitHub, nodejs, writeShellScript,
chromium, bash
lib, stdenv, mkPnpmPackage, fetchFromGitHub, nodejs, writeShellScript,
chromium, bash
}:
let
pname = "rsshub";
version = "20230829";
pname = "rsshub";
version = "20230829";
src = fetchFromGitHub
{
owner = "DIYgod";
repo = "RSSHub";
rev = "afcf9774260dc6505263cf0428970e890f2f7b1d";
hash = "sha256-BQFE0Z5DsFTf0tylQ0NN89hCdXT/Y2M+YPa/10ccOVg=";
};
originalPnpmPackage = mkPnpmPackage { inherit pname version src nodejs; };
nodeModules = originalPnpmPackage.nodeModules.overrideAttrs { PUPPETEER_SKIP_DOWNLOAD = true; };
rsshub-unwrapped = stdenv.mkDerivation
{
inherit version src;
pname = "${pname}-unwrapped";
configurePhase =
''
export HOME=$NIX_BUILD_TOP # Some packages need a writable HOME
export npm_config_nodedir=${nodejs}
{
owner = "DIYgod";
repo = "RSSHub";
rev = "afcf9774260dc6505263cf0428970e890f2f7b1d";
hash = "sha256-BQFE0Z5DsFTf0tylQ0NN89hCdXT/Y2M+YPa/10ccOVg=";
};
originalPnpmPackage = mkPnpmPackage { inherit pname version src nodejs; };
nodeModules = originalPnpmPackage.nodeModules.overrideAttrs { PUPPETEER_SKIP_DOWNLOAD = true; };
rsshub-unwrapped = stdenv.mkDerivation
{
inherit version src;
pname = "${pname}-unwrapped";
configurePhase =
''
export HOME=$NIX_BUILD_TOP # Some packages need a writable HOME
export npm_config_nodedir=${nodejs}
runHook preConfigure
runHook preConfigure
ln -s ${nodeModules}/. node_modules
ln -s ${nodeModules}/. node_modules
runHook postConfigure
'';
installPhase =
''
runHook preInstall
mkdir -p $out
mv * .* $out
runHook postInstall
'';
};
startScript = writeShellScript "rsshub"
''
cd ${rsshub-unwrapped}
export PATH=${lib.makeBinPath [ bash nodejs nodejs.pkgs.pnpm chromium ]}:$PATH
export CHROMIUM_EXECUTABLE_PATH=chromium
pnpm start
'';
runHook postConfigure
'';
installPhase =
''
runHook preInstall
mkdir -p $out
mv * .* $out
runHook postInstall
'';
};
startScript = writeShellScript "rsshub"
''
cd ${rsshub-unwrapped}
export PATH=${lib.makeBinPath [ bash nodejs nodejs.pkgs.pnpm chromium ]}:$PATH
export CHROMIUM_EXECUTABLE_PATH=chromium
pnpm start
'';
in stdenv.mkDerivation rec
{
inherit pname version;
phases = [ "installPhase" ];
installPhase =
''
runHook preInstall
mkdir -p $out/bin
cp ${startScript} $out/bin/rsshub
runHook postInstall
'';
inherit pname version;
phases = [ "installPhase" ];
installPhase =
''
runHook preInstall
mkdir -p $out/bin
cp ${startScript} $out/bin/rsshub
runHook postInstall
'';
}

View File

@@ -1,15 +1,15 @@
{
lib, fetchPypi, buildPythonPackage,
numpy, pillow, wxPython_4_2, matplotlib, ipython, pyopengl
lib, fetchPypi, buildPythonPackage,
numpy, pillow, wxPython_4_2, matplotlib, ipython, pyopengl
}: buildPythonPackage rec
{
pname = "spectral";
version = "0.23.1";
src = fetchPypi
{
inherit pname version;
sha256 = "sha256-4YIic1Je81g7J6lmIm1Vr+CefSmnI2z82LwN+x+Wj8I=";
};
doCheck = false;
propagatedBuildInputs = [ numpy pillow wxPython_4_2 matplotlib ipython pyopengl ];
pname = "spectral";
version = "0.23.1";
src = fetchPypi
{
inherit pname version;
sha256 = "sha256-4YIic1Je81g7J6lmIm1Vr+CefSmnI2z82LwN+x+Wj8I=";
};
doCheck = false;
propagatedBuildInputs = [ numpy pillow wxPython_4_2 matplotlib ipython pyopengl ];
}

View File

@@ -1,42 +1,42 @@
{ lib, stdenv, steam-run, fetchurl, writeShellScript }:
let
typora-dist = stdenv.mkDerivation rec
{
pname = "typora-dist";
version = "1.6.6";
src = fetchurl
{
url = "https://download.typora.io/linux/typora_${version}_amd64.deb";
sha256 = "sha256-77mCgmsROLhfuOmOOyl2C5Ug2NfqEvcD+kMA3aiAQtA=";
};
typora-dist = stdenv.mkDerivation rec
{
pname = "typora-dist";
version = "1.6.6";
src = fetchurl
{
url = "https://download.typora.io/linux/typora_${version}_amd64.deb";
sha256 = "sha256-77mCgmsROLhfuOmOOyl2C5Ug2NfqEvcD+kMA3aiAQtA=";
};
dontFixup = true;
dontFixup = true;
unpackPhase =
''
ar x ${src}
tar xf data.tar.xz
'';
installPhase =
''
mkdir -p $out
mv usr/share $out
'';
};
unpackPhase =
''
ar x ${src}
tar xf data.tar.xz
'';
installPhase =
''
mkdir -p $out
mv usr/share $out
'';
};
in stdenv.mkDerivation rec
{
pname = "typora";
inherit (typora-dist) version;
BuildInputs = [ typora-dist steam-run ];
startScript = writeShellScript "typora" "${steam-run}/bin/steam-run ${typora-dist}/share/typora/Typora $@";
phases = [ "installPhase" ];
installPhase =
''
mkdir -p $out/bin $out/share/applications
ln -s ${startScript} $out/bin/typora
cp ${typora-dist}/share/applications/typora.desktop $out/share/applications
sed -i "s|Exec=.*|Exec=${startScript} %U|g" $out/share/applications/typora.desktop
sed -i "s|Icon=.*|Icon=${typora-dist}/share/icons/hicolor/256x256/apps/typora.png|g" \
$out/share/applications/typora.desktop
'';
pname = "typora";
inherit (typora-dist) version;
BuildInputs = [ typora-dist steam-run ];
startScript = writeShellScript "typora" "${steam-run}/bin/steam-run ${typora-dist}/share/typora/Typora $@";
phases = [ "installPhase" ];
installPhase =
''
mkdir -p $out/bin $out/share/applications
ln -s ${startScript} $out/bin/typora
cp ${typora-dist}/share/applications/typora.desktop $out/share/applications
sed -i "s|Exec=.*|Exec=${startScript} %U|g" $out/share/applications/typora.desktop
sed -i "s|Icon=.*|Icon=${typora-dist}/share/icons/hicolor/256x256/apps/typora.png|g" \
$out/share/applications/typora.desktop
'';
}

View File

@@ -1,14 +1,14 @@
{ lib, fetchFromGitHub, buildPythonPackage, numpy, h5py, phonopy }: buildPythonPackage rec
{
pname = "upho";
version = "0.6.6";
src = fetchFromGitHub
{
owner = "CHN-beta";
repo = "upho";
rev = "0f27ac6918e8972c70692816438e4ac37ec6b348";
sha256 = "sha256-NvoV+AUH9MmGT4ohrLAAvpLs8APP2DOKYlZVliHrVRM=";
};
doCheck = false;
propagatedBuildInputs = [ numpy h5py phonopy ];
pname = "upho";
version = "0.6.6";
src = fetchFromGitHub
{
owner = "CHN-beta";
repo = "upho";
rev = "0f27ac6918e8972c70692816438e4ac37ec6b348";
sha256 = "sha256-NvoV+AUH9MmGT4ohrLAAvpLs8APP2DOKYlZVliHrVRM=";
};
doCheck = false;
propagatedBuildInputs = [ numpy h5py phonopy ];
}

View File

@@ -1,49 +1,48 @@
{
lib, stdenv, fetchurl, autoPatchelfHook, wrapGAppsHook,
glib, gtk2, xorg, libGLU, gtk3, writeShellScript, gsettings-desktop-schemas, xdg-utils
lib, stdenv, fetchurl, autoPatchelfHook, wrapGAppsHook,
glib, gtk2, xorg, libGLU, gtk3, writeShellScript, gsettings-desktop-schemas, xdg-utils
}:
stdenv.mkDerivation rec
{
pname = "vesta";
version = "3.5.5";
src = fetchurl
{
url = "https://jp-minerals.org/vesta/archives/${version}/VESTA-gtk3.tar.bz2";
sha256 = "sRzQNJA7+hsjLWmykqe6bH0p1/aGEB8hCuxCyPzxYHs=";
};
desktopFile = fetchurl
{
url = "https://aur.archlinux.org/cgit/aur.git/plain/VESTA.desktop?h=vesta&id=4fae08afc37ee0fd88d14328cf0d6b308fea04d1";
sha256 = "Tq4AzQgde2KIWKA1k6JlxvdphGG9JluHMZjVw0fBUeQ=";
};
pname = "vesta";
version = "3.5.5";
src = fetchurl
{
url = "https://jp-minerals.org/vesta/archives/${version}/VESTA-gtk3.tar.bz2";
sha256 = "sRzQNJA7+hsjLWmykqe6bH0p1/aGEB8hCuxCyPzxYHs=";
};
desktopFile = fetchurl
{
url = "https://aur.archlinux.org/cgit/aur.git/plain/VESTA.desktop?h=vesta&id=4fae08afc37ee0fd88d14328cf0d6b308fea04d1";
sha256 = "Tq4AzQgde2KIWKA1k6JlxvdphGG9JluHMZjVw0fBUeQ=";
};
nativeBuildInputs = [ autoPatchelfHook wrapGAppsHook ];
buildInputs = [ glib gtk2 xorg.libXxf86vm libGLU gtk3 xorg.libXtst ];
nativeBuildInputs = [ autoPatchelfHook wrapGAppsHook ];
buildInputs = [ glib gtk2 xorg.libXxf86vm libGLU gtk3 xorg.libXtst ];
unpackPhase = "tar -xf ${src}";
unpackPhase = "tar -xf ${src}";
installPhase =
# Note '<<-' here, it strips tabs before EOF. It doesn't work with spaces
''
echo $out
mkdir -p $out/share/applications
cp ${desktopFile} $out/share/applications/vesta.desktop
sed -i "s|Exec=.*|Exec=$out/bin/vesta|" $out/share/applications/vesta.desktop
sed -i "s|Icon=.*|Icon=$out/opt/VESTA-gtk3/img/logo.png|" $out/share/applications/vesta.desktop
installPhase =
''
echo $out
mkdir -p $out/share/applications
cp ${desktopFile} $out/share/applications/vesta.desktop
sed -i "s|Exec=.*|Exec=$out/bin/vesta|" $out/share/applications/vesta.desktop
sed -i "s|Icon=.*|Icon=$out/opt/VESTA-gtk3/img/logo.png|" $out/share/applications/vesta.desktop
mkdir -p $out/opt
cp -r VESTA-gtk3 $out/opt/VESTA-gtk3
mkdir -p $out/opt
cp -r VESTA-gtk3 $out/opt/VESTA-gtk3
mkdir -p $out/bin
tee $out/bin/vesta <<- EOF
#!${stdenv.shell}
export XDG_DATA_DIRS=$GSETTINGS_SCHEMAS_PATH\''${XDG_DATA_DIRS:+:}\$XDG_DATA_DIRS
export PATH="\$PATH\''${PATH:+:}${xdg-utils}/bin"
$out/opt/VESTA-gtk3/VESTA "\$@"
EOF
chmod +x $out/bin/vesta
mkdir -p $out/bin
tee $out/bin/vesta << EOF
#!${stdenv.shell}
export XDG_DATA_DIRS=$GSETTINGS_SCHEMAS_PATH\''${XDG_DATA_DIRS:+:}\$XDG_DATA_DIRS
export PATH="\$PATH\''${PATH:+:}${xdg-utils}/bin"
$out/opt/VESTA-gtk3/VESTA "\$@"
EOF
chmod +x $out/bin/vesta
patchelf --remove-needed libjawt.so $out/opt/VESTA-gtk3/PowderPlot/libswt-awt-gtk-3346.so
'';
patchelf --remove-needed libjawt.so $out/opt/VESTA-gtk3/PowderPlot/libswt-awt-gtk-3346.so
'';
}

View File

@@ -1,84 +1,84 @@
inputs:
{
options.nixos.boot = let inherit (inputs.lib) mkOption types; in
{
grub =
{
timeout = mkOption { type = types.int; default = 5; };
windowsEntries = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
# "efi" using efi, "efiRemovable" using efi with install grub removable, or dev path like "/dev/sda" using bios
installDevice = mkOption { type = types.str; };
};
network.enable = mkOption { type = types.bool; default = false; };
sshd =
{
enable = mkOption { type = types.bool; default = false; };
hostKeys = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) mkConditional attrsToList stripeTabs;
inherit (inputs.config.nixos) boot;
inherit (builtins) concatStringsSep map;
in mkMerge
[
# generic
{
boot =
{
loader.grub = { enable = true; useOSProber = false; };
initrd.systemd.enable = true;
};
}
# grub.timeout
{ boot.loader.timeout = boot.grub.timeout; }
# grub.windowsEntries
{
boot.loader.grub.extraEntries = concatStringsSep "" (map (system: stripeTabs
''
menuentry "${system.value}" {
insmod part_gpt
insmod fat
insmod search_fs_uuid
insmod chain
search --fs-uuid --set=root ${system.name}
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
'') (attrsToList boot.grub.windowsEntries));
}
# grub.installDevice
(
mkConditional (boot.grub.installDevice == "efi" || boot.grub.installDevice == "efiRemovable")
(
mkConditional (boot.grub.installDevice == "efi")
{
boot.loader =
{
efi = { canTouchEfiVariables = true; efiSysMountPoint = "/boot/efi"; };
grub = { device = "nodev"; efiSupport = true; };
};
}
{
boot.loader =
{
efi.efiSysMountPoint = "/boot/efi";
grub = { device = "nodev"; efiSupport = true; efiInstallAsRemovable = true; };
};
}
)
{ boot.loader.grub.device = boot.grub.installDevice; }
)
# network
(
mkIf boot.network.enable
{ boot = { initrd.network.enable = true; kernelParams = [ "ip=dhcp" ]; }; }
)
# sshd
(
mkIf boot.sshd.enable
{ boot.initrd.network.ssh = { enable = true; hostKeys = boot.sshd.hostKeys; };}
)
];
options.nixos.boot = let inherit (inputs.lib) mkOption types; in
{
grub =
{
timeout = mkOption { type = types.int; default = 5; };
windowsEntries = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
# "efi" using efi, "efiRemovable" using efi with install grub removable, or dev path like "/dev/sda" using bios
installDevice = mkOption { type = types.str; };
};
network.enable = mkOption { type = types.bool; default = false; };
sshd =
{
enable = mkOption { type = types.bool; default = false; };
hostKeys = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) mkConditional attrsToList stripeTabs;
inherit (inputs.config.nixos) boot;
inherit (builtins) concatStringsSep map;
in mkMerge
[
# generic
{
boot =
{
loader.grub = { enable = true; useOSProber = false; };
initrd.systemd.enable = true;
};
}
# grub.timeout
{ boot.loader.timeout = boot.grub.timeout; }
# grub.windowsEntries
{
boot.loader.grub.extraEntries = concatStringsSep "" (map (system: stripeTabs
''
menuentry "${system.value}" {
insmod part_gpt
insmod fat
insmod search_fs_uuid
insmod chain
search --fs-uuid --set=root ${system.name}
chainloader /EFI/Microsoft/Boot/bootmgfw.efi
}
'') (attrsToList boot.grub.windowsEntries));
}
# grub.installDevice
(
mkConditional (boot.grub.installDevice == "efi" || boot.grub.installDevice == "efiRemovable")
(
mkConditional (boot.grub.installDevice == "efi")
{
boot.loader =
{
efi = { canTouchEfiVariables = true; efiSysMountPoint = "/boot/efi"; };
grub = { device = "nodev"; efiSupport = true; };
};
}
{
boot.loader =
{
efi.efiSysMountPoint = "/boot/efi";
grub = { device = "nodev"; efiSupport = true; efiInstallAsRemovable = true; };
};
}
)
{ boot.loader.grub.device = boot.grub.installDevice; }
)
# network
(
mkIf boot.network.enable
{ boot = { initrd.network.enable = true; kernelParams = [ "ip=dhcp" ]; }; }
)
# sshd
(
mkIf boot.sshd.enable
{ boot.initrd.network.ssh = { enable = true; hostKeys = boot.sshd.hostKeys; };}
)
];
}

View File

@@ -1,87 +1,87 @@
inputs:
let
inherit (inputs.localLib) stripeTabs;
inherit (builtins) map attrNames;
inherit (inputs.lib) mkMerge mkIf mkOption types;
bugs =
{
# intel i915 hdmi
intel-hdmi.boot.kernelPatches = [{ name = "intel-hdmi"; patch = ./intel-hdmi.patch; }];
# suspend & hibernate do not use platform
suspend-hibernate-no-platform.systemd.sleep.extraConfig = stripeTabs
"
SuspendState=freeze
HibernateMode=shutdown
";
# reload iwlwifi after resume from hibernate
hibernate-iwlwifi.systemd.services.reload-iwlwifi-after-hibernate =
{
description = "reload iwlwifi after resume from hibernate";
after = [ "systemd-hibernate.service" ];
serviceConfig.Type = "oneshot";
script = let modprobe = "${inputs.pkgs.kmod}/bin/modprobe"; in stripeTabs
"
${modprobe} -r iwlwifi
${modprobe} iwlwifi
echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
";
wantedBy = [ "systemd-hibernate.service" ];
};
# disable wakeup on lid open
suspend-lid-no-wakeup.systemd.services.lid-no-wakeup =
{
description = "lid no wake up";
serviceConfig.Type = "oneshot";
script =
let
cat = "${inputs.pkgs.coreutils}/bin/cat";
grep = "${inputs.pkgs.gnugrep}/bin/grep";
in stripeTabs
"
if ${cat} /proc/acpi/wakeup | ${grep} LID0 | ${grep} -q enabled
then
echo LID0 > /proc/acpi/wakeup
fi
";
wantedBy = [ "multi-user.target" ];
};
# xmunet use old encryption
xmunet.nixpkgs.config.packageOverrides = pkgs:
{
wpa_supplicant = pkgs.wpa_supplicant.overrideAttrs (attrs: { patches = attrs.patches ++ [ ./xmunet.patch ];});
};
suspend-hibernate-waydroid.systemd.services =
let
systemctl = "${inputs.pkgs.systemd}/bin/systemctl";
in
{
"waydroid-hibernate" =
{
description = "waydroid hibernate";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
before = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig.Type = "oneshot";
script = "${systemctl} stop waydroid-container";
};
"waydroid-resume" =
{
description = "waydroid resume";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
after = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig.Type = "oneshot";
script = "${systemctl} start waydroid-container";
};
};
firefox.programs.firefox.enable = inputs.lib.mkForce false;
embree.nixpkgs.overlays =
[(final: prev: { embree = prev.embree.override { stdenv = final.genericPackages.stdenv; }; })];
};
in
{
options.nixos.bugs = mkOption
{
type = types.listOf (types.enum (attrNames bugs));
default = [];
};
config = mkMerge (map (bug: mkIf (builtins.elem bug inputs.config.nixos.bugs) bugs.${bug}) (attrNames bugs));
}
let
inherit (inputs.localLib) stripeTabs;
inherit (builtins) map attrNames;
inherit (inputs.lib) mkMerge mkIf mkOption types;
bugs =
{
# intel i915 hdmi
intel-hdmi.boot.kernelPatches = [{ name = "intel-hdmi"; patch = ./intel-hdmi.patch; }];
# suspend & hibernate do not use platform
suspend-hibernate-no-platform.systemd.sleep.extraConfig =
''
SuspendState=freeze
HibernateMode=shutdown
'';
# reload iwlwifi after resume from hibernate
hibernate-iwlwifi.systemd.services.reload-iwlwifi-after-hibernate =
{
description = "reload iwlwifi after resume from hibernate";
after = [ "systemd-hibernate.service" ];
serviceConfig.Type = "oneshot";
script = let modprobe = "${inputs.pkgs.kmod}/bin/modprobe"; in
''
${modprobe} -r iwlwifi
${modprobe} iwlwifi
echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo
'';
wantedBy = [ "systemd-hibernate.service" ];
};
# disable wakeup on lid open
suspend-lid-no-wakeup.systemd.services.lid-no-wakeup =
{
description = "lid no wake up";
serviceConfig.Type = "oneshot";
script =
let
cat = "${inputs.pkgs.coreutils}/bin/cat";
grep = "${inputs.pkgs.gnugrep}/bin/grep";
in
''
if ${cat} /proc/acpi/wakeup | ${grep} LID0 | ${grep} -q enabled
then
echo LID0 > /proc/acpi/wakeup
fi
'';
wantedBy = [ "multi-user.target" ];
};
# xmunet use old encryption
xmunet.nixpkgs.config.packageOverrides = pkgs:
{
wpa_supplicant = pkgs.wpa_supplicant.overrideAttrs (attrs: { patches = attrs.patches ++ [ ./xmunet.patch ];});
};
suspend-hibernate-waydroid.systemd.services =
let
systemctl = "${inputs.pkgs.systemd}/bin/systemctl";
in
{
"waydroid-hibernate" =
{
description = "waydroid hibernate";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
before = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig.Type = "oneshot";
script = "${systemctl} stop waydroid-container";
};
"waydroid-resume" =
{
description = "waydroid resume";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
after = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig.Type = "oneshot";
script = "${systemctl} start waydroid-container";
};
};
firefox.programs.firefox.enable = inputs.lib.mkForce false;
embree.nixpkgs.overlays =
[(final: prev: { embree = prev.embree.override { stdenv = final.genericPackages.stdenv; }; })];
};
in
{
options.nixos.bugs = mkOption
{
type = types.listOf (types.enum (attrNames bugs));
default = [];
};
config = mkMerge (map (bug: mkIf (builtins.elem bug inputs.config.nixos.bugs) bugs.${bug}) (attrNames bugs));
}

View File

@@ -1,35 +1,35 @@
inputs:
let
inherit (inputs) topInputs;
inherit (inputs.localLib) mkModules;
in
{
imports = mkModules
[
topInputs.home-manager.nixosModules.home-manager
topInputs.sops-nix.nixosModules.sops
topInputs.aagl.nixosModules.default
topInputs.nix-index-database.nixosModules.nix-index
topInputs.nur.nixosModules.nur
topInputs.nur-xddxdd.nixosModules.setupOverlay
topInputs.impermanence.nixosModules.impermanence
(inputs: { config.nixpkgs.overlays =
[
topInputs.qchem.overlays.default
topInputs.nixd.overlays.default
topInputs.nix-alien.overlays.default
topInputs.napalm.overlays.default
topInputs.pnpm2nix-nzbr.overlays.default
topInputs.lmix.overlays.default
(import "${topInputs.dguibert-nur-packages}/overlays/nvhpc-overlay")
(final: prev:
{
touchix = topInputs.touchix.packages."${prev.system}";
nix-vscode-extensions = topInputs.nix-vscode-extensions.extensions."${prev.system}";
nur-xddxdd = topInputs.nur-xddxdd.overlays.default final prev;
deploy-rs = { inherit (prev) deploy-rs; inherit ((topInputs.deploy-rs.overlay final prev).deploy-rs) lib; };
})
];})
./fileSystems ./kernel ./hardware ./packages ./boot ./system ./virtualization ./services ./bugs ./users
];
}
let
inherit (inputs) topInputs;
inherit (inputs.localLib) mkModules;
in
{
imports = mkModules
[
topInputs.home-manager.nixosModules.home-manager
topInputs.sops-nix.nixosModules.sops
topInputs.aagl.nixosModules.default
topInputs.nix-index-database.nixosModules.nix-index
topInputs.nur.nixosModules.nur
topInputs.nur-xddxdd.nixosModules.setupOverlay
topInputs.impermanence.nixosModules.impermanence
(inputs: { config.nixpkgs.overlays =
[
topInputs.qchem.overlays.default
topInputs.nixd.overlays.default
topInputs.nix-alien.overlays.default
topInputs.napalm.overlays.default
topInputs.pnpm2nix-nzbr.overlays.default
topInputs.lmix.overlays.default
(import "${topInputs.dguibert-nur-packages}/overlays/nvhpc-overlay")
(final: prev:
{
touchix = topInputs.touchix.packages."${prev.system}";
nix-vscode-extensions = topInputs.nix-vscode-extensions.extensions."${prev.system}";
nur-xddxdd = topInputs.nur-xddxdd.overlays.default final prev;
deploy-rs = { inherit (prev) deploy-rs; inherit ((topInputs.deploy-rs.overlay final prev).deploy-rs) lib; };
})
];})
./fileSystems ./kernel ./hardware ./packages ./boot ./system ./virtualization ./services ./bugs ./users
];
}

View File

@@ -1,240 +1,240 @@
inputs:
{
options.nixos.fileSystems = let inherit (inputs.lib) mkOption types; in
{
mount =
{
# device = mountPoint;
vfat = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
# device.subvol = mountPoint;
btrfs = mkOption { type = types.attrsOf (types.attrsOf types.nonEmptyStr); default = {}; };
};
decrypt =
{
auto = mkOption
{
type = types.attrsOf (types.submodule
{
options =
{
mapper = mkOption { type = types.nonEmptyStr; };
ssd = mkOption { type = types.bool; default = false; };
before = mkOption { type = types.nullOr (types.listOf types.nonEmptyStr); default = null; };
};
});
default = {};
};
manual =
{
enable = mkOption { type = types.bool; default = false; };
devices = mkOption
{
type = types.attrsOf (types.submodule
{
options =
{
mapper = mkOption { type = types.nonEmptyStr; };
ssd = mkOption { type = types.bool; default = false; };
};
});
default = {};
};
delayedMount = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
};
mdadm = mkOption { type = types.nullOr types.str; default = null; };
swap = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
resume = mkOption
{
type = types.nullOr (types.str or (types.submodule
{
options =
{
device = mkOption { type = types.nonEmptyStr; };
offset = mkOption { type = types.ints.unsigned; };
};
}));
default = null;
};
rollingRootfs = mkOption
{
type = types.nullOr (types.submodule { options =
{
device = mkOption { type = types.nonEmptyStr; };
path = mkOption { type = types.nonEmptyStr; };
}; });
default = null;
};
};
config =
let
inherit (builtins) listToAttrs map concatLists concatStringsSep;
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.config.nixos) fileSystems;
in mkMerge
[
# mount.vfat
{
fileSystems = listToAttrs (map
(device: { name = device.value; value = { device = device.name; fsType = "vfat"; }; })
(attrsToList fileSystems.mount.vfat));
}
# mount.btrfs
{
fileSystems = listToAttrs (concatLists (map
(
device: map
(
subvol:
{
name = subvol.value;
value =
{
device = device.name;
fsType = "btrfs";
options = [ "compress-force=zstd" "subvol=${subvol.name}" ];
};
}
)
(attrsToList device.value)
)
(attrsToList fileSystems.mount.btrfs)));
}
# decrypt.auto
(
mkIf (fileSystems.decrypt.auto != null)
{
boot.initrd =
{
luks.devices = (listToAttrs (map
(
device:
{
name = device.value.mapper;
value =
{
device = device.name;
allowDiscards = device.value.ssd;
bypassWorkqueues = device.value.ssd;
crypttabExtraOpts = [ "fido2-device=auto" "x-initrd.attach" ];
};
}
)
(attrsToList fileSystems.decrypt.auto)));
systemd.services =
let
createService = device:
{
name = "systemd-cryptsetup@${device.value.mapper}";
value =
{
before = map (device: "systemd-cryptsetup@${device}.service") device.value.before;
overrideStrategy = "asDropin";
};
};
in
listToAttrs (map createService
(builtins.filter (device: device.value.before != null) (attrsToList fileSystems.decrypt.auto)));
};
}
)
# decrypt.manual
(
mkIf (fileSystems.decrypt.manual.enable)
{
boot.initrd =
{
luks.forceLuksSupportInInitrd = true;
systemd =
{
extraBin =
{
cryptsetup = "${inputs.pkgs.cryptsetup.bin}/bin/cryptsetup";
usbip = "${inputs.config.boot.kernelPackages.usbip}/bin/usbip";
sed = "${inputs.pkgs.gnused}/bin/sed";
awk = "${inputs.pkgs.gawk}/bin/awk";
decrypt = inputs.pkgs.writeShellScript "decrypt" (stripeTabs
"
modprobe vhci-hcd
busid=$(usbip list -r 127.0.0.1 | head -n4 | tail -n1 | awk '{print $1}' | sed 's/://')
usbip attach -r 127.0.0.1 -b $busid
${concatStringsSep "\n" (map
(device: ''systemd-cryptsetup attach ${device.value.mapper} ${device.name} "" fido2-device=auto''
+ (if device.value.ssd then ",discard" else ""))
(attrsToList fileSystems.decrypt.manual.devices))}
");
};
services.wait-manual-decrypt =
{
wantedBy = [ "initrd-root-fs.target" ];
before = [ "roll-rootfs.service" ];
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
script = concatStringsSep "\n" (map
(device: "while [ ! -e /dev/mapper/${device.value.mapper} ]; do sleep 1; done")
(attrsToList fileSystems.decrypt.manual.devices));
};
};
};
fileSystems = listToAttrs (map
(mount: { name = mount; value.options = [ "x-systemd.device-timeout=15min" ]; })
fileSystems.decrypt.manual.delayedMount);
}
)
# mdadm
(
mkIf (fileSystems.mdadm != null)
{ boot.swraid = { enable = true; mdadmConf = fileSystems.mdadm; }; }
)
# swap
{ swapDevices = map (device: { device = device; }) fileSystems.swap; }
# resume
(
mkIf (fileSystems.resume != null) { boot =
(
if builtins.typeOf fileSystems.resume == "string" then
{ resumeDevice = fileSystems.resume; }
else
{
resumeDevice = fileSystems.resume.device;
kernelModules = [ "resume_offset=${fileSystems.resume.offset}" ];
}
);}
)
# rollingRootfs
(
mkIf (fileSystems.rollingRootfs != null)
{
boot.initrd.systemd.services.roll-rootfs =
{
wantedBy = [ "initrd.target" ];
after = [ "cryptsetup.target" "systemd-hibernate-resume.service" ];
before = [ "local-fs-pre.target" "sysroot.mount" ];
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
script = let inherit (fileSystems.rollingRootfs) device path; in stripeTabs
"
mount ${device} /mnt -m
if [ -f /mnt${path}/current/.timestamp ]
then
mv /mnt${path}/current /mnt${path}/$(cat /mnt${path}/current/.timestamp)
fi
btrfs subvolume create /mnt${path}/current
echo $(date '+%Y%m%d%H%M%S') > /mnt${path}/current/.timestamp
umount /mnt
";
};
}
)
];
options.nixos.fileSystems = let inherit (inputs.lib) mkOption types; in
{
mount =
{
# device = mountPoint;
vfat = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
# device.subvol = mountPoint;
btrfs = mkOption { type = types.attrsOf (types.attrsOf types.nonEmptyStr); default = {}; };
};
decrypt =
{
auto = mkOption
{
type = types.attrsOf (types.submodule
{
options =
{
mapper = mkOption { type = types.nonEmptyStr; };
ssd = mkOption { type = types.bool; default = false; };
before = mkOption { type = types.nullOr (types.listOf types.nonEmptyStr); default = null; };
};
});
default = {};
};
manual =
{
enable = mkOption { type = types.bool; default = false; };
devices = mkOption
{
type = types.attrsOf (types.submodule
{
options =
{
mapper = mkOption { type = types.nonEmptyStr; };
ssd = mkOption { type = types.bool; default = false; };
};
});
default = {};
};
delayedMount = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
};
mdadm = mkOption { type = types.nullOr types.str; default = null; };
swap = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
resume = mkOption
{
type = types.nullOr (types.str or (types.submodule
{
options =
{
device = mkOption { type = types.nonEmptyStr; };
offset = mkOption { type = types.ints.unsigned; };
};
}));
default = null;
};
rollingRootfs = mkOption
{
type = types.nullOr (types.submodule { options =
{
device = mkOption { type = types.nonEmptyStr; };
path = mkOption { type = types.nonEmptyStr; };
}; });
default = null;
};
};
config =
let
inherit (builtins) listToAttrs map concatLists concatStringsSep;
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.config.nixos) fileSystems;
in mkMerge
[
# mount.vfat
{
fileSystems = listToAttrs (map
(device: { name = device.value; value = { device = device.name; fsType = "vfat"; }; })
(attrsToList fileSystems.mount.vfat));
}
# mount.btrfs
{
fileSystems = listToAttrs (concatLists (map
(
device: map
(
subvol:
{
name = subvol.value;
value =
{
device = device.name;
fsType = "btrfs";
options = [ "compress-force=zstd" "subvol=${subvol.name}" ];
};
}
)
(attrsToList device.value)
)
(attrsToList fileSystems.mount.btrfs)));
}
# decrypt.auto
(
mkIf (fileSystems.decrypt.auto != null)
{
boot.initrd =
{
luks.devices = (listToAttrs (map
(
device:
{
name = device.value.mapper;
value =
{
device = device.name;
allowDiscards = device.value.ssd;
bypassWorkqueues = device.value.ssd;
crypttabExtraOpts = [ "fido2-device=auto" "x-initrd.attach" ];
};
}
)
(attrsToList fileSystems.decrypt.auto)));
systemd.services =
let
createService = device:
{
name = "systemd-cryptsetup@${device.value.mapper}";
value =
{
before = map (device: "systemd-cryptsetup@${device}.service") device.value.before;
overrideStrategy = "asDropin";
};
};
in
listToAttrs (map createService
(builtins.filter (device: device.value.before != null) (attrsToList fileSystems.decrypt.auto)));
};
}
)
# decrypt.manual
(
mkIf (fileSystems.decrypt.manual.enable)
{
boot.initrd =
{
luks.forceLuksSupportInInitrd = true;
systemd =
{
extraBin =
{
cryptsetup = "${inputs.pkgs.cryptsetup.bin}/bin/cryptsetup";
usbip = "${inputs.config.boot.kernelPackages.usbip}/bin/usbip";
sed = "${inputs.pkgs.gnused}/bin/sed";
awk = "${inputs.pkgs.gawk}/bin/awk";
decrypt = inputs.pkgs.writeShellScript "decrypt"
''
modprobe vhci-hcd
busid=$(usbip list -r 127.0.0.1 | head -n4 | tail -n1 | awk '{print $1}' | sed 's/://')
usbip attach -r 127.0.0.1 -b $busid
${concatStringsSep "\n" (map
(device: ''systemd-cryptsetup attach ${device.value.mapper} ${device.name} "" fido2-device=auto''
+ (if device.value.ssd then ",discard" else ""))
(attrsToList fileSystems.decrypt.manual.devices))}
'';
};
services.wait-manual-decrypt =
{
wantedBy = [ "initrd-root-fs.target" ];
before = [ "roll-rootfs.service" ];
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
script = concatStringsSep "\n" (map
(device: "while [ ! -e /dev/mapper/${device.value.mapper} ]; do sleep 1; done")
(attrsToList fileSystems.decrypt.manual.devices));
};
};
};
fileSystems = listToAttrs (map
(mount: { name = mount; value.options = [ "x-systemd.device-timeout=15min" ]; })
fileSystems.decrypt.manual.delayedMount);
}
)
# mdadm
(
mkIf (fileSystems.mdadm != null)
{ boot.swraid = { enable = true; mdadmConf = fileSystems.mdadm; }; }
)
# swap
{ swapDevices = map (device: { device = device; }) fileSystems.swap; }
# resume
(
mkIf (fileSystems.resume != null) { boot =
(
if builtins.typeOf fileSystems.resume == "string" then
{ resumeDevice = fileSystems.resume; }
else
{
resumeDevice = fileSystems.resume.device;
kernelModules = [ "resume_offset=${fileSystems.resume.offset}" ];
}
);}
)
# rollingRootfs
(
mkIf (fileSystems.rollingRootfs != null)
{
boot.initrd.systemd.services.roll-rootfs =
{
wantedBy = [ "initrd.target" ];
after = [ "cryptsetup.target" "systemd-hibernate-resume.service" ];
before = [ "local-fs-pre.target" "sysroot.mount" ];
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
script = let inherit (fileSystems.rollingRootfs) device path; in
''
mount ${device} /mnt -m
if [ -f /mnt${path}/current/.timestamp ]
then
mv /mnt${path}/current /mnt${path}/$(cat /mnt${path}/current/.timestamp)
fi
btrfs subvolume create /mnt${path}/current
echo $(date '+%Y%m%d%H%M%S') > /mnt${path}/current/.timestamp
umount /mnt
'';
};
}
)
];
}
# Disable CoW for VM image and database:
# sudo chattr +C images
# zstd:15 cause sound stuttering
# From btrfs wiki: 1-3 are real-time, 4-8 slower with improved compression,
# 9-15 try even harder though the resulting size may not be significantly improved.
# 9-15 try even harder though the resulting size may not be significantly improved.
# https://btrfs.readthedocs.io/en/latest/Compression.html
# sudo btrfs filesystem resize -50G /nix
# sudo cryptsetup status root

View File

@@ -1,146 +1,146 @@
inputs:
{
options.nixos.hardware = let inherit (inputs.lib) mkOption types; in
{
bluetooth.enable = mkOption { type = types.bool; default = false; };
joystick.enable = mkOption { type = types.bool; default = false; };
printer.enable = mkOption { type = types.bool; default = false; };
sound.enable = mkOption { type = types.bool; default = false; };
cpus = mkOption { type = types.listOf (types.enum [ "intel" "amd" ]); default = []; };
gpus = mkOption { type = types.listOf (types.enum [ "intel" "nvidia" ]); default = []; };
prime =
{
enable = mkOption { type = types.bool; default = false; };
mode = mkOption { type = types.enum [ "offload" "sync" ]; default = "offload"; };
busId = mkOption { type = types.attrsOf types.str; default = {}; };
};
gamemode.drmDevice = mkOption { type = types.int; default = 0; };
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.config.nixos) hardware;
inherit (builtins) listToAttrs map concatLists;
inherit (inputs.localLib) attrsToList;
in mkMerge
[
# bluetooth
(mkIf hardware.bluetooth.enable { hardware.bluetooth.enable = true; })
# joystick
(mkIf hardware.joystick.enable { hardware = { xone.enable = true; xpadneo.enable = true; }; })
# printer
(
mkIf hardware.printer.enable
{
services =
{
printing = { enable = true; drivers = [ inputs.pkgs.cnijfilter2 ]; };
avahi = { enable = true; nssmdns = true; openFirewall = true; };
};
}
)
# sound
(
mkIf hardware.sound.enable
{
hardware.pulseaudio.enable = false;
services.pipewire = { enable = true; alsa = { enable = true; support32Bit = true; }; pulse.enable = true; };
sound.enable = true;
security.rtkit.enable = true;
environment.etc."wireplumber/main.lua.d/50-alsa-config.lua".text =
let
content = builtins.readFile
(inputs.pkgs.wireplumber + "/share/wireplumber/main.lua.d/50-alsa-config.lua");
matched = builtins.match
".*\n([[:space:]]*)(--\\[\"session\\.suspend-timeout-seconds\"][^\n]*)[\n].*" content;
spaces = builtins.elemAt matched 0;
comment = builtins.elemAt matched 1;
config = ''["session.suspend-timeout-seconds"] = 0'';
in
builtins.replaceStrings [(spaces + comment)] [(spaces + config)] content;
}
)
# cpus
(
mkIf (hardware.cpus != [])
{
hardware.cpu = listToAttrs
(map (name: { inherit name; value = { updateMicrocode = true; }; }) hardware.cpus);
boot.initrd.availableKernelModules =
let
modules =
{
intel = [ "intel_cstate" "aesni_intel" ];
amd = [];
};
in
concatLists (map (cpu: modules.${cpu}) hardware.cpus);
}
)
# gpus
(
mkIf (hardware.gpus != [])
{
boot.initrd.availableKernelModules =
let
modules =
{
intel = [ "i915" ];
nvidia = [ "nvidia" "nvidia_drm" "nvidia_modeset" "nvidia_uvm" ];
};
in
concatLists (map (gpu: modules.${gpu}) hardware.gpus);
hardware =
{
opengl =
{
enable = true;
driSupport = true;
extraPackages =
with inputs.pkgs;
let
packages =
{
intel = [ intel-compute-runtime intel-media-driver intel-vaapi-driver libvdpau-va-gl ];
nvidia = [ vaapiVdpau ];
};
in
concatLists (map (gpu: packages.${gpu}) hardware.gpus);
driSupport32Bit = true;
};
nvidia.nvidiaSettings = builtins.elem "nvidia" hardware.gpus;
};
}
)
(mkIf (builtins.elem "intel" hardware.gpus) { services.xserver.deviceSection = ''Driver "modesetting"''; })
# prime
(
mkIf hardware.prime.enable
{
hardware.nvidia = mkMerge
[
(
mkIf (hardware.prime.mode == "offload")
{
prime.offload = { enable = true; enableOffloadCmd = true; };
powerManagement = { finegrained = true; enable = true; };
}
)
(
mkIf (hardware.prime.mode == "sync")
{
prime = { sync.enable = true; };
# prime.forceFullCompositionPipeline = true;
}
)
{
prime = listToAttrs
(map (gpu: { inherit (gpu) value; name = "${gpu.name}BusId"; }) (attrsToList hardware.prime.busId));
}
];
}
)
{ programs.gamemode.settings.gpu.gpu_device = "${toString hardware.gamemode.drmDevice}"; }
];
options.nixos.hardware = let inherit (inputs.lib) mkOption types; in
{
bluetooth.enable = mkOption { type = types.bool; default = false; };
joystick.enable = mkOption { type = types.bool; default = false; };
printer.enable = mkOption { type = types.bool; default = false; };
sound.enable = mkOption { type = types.bool; default = false; };
cpus = mkOption { type = types.listOf (types.enum [ "intel" "amd" ]); default = []; };
gpus = mkOption { type = types.listOf (types.enum [ "intel" "nvidia" ]); default = []; };
prime =
{
enable = mkOption { type = types.bool; default = false; };
mode = mkOption { type = types.enum [ "offload" "sync" ]; default = "offload"; };
busId = mkOption { type = types.attrsOf types.str; default = {}; };
};
gamemode.drmDevice = mkOption { type = types.int; default = 0; };
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.config.nixos) hardware;
inherit (builtins) listToAttrs map concatLists;
inherit (inputs.localLib) attrsToList;
in mkMerge
[
# bluetooth
(mkIf hardware.bluetooth.enable { hardware.bluetooth.enable = true; })
# joystick
(mkIf hardware.joystick.enable { hardware = { xone.enable = true; xpadneo.enable = true; }; })
# printer
(
mkIf hardware.printer.enable
{
services =
{
printing = { enable = true; drivers = [ inputs.pkgs.cnijfilter2 ]; };
avahi = { enable = true; nssmdns = true; openFirewall = true; };
};
}
)
# sound
(
mkIf hardware.sound.enable
{
hardware.pulseaudio.enable = false;
services.pipewire = { enable = true; alsa = { enable = true; support32Bit = true; }; pulse.enable = true; };
sound.enable = true;
security.rtkit.enable = true;
environment.etc."wireplumber/main.lua.d/50-alsa-config.lua".text =
let
content = builtins.readFile
(inputs.pkgs.wireplumber + "/share/wireplumber/main.lua.d/50-alsa-config.lua");
matched = builtins.match
".*\n([[:space:]]*)(--\\[\"session\\.suspend-timeout-seconds\"][^\n]*)[\n].*" content;
spaces = builtins.elemAt matched 0;
comment = builtins.elemAt matched 1;
config = ''["session.suspend-timeout-seconds"] = 0'';
in
builtins.replaceStrings [(spaces + comment)] [(spaces + config)] content;
}
)
# cpus
(
mkIf (hardware.cpus != [])
{
hardware.cpu = listToAttrs
(map (name: { inherit name; value = { updateMicrocode = true; }; }) hardware.cpus);
boot.initrd.availableKernelModules =
let
modules =
{
intel = [ "intel_cstate" "aesni_intel" ];
amd = [];
};
in
concatLists (map (cpu: modules.${cpu}) hardware.cpus);
}
)
# gpus
(
mkIf (hardware.gpus != [])
{
boot.initrd.availableKernelModules =
let
modules =
{
intel = [ "i915" ];
nvidia = [ "nvidia" "nvidia_drm" "nvidia_modeset" "nvidia_uvm" ];
};
in
concatLists (map (gpu: modules.${gpu}) hardware.gpus);
hardware =
{
opengl =
{
enable = true;
driSupport = true;
extraPackages =
with inputs.pkgs;
let
packages =
{
intel = [ intel-compute-runtime intel-media-driver intel-vaapi-driver libvdpau-va-gl ];
nvidia = [ vaapiVdpau ];
};
in
concatLists (map (gpu: packages.${gpu}) hardware.gpus);
driSupport32Bit = true;
};
nvidia.nvidiaSettings = builtins.elem "nvidia" hardware.gpus;
};
}
)
(mkIf (builtins.elem "intel" hardware.gpus) { services.xserver.deviceSection = ''Driver "modesetting"''; })
# prime
(
mkIf hardware.prime.enable
{
hardware.nvidia = mkMerge
[
(
mkIf (hardware.prime.mode == "offload")
{
prime.offload = { enable = true; enableOffloadCmd = true; };
powerManagement = { finegrained = true; enable = true; };
}
)
(
mkIf (hardware.prime.mode == "sync")
{
prime = { sync.enable = true; };
# prime.forceFullCompositionPipeline = true;
}
)
{
prime = listToAttrs
(map (gpu: { inherit (gpu) value; name = "${gpu.name}BusId"; }) (attrsToList hardware.prime.busId));
}
];
}
)
{ programs.gamemode.settings.gpu.gpu_device = "${toString hardware.gamemode.drmDevice}"; }
];
}

View File

@@ -1,89 +1,89 @@
inputs:
{
options.nixos.kernel = let inherit (inputs.lib) mkOption types; in
{
patches = mkOption { type = types.listOf (types.enum [ "cjktty" "preempt" ]); default = []; };
modules =
{
install = mkOption { type = types.listOf types.str; default = []; };
load = mkOption { type = types.listOf types.str; default = []; };
initrd = mkOption { type = types.listOf types.str; default = []; };
modprobeConfig = mkOption { type = types.listOf types.str; default = []; };
};
};
config = let inherit (inputs.lib) mkMerge mkIf; inherit (inputs.localLib) mkConditional; in mkMerge
[
# generic
{
boot =
{
kernelModules = [ "br_netfilter" ];
initrd.availableKernelModules =
[
"ahci" "ata_piix" "bfq" "failover" "net_failover" "nls_cp437" "nls_iso8859-1" "nvme" "sdhci_acpi" "sd_mod"
"sr_mod" "usbcore" "usbhid" "usbip-core" "usb-common" "usb_storage" "vhci-hcd" "virtio" "virtio_blk"
"virtio_net" "virtio_pci" "xhci_pci" "virtio_ring" "virtio_scsi" "cryptd" "crypto_simd" "libaes"
];
kernelParams = [ "delayacct" "acpi_osi=Linux" ];
kernelPackages = inputs.pkgs.linuxPackagesFor (inputs.pkgs.linuxPackages_xanmod.kernel.override rec
{
src = inputs.pkgs.fetchFromGitHub
{
owner = "xanmod";
repo = "linux";
rev = modDirVersion;
sha256 = "sha256-rvSQJb9MIOXkGEjHOPt3x+dqp1AysvQg7n5yYsg95fk=";
};
version = "6.4.12";
modDirVersion = "6.4.12-xanmod1";
});
};
}
# patches
{
boot.kernelPatches =
(
let
patches =
{
cjktty =
{
patch = inputs.pkgs.fetchurl
{
url = "https://raw.githubusercontent.com/zhmars/cjktty-patches/master/v6.x/cjktty-6.3.patch";
sha256 = "sha256-QnsWruzhtiZnqzTUXkPk9Hb19Iddr4VTWXyV4r+iLvE=";
};
extraStructuredConfig =
{ FONT_CJK_16x16 = inputs.lib.kernel.yes; FONT_CJK_32x32 = inputs.lib.kernel.yes; };
};
preempt =
{
patch = null;
extraStructuredConfig =
{
PREEMPT_VOLUNTARY = inputs.lib.mkForce inputs.lib.kernel.no;
PREEMPT = inputs.lib.mkForce inputs.lib.kernel.yes;
HZ_500 = inputs.lib.mkForce inputs.lib.kernel.no;
HZ_1000 = inputs.lib.mkForce inputs.lib.kernel.yes;
HZ = inputs.lib.mkForce (inputs.lib.kernel.freeform "1000");
};
};
};
in
builtins.map (name: { inherit name; } // patches.${name}) inputs.config.nixos.kernel.patches
);
}
# modules
{
boot =
{
extraModulePackages = inputs.config.nixos.kernel.modules.install;
kernelModules = inputs.config.nixos.kernel.modules.load;
initrd.availableKernelModules = inputs.config.nixos.kernel.modules.initrd;
extraModprobeConfig = builtins.concatStringsSep "\n" inputs.config.nixos.kernel.modules.modprobeConfig;
};
}
];
options.nixos.kernel = let inherit (inputs.lib) mkOption types; in
{
patches = mkOption { type = types.listOf (types.enum [ "cjktty" "preempt" ]); default = []; };
modules =
{
install = mkOption { type = types.listOf types.str; default = []; };
load = mkOption { type = types.listOf types.str; default = []; };
initrd = mkOption { type = types.listOf types.str; default = []; };
modprobeConfig = mkOption { type = types.listOf types.str; default = []; };
};
};
config = let inherit (inputs.lib) mkMerge mkIf; inherit (inputs.localLib) mkConditional; in mkMerge
[
# generic
{
boot =
{
kernelModules = [ "br_netfilter" ];
initrd.availableKernelModules =
[
"ahci" "ata_piix" "bfq" "failover" "net_failover" "nls_cp437" "nls_iso8859-1" "nvme" "sdhci_acpi" "sd_mod"
"sr_mod" "usbcore" "usbhid" "usbip-core" "usb-common" "usb_storage" "vhci-hcd" "virtio" "virtio_blk"
"virtio_net" "virtio_pci" "xhci_pci" "virtio_ring" "virtio_scsi" "cryptd" "crypto_simd" "libaes"
];
kernelParams = [ "delayacct" "acpi_osi=Linux" ];
kernelPackages = inputs.pkgs.linuxPackagesFor (inputs.pkgs.linuxPackages_xanmod.kernel.override rec
{
src = inputs.pkgs.fetchFromGitHub
{
owner = "xanmod";
repo = "linux";
rev = modDirVersion;
sha256 = "sha256-rvSQJb9MIOXkGEjHOPt3x+dqp1AysvQg7n5yYsg95fk=";
};
version = "6.4.12";
modDirVersion = "6.4.12-xanmod1";
});
};
}
# patches
{
boot.kernelPatches =
(
let
patches =
{
cjktty =
{
patch = inputs.pkgs.fetchurl
{
url = "https://raw.githubusercontent.com/zhmars/cjktty-patches/master/v6.x/cjktty-6.3.patch";
sha256 = "sha256-QnsWruzhtiZnqzTUXkPk9Hb19Iddr4VTWXyV4r+iLvE=";
};
extraStructuredConfig =
{ FONT_CJK_16x16 = inputs.lib.kernel.yes; FONT_CJK_32x32 = inputs.lib.kernel.yes; };
};
preempt =
{
patch = null;
extraStructuredConfig =
{
PREEMPT_VOLUNTARY = inputs.lib.mkForce inputs.lib.kernel.no;
PREEMPT = inputs.lib.mkForce inputs.lib.kernel.yes;
HZ_500 = inputs.lib.mkForce inputs.lib.kernel.no;
HZ_1000 = inputs.lib.mkForce inputs.lib.kernel.yes;
HZ = inputs.lib.mkForce (inputs.lib.kernel.freeform "1000");
};
};
};
in
builtins.map (name: { inherit name; } // patches.${name}) inputs.config.nixos.kernel.patches
);
}
# modules
{
boot =
{
extraModulePackages = inputs.config.nixos.kernel.modules.install;
kernelModules = inputs.config.nixos.kernel.modules.load;
initrd.availableKernelModules = inputs.config.nixos.kernel.modules.initrd;
extraModprobeConfig = builtins.concatStringsSep "\n" inputs.config.nixos.kernel.modules.modprobeConfig;
};
}
];
}
# modprobe --show-depends

View File

@@ -1,357 +1,357 @@
inputs:
{
options.nixos.packages = let inherit (inputs.lib) mkOption types; in
{
packageSet = mkOption
{
type = types.enum
[
# no gui, only used for specific purpose
"server"
# gui, for daily use, but not install large programs such as matlab
"desktop"
# nearly everything
"workstation"
];
default = "server";
};
extraPackages = mkOption { type = types.listOf types.unspecified; default = []; };
excludePackages = mkOption { type = types.listOf types.unspecified; default = []; };
extraPythonPackages = mkOption { type = types.listOf types.unspecified; default = []; };
excludePythonPackages = mkOption { type = types.listOf types.unspecified; default = []; };
extraPrebuildPackages = mkOption { type = types.listOf types.unspecified; default = []; };
excludePrebuildPackages = mkOption { type = types.listOf types.unspecified; default = []; };
_packages = mkOption { type = types.listOf types.unspecified; default = []; };
_pythonPackages = mkOption { type = types.listOf types.unspecified; default = []; };
_prebuildPackages = mkOption { type = types.listOf types.unspecified; default = []; };
};
config = let inherit (inputs.lib) mkMerge mkIf; inherit (inputs.localLib) stripeTabs; in mkMerge
[
# >= server
{
nixos.packages = with inputs.pkgs;
{
_packages =
[
# shell
ksh
# basic tools
beep dos2unix gnugrep pv tmux screen parallel tldr cowsay jq zellij neofetch ipfetch
# lsxx
pciutils usbutils lshw util-linux lsof
# top
iotop iftop htop btop powertop s-tui
# editor
nano bat
# downloader
wget aria2 curl
# file manager
tree exa trash-cli lsd broot file xdg-ninja mlocate
# compress
pigz rar upx unzip inputs.topInputs.nixpkgs-stable.legacyPackages.x86_64-linux.zip lzip p7zip
# file system management
sshfs e2fsprogs adb-sync duperemove compsize
# disk management
smartmontools hdparm
# encryption and authentication
apacheHttpd openssl ssh-to-age gnupg age sops pam_u2f yubico-piv-tool
# networking
ipset iptables iproute2 dig nettools traceroute tcping-go whois tcpdump nmap inetutils
# nix tools
nix-output-monitor nix-tree
# office
todo-txt-cli
] ++ (with inputs.config.boot.kernelPackages; [ cpupower usbip ]);
_pythonPackages = [(pythonPackages: with pythonPackages;
[
inquirerpy requests python-telegram-bot tqdm fastapi pypdf2 pandas matplotlib plotly gunicorn redis jinja2
certifi charset-normalizer idna orjson psycopg2
])];
};
programs =
{
nix-index-database.comma.enable = true;
nix-index.enable = true;
zsh =
{
enable = true;
syntaxHighlighting.enable = true;
autosuggestions.enable = true;
enableCompletion = true;
ohMyZsh =
{
enable = true;
plugins = [ "git" "colored-man-pages" "extract" "history-substring-search" "autojump" ];
customPkgs = with inputs.pkgs; [ zsh-nix-shell ];
};
};
ccache.enable = true;
command-not-found.enable = false;
adb.enable = true;
gnupg.agent = { enable = true; enableSSHSupport = true; };
autojump.enable = true;
git =
{
enable = true;
package = inputs.pkgs.gitFull;
lfs.enable = true;
config =
{
init.defaultBranch = "main";
core = { quotepath = false; editor = "vim"; };
};
};
};
services =
{
fwupd.enable = true;
udev.packages = with inputs.pkgs; [ yubikey-personalization libfido2 ];
};
nix.settings.extra-sandbox-paths = [ inputs.config.programs.ccache.cacheDir ];
nixpkgs.config =
{
permittedInsecurePackages = with inputs.pkgs;
[
openssl_1_1.name electron_19.name nodejs-16_x.name python2.name electron_12.name
];
allowUnfree = true;
};
}
# >= desktop
(
mkIf (builtins.elem inputs.config.nixos.packages.packageSet [ "desktop" "workstation" ] )
{
nixos.packages = with inputs.pkgs;
{
_packages =
[
# system management
gparted snapper-gui libsForQt5.qtstyleplugin-kvantum wl-clipboard-x11 kio-fuse wl-mirror
wayland-utils clinfo glxinfo vulkan-tools dracut etcher
# nix tools
ssh-to-age deploy-rs.deploy-rs nixpkgs-fmt
# instant messager
element-desktop telegram-desktop discord inputs.config.nur.repos.linyinfeng.wemeet # native
cinny-desktop # nur-xddxdd.wine-wechat thunder
# browser
google-chrome
# networking
remmina putty mtr-gui
# password and key management
bitwarden yubikey-manager yubikey-manager-qt yubikey-personalization yubikey-personalization-gui
# download
qbittorrent yt-dlp nur-xddxdd.baidupcs-go wgetpaste
# office
crow-translate zotero pandoc
# development
scrcpy
# media
spotify yesplaymusic mpv nomacs simplescreenrecorder imagemagick gimp netease-cloud-music-gtk
# text editor
localPackages.typora
# themes
orchis-theme tela-circle-icon-theme plasma-overdose-kde-theme materia-kde-theme graphite-kde-theme
arc-kde-theme materia-theme
# news
fluent-reader rssguard
# davinci-resolve playonlinux
(
vscode-with-extensions.override
{
vscodeExtensions = with nix-vscode-extensions.vscode-marketplace;
(with equinusocio; [ vsc-community-material-theme vsc-material-theme-icons ])
++ (with github; [ copilot copilot-chat copilot-labs github-vscode-theme ])
++ (with intellsmi; [ comment-translate deepl-translate ])
++ (with ms-python; [ isort python vscode-pylance ])
++ (with ms-toolsai;
[
jupyter jupyter-keymap jupyter-renderers vscode-jupyter-cell-tags vscode-jupyter-slideshow
])
++ (with ms-vscode;
[
cmake-tools cpptools cpptools-extension-pack cpptools-themes hexeditor remote-explorer
test-adapter-converter
])
++ (with ms-vscode-remote; [ remote-ssh remote-containers remote-ssh-edit ])
++ [
donjayamanne.githistory genieai.chatgpt-vscode fabiospampinato.vscode-diff cschlosser.doxdocgen
llvm-vs-code-extensions.vscode-clangd ms-ceintl.vscode-language-pack-zh-hans oderwat.indent-rainbow
twxs.cmake guyutongxue.cpp-reference znck.grammarly thfriedrich.lammps leetcode.vscode-leetcode
james-yu.latex-workshop gimly81.matlab affenwiesel.matlab-formatter ckolkman.vscode-postgres
yzhang.markdown-all-in-one pkief.material-icon-theme bbenoist.nix ms-ossdata.vscode-postgresql
redhat.vscode-xml dotjoshjohnson.xml jnoortheen.nix-ide xdebug.php-debug hbenl.vscode-test-explorer
jeff-hykin.better-cpp-syntax fredericbonnet.cmake-test-adapter mesonbuild.mesonbuild
hirse.vscode-ungit fortran-lang.linter-gfortran tboox.xmake-vscode ccls-project.ccls
feiskyer.chatgpt-copilot yukiuuh2936.vscode-modern-fortran-formatter wolframresearch.wolfram
njpipeorgan.wolfram-language-notebook brettm12345.nixfmt-vscode
];
}
)
] ++ (with inputs.lib; filter isDerivation (attrValues plasma5Packages.kdeGear));
};
programs =
{
steam.enable = true;
kdeconnect.enable = true;
wireshark = { enable = true; package = inputs.pkgs.wireshark; };
firefox =
{
enable = true;
languagePacks = [ "zh-CN" "en-US" ];
nativeMessagingHosts.firefoxpwa = true;
};
vim.package = inputs.pkgs.vim-full;
};
nixpkgs.config.packageOverrides = pkgs:
{
telegram-desktop = pkgs.telegram-desktop.overrideAttrs (attrs:
{
patches = (if (attrs ? patches) then attrs.patches else []) ++ [ ./telegram.patch ];
});
};
services.pcscd.enable = true;
}
)
# >= workstation
(
mkIf (inputs.config.nixos.packages.packageSet == "workstation")
{
nixos.packages = with inputs.pkgs;
{
_packages =
[
# nix tools
nix-template appimage-run nil nixd nix-alien nix-serve node2nix nix-prefetch-github prefetch-npm-deps
nix-prefetch-docker pnpm-lock-export
# instant messager
zoom-us signal-desktop qq nur-xddxdd.wechat-uos # jail
# office
libreoffice-qt texlive.combined.scheme-full texstudio poppler_utils pdftk gnuplot pdfchain
# development
jetbrains.clion android-studio dbeaver cling clang-tools_16 ccls fprettify
# media
nur-xddxdd.svp obs-studio waifu2x-converter-cpp inkscape blender
# virtualization
wine virt-viewer bottles # wine64
# text editor
appflowy notion-app-enhanced joplin-desktop standardnotes
# math, physics and chemistry
mathematica octave root ovito paraview localPackages.vesta qchem.quantum-espresso # vsim
# news
newsflash newsboat
];
_pythonPackages = [(pythonPackages: with pythonPackages;
[
phonopy tensorflow keras openai scipy scikit-learn
])];
_prebuildPackages = [ httplib magic-enum xtensor boost cereal cxxopts ftxui yaml-cpp gfortran gcc10 python2 ];
};
programs =
{
anime-game-launcher.enable = true;
honkers-railway-launcher.enable = true;
nix-ld.enable = true;
gamemode =
{
enable = true;
settings =
{
general.renice = 10;
gpu =
{
apply_gpu_optimisations = "accept-responsibility";
nv_powermizer_mode = 1;
};
custom = let notify-send = "${inputs.pkgs.libnotify}/bin/notify-send"; in
{
start = "${notify-send} 'GameMode started'";
end = "${notify-send} 'GameMode ended'";
};
};
};
chromium =
{
enable = true;
extraOpts =
{
PasswordManagerEnabled = false;
};
};
};
}
)
# apply package configs
{
environment.systemPackages = let inherit (inputs.lib.lists) subtractLists; in with inputs.config.nixos.packages;
(subtractLists excludePackages (_packages ++ extraPackages))
++ [
(inputs.pkgs.python3.withPackages (pythonPackages:
subtractLists
(builtins.concatLists (builtins.map (packageFunction: packageFunction pythonPackages)
excludePythonPackages))
(builtins.concatLists (builtins.map (packageFunction: packageFunction pythonPackages)
(_pythonPackages ++ extraPythonPackages)))))
(inputs.pkgs.callPackage ({ stdenv }: stdenv.mkDerivation
{
name = "prebuild-packages";
propagateBuildInputs = subtractLists excludePrebuildPackages (_prebuildPackages ++ extraPrebuildPackages);
phases = [ "installPhase" ];
installPhase = stripeTabs
''
runHook preInstall
mkdir -p $out
runHook postInstall
'';
}) {})
];
}
];
options.nixos.packages = let inherit (inputs.lib) mkOption types; in
{
packageSet = mkOption
{
type = types.enum
[
# no gui, only used for specific purpose
"server"
# gui, for daily use, but not install large programs such as matlab
"desktop"
# nearly everything
"workstation"
];
default = "server";
};
extraPackages = mkOption { type = types.listOf types.unspecified; default = []; };
excludePackages = mkOption { type = types.listOf types.unspecified; default = []; };
extraPythonPackages = mkOption { type = types.listOf types.unspecified; default = []; };
excludePythonPackages = mkOption { type = types.listOf types.unspecified; default = []; };
extraPrebuildPackages = mkOption { type = types.listOf types.unspecified; default = []; };
excludePrebuildPackages = mkOption { type = types.listOf types.unspecified; default = []; };
_packages = mkOption { type = types.listOf types.unspecified; default = []; };
_pythonPackages = mkOption { type = types.listOf types.unspecified; default = []; };
_prebuildPackages = mkOption { type = types.listOf types.unspecified; default = []; };
};
config = let inherit (inputs.lib) mkMerge mkIf; inherit (inputs.localLib) stripeTabs; in mkMerge
[
# >= server
{
nixos.packages = with inputs.pkgs;
{
_packages =
[
# shell
ksh
# basic tools
beep dos2unix gnugrep pv tmux screen parallel tldr cowsay jq zellij neofetch ipfetch
# lsxx
pciutils usbutils lshw util-linux lsof
# top
iotop iftop htop btop powertop s-tui
# editor
nano bat
# downloader
wget aria2 curl
# file manager
tree exa trash-cli lsd broot file xdg-ninja mlocate
# compress
pigz rar upx unzip inputs.topInputs.nixpkgs-stable.legacyPackages.x86_64-linux.zip lzip p7zip
# file system management
sshfs e2fsprogs adb-sync duperemove compsize
# disk management
smartmontools hdparm
# encryption and authentication
apacheHttpd openssl ssh-to-age gnupg age sops pam_u2f yubico-piv-tool
# networking
ipset iptables iproute2 dig nettools traceroute tcping-go whois tcpdump nmap inetutils
# nix tools
nix-output-monitor nix-tree
# office
todo-txt-cli
] ++ (with inputs.config.boot.kernelPackages; [ cpupower usbip ]);
_pythonPackages = [(pythonPackages: with pythonPackages;
[
inquirerpy requests python-telegram-bot tqdm fastapi pypdf2 pandas matplotlib plotly gunicorn redis jinja2
certifi charset-normalizer idna orjson psycopg2
])];
};
programs =
{
nix-index-database.comma.enable = true;
nix-index.enable = true;
zsh =
{
enable = true;
syntaxHighlighting.enable = true;
autosuggestions.enable = true;
enableCompletion = true;
ohMyZsh =
{
enable = true;
plugins = [ "git" "colored-man-pages" "extract" "history-substring-search" "autojump" ];
customPkgs = with inputs.pkgs; [ zsh-nix-shell ];
};
};
ccache.enable = true;
command-not-found.enable = false;
adb.enable = true;
gnupg.agent = { enable = true; enableSSHSupport = true; };
autojump.enable = true;
git =
{
enable = true;
package = inputs.pkgs.gitFull;
lfs.enable = true;
config =
{
init.defaultBranch = "main";
core = { quotepath = false; editor = "vim"; };
};
};
};
services =
{
fwupd.enable = true;
udev.packages = with inputs.pkgs; [ yubikey-personalization libfido2 ];
};
nix.settings.extra-sandbox-paths = [ inputs.config.programs.ccache.cacheDir ];
nixpkgs.config =
{
permittedInsecurePackages = with inputs.pkgs;
[
openssl_1_1.name electron_19.name nodejs-16_x.name python2.name electron_12.name
];
allowUnfree = true;
};
}
# >= desktop
(
mkIf (builtins.elem inputs.config.nixos.packages.packageSet [ "desktop" "workstation" ] )
{
nixos.packages = with inputs.pkgs;
{
_packages =
[
# system management
gparted snapper-gui libsForQt5.qtstyleplugin-kvantum wl-clipboard-x11 kio-fuse wl-mirror
wayland-utils clinfo glxinfo vulkan-tools dracut etcher
# nix tools
ssh-to-age deploy-rs.deploy-rs nixpkgs-fmt
# instant messager
element-desktop telegram-desktop discord inputs.config.nur.repos.linyinfeng.wemeet # native
cinny-desktop # nur-xddxdd.wine-wechat thunder
# browser
google-chrome
# networking
remmina putty mtr-gui
# password and key management
bitwarden yubikey-manager yubikey-manager-qt yubikey-personalization yubikey-personalization-gui
# download
qbittorrent yt-dlp nur-xddxdd.baidupcs-go wgetpaste
# office
crow-translate zotero pandoc
# development
scrcpy
# media
spotify yesplaymusic mpv nomacs simplescreenrecorder imagemagick gimp netease-cloud-music-gtk
# text editor
localPackages.typora
# themes
orchis-theme tela-circle-icon-theme plasma-overdose-kde-theme materia-kde-theme graphite-kde-theme
arc-kde-theme materia-theme
# news
fluent-reader rssguard
# davinci-resolve playonlinux
(
vscode-with-extensions.override
{
vscodeExtensions = with nix-vscode-extensions.vscode-marketplace;
(with equinusocio; [ vsc-community-material-theme vsc-material-theme-icons ])
++ (with github; [ copilot copilot-chat copilot-labs github-vscode-theme ])
++ (with intellsmi; [ comment-translate deepl-translate ])
++ (with ms-python; [ isort python vscode-pylance ])
++ (with ms-toolsai;
[
jupyter jupyter-keymap jupyter-renderers vscode-jupyter-cell-tags vscode-jupyter-slideshow
])
++ (with ms-vscode;
[
cmake-tools cpptools cpptools-extension-pack cpptools-themes hexeditor remote-explorer
test-adapter-converter
])
++ (with ms-vscode-remote; [ remote-ssh remote-containers remote-ssh-edit ])
++ [
donjayamanne.githistory genieai.chatgpt-vscode fabiospampinato.vscode-diff cschlosser.doxdocgen
llvm-vs-code-extensions.vscode-clangd ms-ceintl.vscode-language-pack-zh-hans oderwat.indent-rainbow
twxs.cmake guyutongxue.cpp-reference znck.grammarly thfriedrich.lammps leetcode.vscode-leetcode
james-yu.latex-workshop gimly81.matlab affenwiesel.matlab-formatter ckolkman.vscode-postgres
yzhang.markdown-all-in-one pkief.material-icon-theme bbenoist.nix ms-ossdata.vscode-postgresql
redhat.vscode-xml dotjoshjohnson.xml jnoortheen.nix-ide xdebug.php-debug hbenl.vscode-test-explorer
jeff-hykin.better-cpp-syntax fredericbonnet.cmake-test-adapter mesonbuild.mesonbuild
hirse.vscode-ungit fortran-lang.linter-gfortran tboox.xmake-vscode ccls-project.ccls
feiskyer.chatgpt-copilot yukiuuh2936.vscode-modern-fortran-formatter wolframresearch.wolfram
njpipeorgan.wolfram-language-notebook brettm12345.nixfmt-vscode
];
}
)
] ++ (with inputs.lib; filter isDerivation (attrValues plasma5Packages.kdeGear));
};
programs =
{
steam.enable = true;
kdeconnect.enable = true;
wireshark = { enable = true; package = inputs.pkgs.wireshark; };
firefox =
{
enable = true;
languagePacks = [ "zh-CN" "en-US" ];
nativeMessagingHosts.firefoxpwa = true;
};
vim.package = inputs.pkgs.vim-full;
};
nixpkgs.config.packageOverrides = pkgs:
{
telegram-desktop = pkgs.telegram-desktop.overrideAttrs (attrs:
{
patches = (if (attrs ? patches) then attrs.patches else []) ++ [ ./telegram.patch ];
});
};
services.pcscd.enable = true;
}
)
# >= workstation
(
mkIf (inputs.config.nixos.packages.packageSet == "workstation")
{
nixos.packages = with inputs.pkgs;
{
_packages =
[
# nix tools
nix-template appimage-run nil nixd nix-alien nix-serve node2nix nix-prefetch-github prefetch-npm-deps
nix-prefetch-docker pnpm-lock-export
# instant messager
zoom-us signal-desktop qq nur-xddxdd.wechat-uos # jail
# office
libreoffice-qt texlive.combined.scheme-full texstudio poppler_utils pdftk gnuplot pdfchain
# development
jetbrains.clion android-studio dbeaver cling clang-tools_16 ccls fprettify
# media
nur-xddxdd.svp obs-studio waifu2x-converter-cpp inkscape blender
# virtualization
wine virt-viewer bottles # wine64
# text editor
appflowy notion-app-enhanced joplin-desktop standardnotes
# math, physics and chemistry
mathematica octave root ovito paraview localPackages.vesta qchem.quantum-espresso # vsim
# news
newsflash newsboat
];
_pythonPackages = [(pythonPackages: with pythonPackages;
[
phonopy tensorflow keras openai scipy scikit-learn
])];
_prebuildPackages = [ httplib magic-enum xtensor boost cereal cxxopts ftxui yaml-cpp gfortran gcc10 python2 ];
};
programs =
{
anime-game-launcher.enable = true;
honkers-railway-launcher.enable = true;
nix-ld.enable = true;
gamemode =
{
enable = true;
settings =
{
general.renice = 10;
gpu =
{
apply_gpu_optimisations = "accept-responsibility";
nv_powermizer_mode = 1;
};
custom = let notify-send = "${inputs.pkgs.libnotify}/bin/notify-send"; in
{
start = "${notify-send} 'GameMode started'";
end = "${notify-send} 'GameMode ended'";
};
};
};
chromium =
{
enable = true;
extraOpts =
{
PasswordManagerEnabled = false;
};
};
};
}
)
# apply package configs
{
environment.systemPackages = let inherit (inputs.lib.lists) subtractLists; in with inputs.config.nixos.packages;
(subtractLists excludePackages (_packages ++ extraPackages))
++ [
(inputs.pkgs.python3.withPackages (pythonPackages:
subtractLists
(builtins.concatLists (builtins.map (packageFunction: packageFunction pythonPackages)
excludePythonPackages))
(builtins.concatLists (builtins.map (packageFunction: packageFunction pythonPackages)
(_pythonPackages ++ extraPythonPackages)))))
(inputs.pkgs.callPackage ({ stdenv }: stdenv.mkDerivation
{
name = "prebuild-packages";
propagateBuildInputs = subtractLists excludePrebuildPackages (_prebuildPackages ++ extraPrebuildPackages);
phases = [ "installPhase" ];
installPhase = stripeTabs
''
runHook preInstall
mkdir -p $out
runHook postInstall
'';
}) {})
];
}
];
}
# programs.firejail =
# {
# enable = true;
# wrappedBinaries =
# {
# qq =
# {
# executable = "${inputs.pkgs.qq}/bin/qq";
# profile = "${inputs.pkgs.firejail}/etc/firejail/linuxqq.profile";
# };
# };
# };
# programs.firejail =
# {
# enable = true;
# wrappedBinaries =
# {
# qq =
# {
# executable = "${inputs.pkgs.qq}/bin/qq";
# profile = "${inputs.pkgs.firejail}/etc/firejail/linuxqq.profile";
# };
# };
# };
# config.nixpkgs.config.replaceStdenv = { pkgs }: pkgs.ccacheStdenv;
# only replace stdenv for large and tested packages
# config.programs.ccache.packageNames = [ "webkitgtk" "libreoffice" "tensorflow" "linux" "chromium" ];
# config.nixpkgs.overlays = [(final: prev:
# {
# libreoffice-qt = prev.libreoffice-qt.override (prev: { unwrapped = prev.unwrapped.override
# (prev: { stdenv = final.ccacheStdenv.override { stdenv = prev.stdenv; }; }); });
# python3 = prev.python3.override { packageOverrides = python-final: python-prev:
# {
# tensorflow = python-prev.tensorflow.override
# { stdenv = final.ccacheStdenv.override { stdenv = python-prev.tensorflow.stdenv; }; };
# };};
# # webkitgtk = prev.webkitgtk.override (prev:
# # { stdenv = final.ccacheStdenv.override { stdenv = prev.stdenv; }; enableUnifiedBuilds = false; });
# wxGTK31 = prev.wxGTK31.override { stdenv = final.ccacheStdenv.override { stdenv = prev.wxGTK31.stdenv; }; };
# wxGTK32 = prev.wxGTK32.override { stdenv = final.ccacheStdenv.override { stdenv = prev.wxGTK32.stdenv; }; };
# # firefox-unwrapped = prev.firefox-unwrapped.override
# # { stdenv = final.ccacheStdenv.override { stdenv = prev.firefox-unwrapped.stdenv; }; };
# # chromium = prev.chromium.override
# # { stdenv = final.ccacheStdenv.override { stdenv = prev.chromium.stdenv; }; };
# # linuxPackages_xanmod_latest = prev.linuxPackages_xanmod_latest.override
# # {
# # kernel = prev.linuxPackages_xanmod_latest.kernel.override
# # {
# # stdenv = final.ccacheStdenv.override { stdenv = prev.linuxPackages_xanmod_latest.kernel.stdenv; };
# # buildPackages = prev.linuxPackages_xanmod_latest.kernel.buildPackages //
# # { stdenv = prev.linuxPackages_xanmod_latest.kernel.buildPackages.stdenv; };
# # };
# # };
# })];
# config.programs.ccache.packageNames = [ "libreoffice-unwrapped" ];
# only replace stdenv for large and tested packages
# config.programs.ccache.packageNames = [ "webkitgtk" "libreoffice" "tensorflow" "linux" "chromium" ];
# config.nixpkgs.overlays = [(final: prev:
# {
# libreoffice-qt = prev.libreoffice-qt.override (prev: { unwrapped = prev.unwrapped.override
# (prev: { stdenv = final.ccacheStdenv.override { stdenv = prev.stdenv; }; }); });
# python3 = prev.python3.override { packageOverrides = python-final: python-prev:
# {
# tensorflow = python-prev.tensorflow.override
# { stdenv = final.ccacheStdenv.override { stdenv = python-prev.tensorflow.stdenv; }; };
# };};
# # webkitgtk = prev.webkitgtk.override (prev:
# # { stdenv = final.ccacheStdenv.override { stdenv = prev.stdenv; }; enableUnifiedBuilds = false; });
# wxGTK31 = prev.wxGTK31.override { stdenv = final.ccacheStdenv.override { stdenv = prev.wxGTK31.stdenv; }; };
# wxGTK32 = prev.wxGTK32.override { stdenv = final.ccacheStdenv.override { stdenv = prev.wxGTK32.stdenv; }; };
# # firefox-unwrapped = prev.firefox-unwrapped.override
# # { stdenv = final.ccacheStdenv.override { stdenv = prev.firefox-unwrapped.stdenv; }; };
# # chromium = prev.chromium.override
# # { stdenv = final.ccacheStdenv.override { stdenv = prev.chromium.stdenv; }; };
# # linuxPackages_xanmod_latest = prev.linuxPackages_xanmod_latest.override
# # {
# # kernel = prev.linuxPackages_xanmod_latest.kernel.override
# # {
# # stdenv = final.ccacheStdenv.override { stdenv = prev.linuxPackages_xanmod_latest.kernel.stdenv; };
# # buildPackages = prev.linuxPackages_xanmod_latest.kernel.buildPackages //
# # { stdenv = prev.linuxPackages_xanmod_latest.kernel.buildPackages.stdenv; };
# # };
# # };
# })];
# config.programs.ccache.packageNames = [ "libreoffice-unwrapped" ];
# cross-x86_64-pc-linux-musl/gcc
# dev-cpp/cpp-httplib ? how to use
@@ -408,4 +408,4 @@ inputs:
# x11-misc/optimus-manager
# x11-misc/unclutter-xfixes
# ++ ( with inputs.pkgs.pkgsCross.mingwW64.buildPackages; [ gcc ] );
# ++ ( with inputs.pkgs.pkgsCross.mingwW64.buildPackages; [ gcc ] );

View File

@@ -1,37 +1,37 @@
inputs:
{
options.nixos.services.coturn = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
hostname = mkOption { type = types.str; default = "coturn.chn.moe"; };
};
config =
let
inherit (inputs.config.nixos.services) coturn;
inherit (inputs.lib) mkIf;
in mkIf coturn.enable
{
services.coturn =
let
keydir = inputs.config.security.acme.certs.${coturn.hostname}.directory;
in
{
enable = true;
use-auth-secret = true;
static-auth-secret-file = inputs.config.sops.secrets."coturn/auth-secret".path;
realm = coturn.hostname;
cert = "${keydir}/full.pem";
pkey = "${keydir}/key.pem";
no-cli = true;
};
sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User;
nixos.services.acme = { enable = true; certs = [ coturn.hostname ]; };
security.acme.certs.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group;
networking.firewall = with inputs.config.services.coturn;
{
allowedUDPPorts = [ listening-port tls-listening-port ];
allowedTCPPorts = [ listening-port tls-listening-port ];
allowedUDPPortRanges = [ { from = min-port; to = max-port; } ];
};
};
options.nixos.services.coturn = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
hostname = mkOption { type = types.str; default = "coturn.chn.moe"; };
};
config =
let
inherit (inputs.config.nixos.services) coturn;
inherit (inputs.lib) mkIf;
in mkIf coturn.enable
{
services.coturn =
let
keydir = inputs.config.security.acme.certs.${coturn.hostname}.directory;
in
{
enable = true;
use-auth-secret = true;
static-auth-secret-file = inputs.config.sops.secrets."coturn/auth-secret".path;
realm = coturn.hostname;
cert = "${keydir}/full.pem";
pkey = "${keydir}/key.pem";
no-cli = true;
};
sops.secrets."coturn/auth-secret".owner = inputs.config.systemd.services.coturn.serviceConfig.User;
nixos.services.acme = { enable = true; certs = [ coturn.hostname ]; };
security.acme.certs.${coturn.hostname}.group = inputs.config.systemd.services.coturn.serviceConfig.Group;
networking.firewall = with inputs.config.services.coturn;
{
allowedUDPPorts = [ listening-port tls-listening-port ];
allowedTCPPorts = [ listening-port tls-listening-port ];
allowedUDPPortRanges = [ { from = min-port; to = max-port; } ];
};
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,103 +1,103 @@
inputs:
{
options.nixos.services.docker = let inherit (inputs.lib) mkOption types; in
{
type = types.attrsOf (types.submodule (inputs: { options =
{
user = mkOption { type = types.nonEmptyStr; default = inputs.config._module.args.name; };
image = mkOption { type = types.package; };
imageName =
mkOption { type = types.nonEmptyStr; default = "${inputs.image.imageName}:${inputs.image.imageTag}"; };
ports = mkOption
{
type = types.listOf (types.oneOf
[
types.ints.unsigned
types.submodule (inputs: { options =
{
hostIp = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; };
hostPort = mkOption { type = types.ints.unsigned; };
containerPort = mkOption { type = types.ints.unsigned; };
protocol = mkOption { type = types.enum [ "tcp" "udp" ]; default = "tcp"; };
};})
]);
default = [];
};
environmentFile = mkOption { type = types.oneOf [ types.bool types.nonEmptyStr ]; default = false; };
};}));
default = {};
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (builtins) listToAttrs map concatLists;
inherit (inputs.localLib) attrsToList;
inherit (inputs.config.nixos.services) docker;
in mkMerge
[
{
virtualisation.oci-containers.containers = listToAttrs (map
(container:
{
name = "${container.name}";
value =
{
image = container.value.imageName;
imageFile = container.value.image;
ports = map
(port:
(
if builtins.typeOf port == "int" then "127.0.0.1::${toString port}"
else ("${port.value.hostIp}:${toString port.value.hostPort}"
+ ":${toString port.value.containerPort}/${port.value.protocol}")
))
container.value.ports;
extraOptions = [ "--add-host=host.docker.internal:host-gateway" ];
environmentFiles =
if builtins.typeOf container.value.environmentFile == "bool" && container.value.environmentFile
then [ inputs.config.sops.templates."${container.name}/env".path ]
else if builtins.typeOf container.value.environmentFile == "bool" then []
else [ container.value.environmentFile ];
};
})
(attrsToList docker));
systemd.services = listToAttrs (concatLists (map
(container:
[
{
name = "docker-${container.value.user}-daemon";
value =
{
wantedBy = [ "multi-user.target" ];
inherit (inputs.systemd.user.services.docker) description path;
serviceConfig = inputs.systemd.user.services.docker.serviceConfig //
{
User = container.value.user;
Group = container.value.user;
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
ExecStart = inputs.systemd.user.services.docker.serviceConfig.ExecStart
+ " -H unix:///var/run/docker-rootless/${container.value.user}.sock";
};
unitConfig = { inherit (inputs.systemd.user.services.docker.unitConfig) StartLimitInterval; };
};
}
{
name = "docker-${container.name}";
value =
{
requires = [ "docker-${container.value.user}-daemon.service" ];
after = [ "docker-${container.value.user}-daemon.service" ];
environment.DOCKER_HOST = "unix:///var/run/docker-rootless/${container.value.user}.sock";
serviceConfig = { User = container.value.user; Group = container.value.user; };
};
}
])
(attrsToList docker)));
}
(mkIf (docker != {})
{
systemd.tmpfiles.rules = [ "d /var/run/docker-rootless 0777" ];
nixos.virtualization.docker.enable = true;
})
];
options.nixos.services.docker = let inherit (inputs.lib) mkOption types; in
{
type = types.attrsOf (types.submodule (inputs: { options =
{
user = mkOption { type = types.nonEmptyStr; default = inputs.config._module.args.name; };
image = mkOption { type = types.package; };
imageName =
mkOption { type = types.nonEmptyStr; default = with inputs.image; (imageName + ":" + imageTag); };
ports = mkOption
{
type = types.listOf (types.oneOf
[
types.ints.unsigned
types.submodule (inputs: { options =
{
hostIp = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; };
hostPort = mkOption { type = types.ints.unsigned; };
containerPort = mkOption { type = types.ints.unsigned; };
protocol = mkOption { type = types.enum [ "tcp" "udp" ]; default = "tcp"; };
};})
]);
default = [];
};
environmentFile = mkOption { type = types.oneOf [ types.bool types.nonEmptyStr ]; default = false; };
};}));
default = {};
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (builtins) listToAttrs map concatLists;
inherit (inputs.localLib) attrsToList;
inherit (inputs.config.nixos.services) docker;
in mkMerge
[
{
virtualisation.oci-containers.containers = listToAttrs (map
(container:
{
name = "${container.name}";
value =
{
image = container.value.imageName;
imageFile = container.value.image;
ports = map
(port:
(
if builtins.typeOf port == "int" then "127.0.0.1::${toString port}"
else ("${port.value.hostIp}:${toString port.value.hostPort}"
+ ":${toString port.value.containerPort}/${port.value.protocol}")
))
container.value.ports;
extraOptions = [ "--add-host=host.docker.internal:host-gateway" ];
environmentFiles =
if builtins.typeOf container.value.environmentFile == "bool" && container.value.environmentFile
then [ inputs.config.sops.templates."${container.name}/env".path ]
else if builtins.typeOf container.value.environmentFile == "bool" then []
else [ container.value.environmentFile ];
};
})
(attrsToList docker));
systemd.services = listToAttrs (concatLists (map
(container:
[
{
name = "docker-${container.value.user}-daemon";
value =
{
wantedBy = [ "multi-user.target" ];
inherit (inputs.systemd.user.services.docker) description path;
serviceConfig = inputs.systemd.user.services.docker.serviceConfig //
{
User = container.value.user;
Group = container.value.user;
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
ExecStart = inputs.systemd.user.services.docker.serviceConfig.ExecStart
+ " -H unix:///var/run/docker-rootless/${container.value.user}.sock";
};
unitConfig = { inherit (inputs.systemd.user.services.docker.unitConfig) StartLimitInterval; };
};
}
{
name = "docker-${container.name}";
value =
{
requires = [ "docker-${container.value.user}-daemon.service" ];
after = [ "docker-${container.value.user}-daemon.service" ];
environment.DOCKER_HOST = "unix:///var/run/docker-rootless/${container.value.user}.sock";
serviceConfig = { User = container.value.user; Group = container.value.user; };
};
}
])
(attrsToList docker)));
}
(mkIf (docker != {})
{
systemd.tmpfiles.rules = [ "d /var/run/docker-rootless 0777" ];
nixos.virtualization.docker.enable = true;
})
];
}

View File

@@ -1,23 +1,23 @@
inputs:
{
options.nixos.services.huginn.enable = inputs.lib.mkOption { type = inputs.lib.types.bool; default = false; };
config = inputs.lib.mkIf inputs.config.nixos.services.huginn.enable
{
nixos.services =
{
docker.huginn =
{
image = inputs.pkgs.dockerTools.pullImage
{
imageName = "huginn/huginn";
imageDigest = "sha256:dbe871597d43232add81d1adfc5ad9f5cf9dcb5e1f1ba3d669598c20b96ab6c1";
sha256 = "0ls97k8ic7w5j54jlpwh8rrvj1y4pl4106j9pyap105r6p7dziiz";
finalImageName = "huginn/huginn";
finalImageTag = "2d5fcafc507da3e8c115c3479e9116a0758c5375";
};
ports = [ 3000 ];
environmentFile = true;
};
};
};
options.nixos.services.huginn.enable = inputs.lib.mkOption { type = inputs.lib.types.bool; default = false; };
config = inputs.lib.mkIf inputs.config.nixos.services.huginn.enable
{
nixos.services =
{
docker.huginn =
{
image = inputs.pkgs.dockerTools.pullImage
{
imageName = "huginn/huginn";
imageDigest = "sha256:dbe871597d43232add81d1adfc5ad9f5cf9dcb5e1f1ba3d669598c20b96ab6c1";
sha256 = "0ls97k8ic7w5j54jlpwh8rrvj1y4pl4106j9pyap105r6p7dziiz";
finalImageName = "huginn/huginn";
finalImageTag = "2d5fcafc507da3e8c115c3479e9116a0758c5375";
};
ports = [ 3000 ];
environmentFile = true;
};
};
};
}

View File

@@ -1,104 +1,104 @@
inputs:
{
options.nixos.services.meilisearch = let inherit (inputs.lib) mkOption types; in
{
instances = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
user = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
port = mkOption { type = types.ints.unsigned; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) meilisearch;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (builtins) map listToAttrs;
in
{
systemd =
{
services = listToAttrs (map
(instance:
{
name = "meilisearch-${instance.name}";
value =
{
description = "meiliSearch ${instance.name}";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
# environment.RUST_BACKTRACE = "full";
serviceConfig =
{
User = instance.value.user;
Group = inputs.config.users.users.${instance.value.user}.group;
ExecStart =
let
meilisearch = inputs.pkgs.meilisearch.overrideAttrs (prev:
{
RUSTFLAGS = prev.RUSTFLAGS or [] ++ [ "-Clto=true" "-Cpanic=abort" "-Cembed-bitcode=yes"]
++ (
let inherit (inputs.config.nixos.system) march;
in (if march != null then [ "-Ctarget-cpu=${march}" ] else [])
);
});
config = inputs.config.sops.templates."meilisearch-${instance.name}.toml".path;
in
"${meilisearch}/bin/meilisearch --config-file-path ${config}";
Restart = "always";
StartLimitBurst = 3;
LimitNOFILE = "infinity";
LimitNPROC = "infinity";
LimitCORE = "infinity";
CPUSchedulingPolicy = "idle";
IOSchedulingClass = "idle";
IOSchedulingPriority = 4;
IOAccounting = true;
IOWeight = 1;
Nice = 19;
Slice = "-.slice";
};
};
})
(attrsToList meilisearch.instances));
tmpfiles.rules = map
(instance:
let
user = instance.value.user;
group = inputs.config.users.users.${instance.value.user}.group;
in
"d /var/lib/meilisearch/${instance.name} 0700 ${user} ${group}")
(attrsToList meilisearch.instances);
};
sops =
{
templates = listToAttrs (map
(instance:
{
name = "meilisearch-${instance.name}.toml";
value =
{
content = stripeTabs
''
db_path = "/var/lib/meilisearch/${instance.name}"
http_addr = "0.0.0.0:${toString instance.value.port}"
master_key = "${inputs.config.sops.placeholder."meilisearch/${instance.name}"}"
env = "production"
dump_dir = "/var/lib/meilisearch/${instance.name}/dumps"
log_level = "INFO"
max_indexing_memory = "8Gb"
max_indexing_threads = 1
'';
owner = inputs.config.users.users.misskey.name;
};
})
(attrsToList meilisearch.instances));
secrets = listToAttrs (map
(instance: { name = "meilisearch/${instance.name}"; value = {}; })
(attrsToList meilisearch.instances));
};
};
options.nixos.services.meilisearch = let inherit (inputs.lib) mkOption types; in
{
instances = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
user = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
port = mkOption { type = types.ints.unsigned; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) meilisearch;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (builtins) map listToAttrs;
in
{
systemd =
{
services = listToAttrs (map
(instance:
{
name = "meilisearch-${instance.name}";
value =
{
description = "meiliSearch ${instance.name}";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
# environment.RUST_BACKTRACE = "full";
serviceConfig =
{
User = instance.value.user;
Group = inputs.config.users.users.${instance.value.user}.group;
ExecStart =
let
meilisearch = inputs.pkgs.meilisearch.overrideAttrs (prev:
{
RUSTFLAGS = prev.RUSTFLAGS or [] ++ [ "-Clto=true" "-Cpanic=abort" "-Cembed-bitcode=yes"]
++ (
let inherit (inputs.config.nixos.system) march;
in (if march != null then [ "-Ctarget-cpu=${march}" ] else [])
);
});
config = inputs.config.sops.templates."meilisearch-${instance.name}.toml".path;
in
"${meilisearch}/bin/meilisearch --config-file-path ${config}";
Restart = "always";
StartLimitBurst = 3;
LimitNOFILE = "infinity";
LimitNPROC = "infinity";
LimitCORE = "infinity";
CPUSchedulingPolicy = "idle";
IOSchedulingClass = "idle";
IOSchedulingPriority = 4;
IOAccounting = true;
IOWeight = 1;
Nice = 19;
Slice = "-.slice";
};
};
})
(attrsToList meilisearch.instances));
tmpfiles.rules = map
(instance:
let
user = instance.value.user;
group = inputs.config.users.users.${instance.value.user}.group;
in
"d /var/lib/meilisearch/${instance.name} 0700 ${user} ${group}")
(attrsToList meilisearch.instances);
};
sops =
{
templates = listToAttrs (map
(instance:
{
name = "meilisearch-${instance.name}.toml";
value =
{
content =
''
db_path = "/var/lib/meilisearch/${instance.name}"
http_addr = "0.0.0.0:${toString instance.value.port}"
master_key = "${inputs.config.sops.placeholder."meilisearch/${instance.name}"}"
env = "production"
dump_dir = "/var/lib/meilisearch/${instance.name}/dumps"
log_level = "INFO"
max_indexing_memory = "8Gb"
max_indexing_threads = 1
'';
owner = inputs.config.users.users.misskey.name;
};
})
(attrsToList meilisearch.instances));
secrets = listToAttrs (map
(instance: { name = "meilisearch/${instance.name}"; value = {}; })
(attrsToList meilisearch.instances));
};
};
}

View File

@@ -1,161 +1,161 @@
inputs:
{
options.nixos.services = let inherit (inputs.lib) mkOption types; in
{
misskey =
{
enable = mkOption { type = types.bool; default = false; };
port = mkOption { type = types.ints.unsigned; default = 9726; };
hostname = mkOption { type = types.str; default = "misskey.chn.moe"; };
};
misskey-proxy = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
hostname = mkOption { type = types.str; default = submoduleInputs.config._module.args.name; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) misskey misskey-proxy;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.lib) mkIf mkMerge;
inherit (builtins) map listToAttrs toString replaceStrings;
in mkMerge
[
(mkIf misskey.enable
{
systemd =
{
services.misskey =
{
description = "misskey";
after = [ "network.target" "redis-misskey.service" "postgresql.service" "meilisearch-misskey.service" ];
requires = [ "network.target" "redis-misskey.service" "postgresql.service" "meilisearch-misskey.service" ];
wantedBy = [ "multi-user.target" ];
environment.MISSKEY_CONFIG_YML = inputs.config.sops.templates."misskey/default.yml".path;
serviceConfig = rec
{
User = inputs.config.users.users.misskey.name;
Group = inputs.config.users.users.misskey.group;
WorkingDirectory = "/var/lib/misskey/work";
ExecStart = "${WorkingDirectory}/bin/misskey";
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
};
};
tmpfiles.rules = [ "d /var/lib/misskey/files 0700 misskey misskey" ];
};
fileSystems =
{
"/var/lib/misskey/work" =
{
device = "${inputs.pkgs.localPackages.misskey}";
options = [ "bind" ];
};
"/var/lib/misskey/work/files" =
{
device = "/var/lib/misskey/files";
options = [ "bind" ];
};
};
sops.templates."misskey/default.yml" =
{
content =
let
placeholder = inputs.config.sops.placeholder;
misskey = inputs.config.nixos.services.misskey;
redis = inputs.config.nixos.services.redis.instances.misskey;
in replaceStrings ["\t"] [" "] (stripeTabs
''
url: https://${misskey.hostname}/
port: ${toString misskey.port}
db:
host: 127.0.0.1
port: 5432
db: misskey
user: misskey
pass: ${placeholder."postgresql/misskey"}
extra:
statement_timeout: 60000
dbReplications: false
redis:
host: 127.0.0.1
port: ${toString redis.port}
pass: ${placeholder."redis/misskey"}
meilisearch:
host: 127.0.0.1
port: 7700
apiKey: ${placeholder."meilisearch/misskey"}
ssl: false
index: misskey
scope: global
id: 'aid'
proxyBypassHosts:
- api.deepl.com
- api-free.deepl.com
- www.recaptcha.net
- hcaptcha.com
- challenges.cloudflare.com
proxyRemoteFiles: true
signToActivityPubGet: true
maxFileSize: 1073741824
'');
owner = inputs.config.users.users.misskey.name;
};
users =
{
users.misskey = { isSystemUser = true; group = "misskey"; home = "/var/lib/misskey"; createHome = true; };
groups.misskey = {};
};
nixos.services =
{
redis.instances.misskey.port = 3545;
nginx =
{
enable = true;
httpProxy =
{
"${misskey.hostname}" =
{
upstream = "http://127.0.0.1:${toString misskey.port}";
websocket = true;
setHeaders.Host = misskey.hostname;
};
"direct.${misskey.hostname}" =
{
upstream = "http://127.0.0.1:${toString misskey.port}";
websocket = true;
setHeaders.Host = misskey.hostname;
detectAuth = true;
};
};
};
postgresql = { enable = true; instances.misskey = {}; };
meilisearch.instances.misskey = { user = inputs.config.users.users.misskey.name; port = 7700; };
};
})
(mkIf (misskey-proxy != {})
{
nixos.services.nginx =
{
enable = true;
httpProxy = listToAttrs (map
(proxy:
{
name = proxy.value.hostname;
value =
{
upstream = "https://direct.${proxy.value.hostname}";
websocket = true;
setHeaders.Host = "direct.${proxy.value.hostname}";
addAuth = true;
};
})
(attrsToList misskey-proxy));
};
})
];
options.nixos.services = let inherit (inputs.lib) mkOption types; in
{
misskey =
{
enable = mkOption { type = types.bool; default = false; };
port = mkOption { type = types.ints.unsigned; default = 9726; };
hostname = mkOption { type = types.str; default = "misskey.chn.moe"; };
};
misskey-proxy = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
hostname = mkOption { type = types.str; default = submoduleInputs.config._module.args.name; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) misskey misskey-proxy;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.lib) mkIf mkMerge;
inherit (builtins) map listToAttrs toString replaceStrings;
in mkMerge
[
(mkIf misskey.enable
{
systemd =
{
services.misskey =
{
description = "misskey";
after = [ "network.target" "redis-misskey.service" "postgresql.service" "meilisearch-misskey.service" ];
requires = [ "network.target" "redis-misskey.service" "postgresql.service" "meilisearch-misskey.service" ];
wantedBy = [ "multi-user.target" ];
environment.MISSKEY_CONFIG_YML = inputs.config.sops.templates."misskey/default.yml".path;
serviceConfig = rec
{
User = inputs.config.users.users.misskey.name;
Group = inputs.config.users.users.misskey.group;
WorkingDirectory = "/var/lib/misskey/work";
ExecStart = "${WorkingDirectory}/bin/misskey";
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
};
};
tmpfiles.rules = [ "d /var/lib/misskey/files 0700 misskey misskey" ];
};
fileSystems =
{
"/var/lib/misskey/work" =
{
device = "${inputs.pkgs.localPackages.misskey}";
options = [ "bind" ];
};
"/var/lib/misskey/work/files" =
{
device = "/var/lib/misskey/files";
options = [ "bind" ];
};
};
sops.templates."misskey/default.yml" =
{
content =
let
placeholder = inputs.config.sops.placeholder;
misskey = inputs.config.nixos.services.misskey;
redis = inputs.config.nixos.services.redis.instances.misskey;
in
''
url: https://${misskey.hostname}/
port: ${toString misskey.port}
db:
host: 127.0.0.1
port: 5432
db: misskey
user: misskey
pass: ${placeholder."postgresql/misskey"}
extra:
statement_timeout: 60000
dbReplications: false
redis:
host: 127.0.0.1
port: ${toString redis.port}
pass: ${placeholder."redis/misskey"}
meilisearch:
host: 127.0.0.1
port: 7700
apiKey: ${placeholder."meilisearch/misskey"}
ssl: false
index: misskey
scope: global
id: 'aid'
proxyBypassHosts:
- api.deepl.com
- api-free.deepl.com
- www.recaptcha.net
- hcaptcha.com
- challenges.cloudflare.com
proxyRemoteFiles: true
signToActivityPubGet: true
maxFileSize: 1073741824
'';
owner = inputs.config.users.users.misskey.name;
};
users =
{
users.misskey = { isSystemUser = true; group = "misskey"; home = "/var/lib/misskey"; createHome = true; };
groups.misskey = {};
};
nixos.services =
{
redis.instances.misskey.port = 3545;
nginx =
{
enable = true;
httpProxy =
{
"${misskey.hostname}" =
{
upstream = "http://127.0.0.1:${toString misskey.port}";
websocket = true;
setHeaders.Host = misskey.hostname;
};
"direct.${misskey.hostname}" =
{
upstream = "http://127.0.0.1:${toString misskey.port}";
websocket = true;
setHeaders.Host = misskey.hostname;
detectAuth = true;
};
};
};
postgresql = { enable = true; instances.misskey = {}; };
meilisearch.instances.misskey = { user = inputs.config.users.users.misskey.name; port = 7700; };
};
})
(mkIf (misskey-proxy != {})
{
nixos.services.nginx =
{
enable = true;
httpProxy = listToAttrs (map
(proxy:
{
name = proxy.value.hostname;
value =
{
upstream = "https://direct.${proxy.value.hostname}";
websocket = true;
setHeaders.Host = "direct.${proxy.value.hostname}";
addAuth = true;
};
})
(attrsToList misskey-proxy));
};
})
];
}

View File

@@ -1,55 +1,55 @@
inputs:
{
options.nixos.services.nebula = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
# null: is lighthouse, non-empty string: is not lighthouse, and use this string as lighthouse address.
lighthouse = mkOption { type = types.nullOr types.nonEmptyStr; };
};
config =
let
inherit (inputs.lib) mkIf;
inherit (inputs.config.nixos.services) nebula;
inherit (builtins) concatStringsSep;
in mkIf nebula.enable
{
services.nebula.networks.nebula =
{
enable = true;
ca = ./ca.crt;
cert = ./. + "/${inputs.config.nixos.system.hostname}.crt";
key = inputs.config.sops.templates."nebula/key-template".path;
firewall.inbound = [ { host = "any"; port = "any"; proto = "any"; } ];
firewall.outbound = [ { host = "any"; port = "any"; proto = "any"; } ];
}
// (
if nebula.lighthouse == null then { isLighthouse = true; }
else
{
lighthouses = [ "192.168.82.1" ];
staticHostMap."192.168.82.1" = [ "${nebula.lighthouse}:4242" ];
listen.port = 0;
}
);
sops =
{
templates."nebula/key-template" =
{
content = concatStringsSep "\n"
[
"-----BEGIN NEBULA X25519 PRIVATE KEY-----"
inputs.config.sops.placeholder."nebula/key"
"-----END NEBULA X25519 PRIVATE KEY-----"
];
owner = inputs.config.systemd.services."nebula@nebula".serviceConfig.User;
group = inputs.config.systemd.services."nebula@nebula".serviceConfig.Group;
};
secrets."nebula/key" = {};
};
networking.firewall = if nebula.lighthouse != null then {} else
{
allowedTCPPorts = [ 4242 ];
allowedUDPPorts = [ 4242 ];
};
};
options.nixos.services.nebula = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
# null: is lighthouse, non-empty string: is not lighthouse, and use this string as lighthouse address.
lighthouse = mkOption { type = types.nullOr types.nonEmptyStr; };
};
config =
let
inherit (inputs.lib) mkIf;
inherit (inputs.config.nixos.services) nebula;
inherit (builtins) concatStringsSep;
in mkIf nebula.enable
{
services.nebula.networks.nebula =
{
enable = true;
ca = ./ca.crt;
cert = ./. + "/${inputs.config.nixos.system.hostname}.crt";
key = inputs.config.sops.templates."nebula/key-template".path;
firewall.inbound = [ { host = "any"; port = "any"; proto = "any"; } ];
firewall.outbound = [ { host = "any"; port = "any"; proto = "any"; } ];
}
// (
if nebula.lighthouse == null then { isLighthouse = true; }
else
{
lighthouses = [ "192.168.82.1" ];
staticHostMap."192.168.82.1" = [ "${nebula.lighthouse}:4242" ];
listen.port = 0;
}
);
sops =
{
templates."nebula/key-template" =
{
content = concatStringsSep "\n"
[
"-----BEGIN NEBULA X25519 PRIVATE KEY-----"
inputs.config.sops.placeholder."nebula/key"
"-----END NEBULA X25519 PRIVATE KEY-----"
];
owner = inputs.config.systemd.services."nebula@nebula".serviceConfig.User;
group = inputs.config.systemd.services."nebula@nebula".serviceConfig.Group;
};
secrets."nebula/key" = {};
};
networking.firewall = if nebula.lighthouse != null then {} else
{
allowedTCPPorts = [ 4242 ];
allowedUDPPorts = [ 4242 ];
};
};
}

View File

@@ -1,267 +1,264 @@
inputs:
{
options.nixos.services.nginx = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
transparentProxy =
{
enable = mkOption { type = types.bool; default = true; };
externalIp = mkOption { type = types.nonEmptyStr; };
map = mkOption { type = types.attrsOf types.ints.unsigned; default = {};};
};
httpProxy = mkOption
{
type = types.attrsOf (types.submodule { options =
{
upstream = mkOption { type = types.nonEmptyStr; };
rewriteHttps = mkOption { type = types.bool; default = false; };
websocket = mkOption { type = types.bool; default = false; };
http2 = mkOption { type = types.bool; default = true; };
setHeaders = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
addAuth = mkOption { type = types.bool; default = false; };
detectAuth = mkOption { type = types.bool; default = false; };
};});
default = {};
};
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.config.nixos.services) nginx;
inherit (builtins) map listToAttrs concatStringsSep toString filter attrValues;
in mkMerge
[
(mkIf nginx.enable
{
services =
{
nginx =
{
enable = true;
enableReload = true;
eventsConfig = stripeTabs
''
worker_connections 524288;
use epoll;
'';
commonHttpConfig = stripeTabs
''
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb {
$geoip2_data_country_code country iso_code;
}
log_format http '[$time_local] $remote_addr-$geoip2_data_country_code "$host"'
' $request_length $bytes_sent $status "$request" referer: "$http_referer" ua: "$http_user_agent"';
access_log syslog:server=unix:/dev/log http;
proxy_ssl_server_name on;
proxy_ssl_session_reuse off;
send_timeout 10m;
'';
proxyTimeout = "10m";
virtualHosts = listToAttrs (map
(site:
{
inherit (site) name;
value =
{
serverName = site.name;
listen =
[
{ addr = "127.0.0.1"; port = (if site.value.http2 then 443 else 3065); ssl = true; }
{ addr = "0.0.0.0"; port = 80; }
];
useACMEHost = site.name;
locations."/" =
{
proxyPass = site.value.upstream;
proxyWebsockets = site.value.websocket;
recommendedProxySettings = false;
recommendedProxySettingsNoHost = true;
basicAuthFile =
if site.value.detectAuth then
inputs.config.sops.secrets."nginx/detectAuth/${site.name}".path
else null;
extraConfig = concatStringsSep "\n"
(
(map
(header: "proxy_set_header ${header.name} ${header.value};")
(attrsToList site.value.setHeaders))
++ (if site.value.detectAuth then ["proxy_hide_header Authorization;"] else [])
++ (
if site.value.addAuth then
["include ${inputs.config.sops.templates."nginx/addAuth/${site.name}-template".path};"]
else [])
);
};
addSSL = true;
forceSSL = site.value.rewriteHttps;
http2 = site.value.http2;
};
})
(attrsToList nginx.httpProxy));
recommendedZstdSettings = true;
recommendedTlsSettings = true;
recommendedProxySettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedBrotliSettings = true;
clientMaxBodySize = "0";
package =
let
nginx-geoip2 =
{
name = "ngx_http_geoip2_module";
src = inputs.pkgs.fetchFromGitHub
{
owner = "leev";
repo = "ngx_http_geoip2_module";
rev = "a607a41a8115fecfc05b5c283c81532a3d605425";
hash = "sha256-CkmaeEa1iEAabJEDu3FhBUR7QF38koGYlyx+pyKZV9Y=";
};
meta.license = [];
};
in
(inputs.pkgs.nginxMainline.override (prev: { modules = prev.modules ++ [ nginx-geoip2 ]; }))
.overrideAttrs (prev: { buildInputs = prev.buildInputs ++ [ inputs.pkgs.libmaxminddb ]; });
};
geoipupdate =
{
enable = true;
settings =
{
AccountID = 901296;
LicenseKey = inputs.config.sops.secrets."nginx/maxmind-license".path;
EditionIDs = [ "GeoLite2-ASN" "GeoLite2-City" "GeoLite2-Country" ];
};
};
};
sops =
{
templates = listToAttrs (map
(site:
{
name = "nginx/addAuth/${site.name}-template";
value =
{
content =
let placeholder = inputs.config.sops.placeholder."nginx/addAuth/${site.name}";
in ''proxy_set_header Authorization "Basic ${placeholder}";'';
owner = inputs.config.users.users.nginx.name;
};
})
(filter (site: site.value.addAuth) (attrsToList nginx.httpProxy)));
secrets = { "nginx/maxmind-license".owner = inputs.config.users.users.nginx.name; }
// (listToAttrs (map
(site: { name = "nginx/detectAuth/${site.name}"; value.owner = inputs.config.users.users.nginx.name; })
(filter (site: site.value.detectAuth) (attrsToList nginx.httpProxy))))
// (listToAttrs (map
(site: { name = "nginx/addAuth/${site.name}"; value = {}; })
(filter (site: site.value.addAuth) (attrsToList nginx.httpProxy))));
};
systemd.services.nginx.serviceConfig =
{
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
LimitNPROC = 65536;
LimitNOFILE = 524288;
};
nixos.services.acme =
{
enable = true;
certs = map (cert: cert.name) (attrsToList nginx.httpProxy);
};
security.acme.certs = listToAttrs (map
(cert: { inherit (cert) name; value.group = inputs.config.services.nginx.group; })
(attrsToList nginx.httpProxy));
})
(mkIf nginx.transparentProxy.enable
{
services.nginx.streamConfig = stripeTabs
''
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb
{
$geoip2_data_country_code country iso_code;
}
log_format stream '[$time_local] $remote_addr-$geoip2_data_country_code "$ssl_preread_server_name"->$backend $bytes_sent $bytes_received';
access_log syslog:server=unix:/dev/log stream;
map $ssl_preread_server_name $backend
{
${concatStringsSep "\n" (map
(x: '' "${x.name}" 127.0.0.1:${toString x.value};'')
(
(attrsToList nginx.transparentProxy.map)
++ (map
(site: { name = site.name; value = (if site.value.http2 then 443 else 3065); })
(attrsToList nginx.httpProxy)
)
))}
default 127.0.0.1:443;
}
server
{
listen ${nginx.transparentProxy.externalIp}:443;
ssl_preread on;
proxy_bind $remote_addr transparent;
proxy_pass $backend;
proxy_connect_timeout 1s;
proxy_socket_keepalive on;
proxy_buffer_size 128k;
}
'';
networking.firewall.allowedTCPPorts = [ 80 443 ];
systemd.services.nginx-proxy =
let
ipset = "${inputs.pkgs.ipset}/bin/ipset";
iptables = "${inputs.pkgs.iptables}/bin/iptables";
ip = "${inputs.pkgs.iproute}/bin/ip";
start = inputs.pkgs.writeShellScript "nginx-proxy.start"
(
(
stripeTabs
''
${ipset} create nginx_proxy_port bitmap:port range 0-65535
${iptables} -t mangle -N nginx_proxy_mark
${iptables} -t mangle -A OUTPUT -j nginx_proxy_mark
${iptables} -t mangle -A nginx_proxy_mark -s 127.0.0.1 -p tcp \
-m set --match-set nginx_proxy_port src -j MARK --set-mark 2/2
${iptables} -t mangle -N nginx_proxy
${iptables} -t mangle -A PREROUTING -j nginx_proxy
${iptables} -t mangle -A nginx_proxy -s 127.0.0.1 -p tcp \
-m set --match-set nginx_proxy_port src -j MARK --set-mark 2/2
${ip} rule add fwmark 2/2 table 200
${ip} route add local 0.0.0.0/0 dev lo table 200
''
)
+ concatStringsSep "\n" (map
(port: ''${ipset} add nginx_proxy_port ${toString port}'')
(inputs.lib.unique ((attrValues nginx.transparentProxy.map) ++ [ 443 3065 ])))
);
stop = inputs.pkgs.writeShellScript "nginx-proxy.stop" (stripeTabs
''
${iptables} -t mangle -F nginx_proxy_mark
${iptables} -t mangle -D OUTPUT -j nginx_proxy_mark
${iptables} -t mangle -X nginx_proxy_mark
${iptables} -t mangle -F nginx_proxy
${iptables} -t mangle -D PREROUTING -j nginx_proxy
${iptables} -t mangle -X nginx_proxy
${ip} rule del fwmark 2/2 table 200
${ip} route del local 0.0.0.0/0 dev lo table 200
${ipset} destroy nginx_proxy_port
'');
in
{
description = "nginx transparent proxy";
after = [ "network.target" ];
serviceConfig =
{
Type = "simple";
RemainAfterExit = true;
ExecStart = start;
ExecStop = stop;
};
wants = [ "network.target" ];
wantedBy= [ "multi-user.target" ];
};
})
];
options.nixos.services.nginx = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
transparentProxy =
{
enable = mkOption { type = types.bool; default = true; };
externalIp = mkOption { type = types.nonEmptyStr; };
map = mkOption { type = types.attrsOf types.ints.unsigned; default = {};};
};
httpProxy = mkOption
{
type = types.attrsOf (types.submodule { options =
{
upstream = mkOption { type = types.nonEmptyStr; };
rewriteHttps = mkOption { type = types.bool; default = false; };
websocket = mkOption { type = types.bool; default = false; };
http2 = mkOption { type = types.bool; default = true; };
setHeaders = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
addAuth = mkOption { type = types.bool; default = false; };
detectAuth = mkOption { type = types.bool; default = false; };
};});
default = {};
};
};
config =
let
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.config.nixos.services) nginx;
inherit (builtins) map listToAttrs concatStringsSep toString filter attrValues;
in mkMerge
[
(mkIf nginx.enable
{
services =
{
nginx =
{
enable = true;
enableReload = true;
eventsConfig =
''
worker_connections 524288;
use epoll;
'';
commonHttpConfig =
''
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb {
$geoip2_data_country_code country iso_code;
}
log_format http '[$time_local] $remote_addr-$geoip2_data_country_code "$host"'
' $request_length $bytes_sent $status "$request" referer: "$http_referer" ua: "$http_user_agent"';
access_log syslog:server=unix:/dev/log http;
proxy_ssl_server_name on;
proxy_ssl_session_reuse off;
send_timeout 10m;
'';
proxyTimeout = "10m";
virtualHosts = listToAttrs (map
(site:
{
inherit (site) name;
value =
{
serverName = site.name;
listen =
[
{ addr = "127.0.0.1"; port = (if site.value.http2 then 443 else 3065); ssl = true; }
{ addr = "0.0.0.0"; port = 80; }
];
useACMEHost = site.name;
locations."/" =
{
proxyPass = site.value.upstream;
proxyWebsockets = site.value.websocket;
recommendedProxySettings = false;
recommendedProxySettingsNoHost = true;
basicAuthFile =
if site.value.detectAuth then
inputs.config.sops.secrets."nginx/detectAuth/${site.name}".path
else null;
extraConfig = concatStringsSep "\n"
(
(map
(header: "proxy_set_header ${header.name} ${header.value};")
(attrsToList site.value.setHeaders))
++ (if site.value.detectAuth then ["proxy_hide_header Authorization;"] else [])
++ (
if site.value.addAuth then
["include ${inputs.config.sops.templates."nginx/addAuth/${site.name}-template".path};"]
else [])
);
};
addSSL = true;
forceSSL = site.value.rewriteHttps;
http2 = site.value.http2;
};
})
(attrsToList nginx.httpProxy));
recommendedZstdSettings = true;
recommendedTlsSettings = true;
recommendedProxySettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedBrotliSettings = true;
clientMaxBodySize = "0";
package =
let
nginx-geoip2 =
{
name = "ngx_http_geoip2_module";
src = inputs.pkgs.fetchFromGitHub
{
owner = "leev";
repo = "ngx_http_geoip2_module";
rev = "a607a41a8115fecfc05b5c283c81532a3d605425";
hash = "sha256-CkmaeEa1iEAabJEDu3FhBUR7QF38koGYlyx+pyKZV9Y=";
};
meta.license = [];
};
in
(inputs.pkgs.nginxMainline.override (prev: { modules = prev.modules ++ [ nginx-geoip2 ]; }))
.overrideAttrs (prev: { buildInputs = prev.buildInputs ++ [ inputs.pkgs.libmaxminddb ]; });
};
geoipupdate =
{
enable = true;
settings =
{
AccountID = 901296;
LicenseKey = inputs.config.sops.secrets."nginx/maxmind-license".path;
EditionIDs = [ "GeoLite2-ASN" "GeoLite2-City" "GeoLite2-Country" ];
};
};
};
sops =
{
templates = listToAttrs (map
(site:
{
name = "nginx/addAuth/${site.name}-template";
value =
{
content =
let placeholder = inputs.config.sops.placeholder."nginx/addAuth/${site.name}";
in ''proxy_set_header Authorization "Basic ${placeholder}";'';
owner = inputs.config.users.users.nginx.name;
};
})
(filter (site: site.value.addAuth) (attrsToList nginx.httpProxy)));
secrets = { "nginx/maxmind-license".owner = inputs.config.users.users.nginx.name; }
// (listToAttrs (map
(site: { name = "nginx/detectAuth/${site.name}"; value.owner = inputs.config.users.users.nginx.name; })
(filter (site: site.value.detectAuth) (attrsToList nginx.httpProxy))))
// (listToAttrs (map
(site: { name = "nginx/addAuth/${site.name}"; value = {}; })
(filter (site: site.value.addAuth) (attrsToList nginx.httpProxy))));
};
systemd.services.nginx.serviceConfig =
{
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
LimitNPROC = 65536;
LimitNOFILE = 524288;
};
nixos.services.acme =
{
enable = true;
certs = map (cert: cert.name) (attrsToList nginx.httpProxy);
};
security.acme.certs = listToAttrs (map
(cert: { inherit (cert) name; value.group = inputs.config.services.nginx.group; })
(attrsToList nginx.httpProxy));
})
(mkIf nginx.transparentProxy.enable
{
services.nginx.streamConfig =
''
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb
{
$geoip2_data_country_code country iso_code;
}
log_format stream '[$time_local] $remote_addr-$geoip2_data_country_code "$ssl_preread_server_name"->$backend $bytes_sent $bytes_received';
access_log syslog:server=unix:/dev/log stream;
map $ssl_preread_server_name $backend
{
${concatStringsSep "\n" (map
(x: '' "${x.name}" 127.0.0.1:${toString x.value};'')
(
(attrsToList nginx.transparentProxy.map)
++ (map
(site: { name = site.name; value = (if site.value.http2 then 443 else 3065); })
(attrsToList nginx.httpProxy)
)
))}
default 127.0.0.1:443;
}
server
{
listen ${nginx.transparentProxy.externalIp}:443;
ssl_preread on;
proxy_bind $remote_addr transparent;
proxy_pass $backend;
proxy_connect_timeout 1s;
proxy_socket_keepalive on;
proxy_buffer_size 128k;
}
'';
networking.firewall.allowedTCPPorts = [ 80 443 ];
systemd.services.nginx-proxy =
let
ipset = "${inputs.pkgs.ipset}/bin/ipset";
iptables = "${inputs.pkgs.iptables}/bin/iptables";
ip = "${inputs.pkgs.iproute}/bin/ip";
start = inputs.pkgs.writeShellScript "nginx-proxy.start"
(
''
${ipset} create nginx_proxy_port bitmap:port range 0-65535
${iptables} -t mangle -N nginx_proxy_mark
${iptables} -t mangle -A OUTPUT -j nginx_proxy_mark
${iptables} -t mangle -A nginx_proxy_mark -s 127.0.0.1 -p tcp \
-m set --match-set nginx_proxy_port src -j MARK --set-mark 2/2
${iptables} -t mangle -N nginx_proxy
${iptables} -t mangle -A PREROUTING -j nginx_proxy
${iptables} -t mangle -A nginx_proxy -s 127.0.0.1 -p tcp \
-m set --match-set nginx_proxy_port src -j MARK --set-mark 2/2
${ip} rule add fwmark 2/2 table 200
${ip} route add local 0.0.0.0/0 dev lo table 200
''
+ concatStringsSep "\n" (map
(port: ''${ipset} add nginx_proxy_port ${toString port}'')
(inputs.lib.unique ((attrValues nginx.transparentProxy.map) ++ [ 443 3065 ])))
);
stop = inputs.pkgs.writeShellScript "nginx-proxy.stop"
''
${iptables} -t mangle -F nginx_proxy_mark
${iptables} -t mangle -D OUTPUT -j nginx_proxy_mark
${iptables} -t mangle -X nginx_proxy_mark
${iptables} -t mangle -F nginx_proxy
${iptables} -t mangle -D PREROUTING -j nginx_proxy
${iptables} -t mangle -X nginx_proxy
${ip} rule del fwmark 2/2 table 200
${ip} route del local 0.0.0.0/0 dev lo table 200
${ipset} destroy nginx_proxy_port
'';
in
{
description = "nginx transparent proxy";
after = [ "network.target" ];
serviceConfig =
{
Type = "simple";
RemainAfterExit = true;
ExecStart = start;
ExecStop = stop;
};
wants = [ "network.target" ];
wantedBy= [ "multi-user.target" ];
};
})
];
}

View File

@@ -1,87 +1,87 @@
inputs:
{
options.nixos.services.postgresql = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
instances = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
database = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
user = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
passwordFile = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) postgresql;
inherit (inputs.lib) mkMerge mkAfter concatStringsSep mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (builtins) map listToAttrs filter;
in mkIf postgresql.enable
{
services =
{
postgresql =
{
enable = true;
package = inputs.pkgs.postgresql_15;
enableTCPIP = true;
authentication = "host all all 0.0.0.0/0 md5";
settings =
{
unix_socket_permissions = "0700";
shared_buffers = "8192MB";
work_mem = "512MB";
autovacuum = "on";
};
# log_timezone = 'Asia/Shanghai'
# datestyle = 'iso, mdy'
# timezone = 'Asia/Shanghai'
# lc_messages = 'en_US.utf8'
# lc_monetary = 'en_US.utf8'
# lc_numeric = 'en_US.utf8'
# lc_time = 'en_US.utf8'
# default_text_search_config = 'pg_catalog.english'
# plperl.on_init = 'use utf8; use re; package utf8; require "utf8_heavy.pl";'
# mv /path/to/dir /path/to/dir_old
# mkdir /path/to/dir
# chattr +C /path/to/dir
# cp -a --reflink=never /path/to/dir_old/. /path/to/dir
# rm -rf /path/to/dir_old
ensureDatabases = map (db: db.value.database) (attrsToList postgresql.instances);
ensureUsers = map (db: { name = db.value.user; }) (attrsToList postgresql.instances);
};
postgresqlBackup =
{
enable = true;
pgdumpOptions = "-Fc";
compression = "none";
databases = map (db: db.value.database) (attrsToList postgresql.instances);
};
};
systemd.services.postgresql.postStart = mkAfter (concatStringsSep "\n" (map
(db:
let
passwordFile =
if db.value.passwordFile or null != null then db.value.passwordFile
else inputs.config.sops.secrets."postgresql/${db.value.user}".path;
in
# set user password
"$PSQL -tAc \"ALTER USER ${db.value.user} with encrypted password '$(cat ${passwordFile})'\""
# set db owner
+ "\n"
+ "$PSQL -tAc \"select pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d"
+ " WHERE d.datname = '${db.value.database}' ORDER BY 1\""
+ " | grep -E '^${db.value.user}$' -q"
+ " || $PSQL -tAc \"ALTER DATABASE ${db.value.database} OWNER TO ${db.value.user}\"")
(attrsToList postgresql.instances)));
sops.secrets = listToAttrs (map
(db: { name = "postgresql/${db.value.user}"; value.owner = inputs.config.users.users.postgres.name; })
(filter (db: db.value.passwordFile == null) (attrsToList postgresql.instances)));
};
options.nixos.services.postgresql = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
instances = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
database = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
user = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
passwordFile = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) postgresql;
inherit (inputs.lib) mkMerge mkAfter concatStringsSep mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (builtins) map listToAttrs filter;
in mkIf postgresql.enable
{
services =
{
postgresql =
{
enable = true;
package = inputs.pkgs.postgresql_15;
enableTCPIP = true;
authentication = "host all all 0.0.0.0/0 md5";
settings =
{
unix_socket_permissions = "0700";
shared_buffers = "8192MB";
work_mem = "512MB";
autovacuum = "on";
};
# log_timezone = 'Asia/Shanghai'
# datestyle = 'iso, mdy'
# timezone = 'Asia/Shanghai'
# lc_messages = 'en_US.utf8'
# lc_monetary = 'en_US.utf8'
# lc_numeric = 'en_US.utf8'
# lc_time = 'en_US.utf8'
# default_text_search_config = 'pg_catalog.english'
# plperl.on_init = 'use utf8; use re; package utf8; require "utf8_heavy.pl";'
# mv /path/to/dir /path/to/dir_old
# mkdir /path/to/dir
# chattr +C /path/to/dir
# cp -a --reflink=never /path/to/dir_old/. /path/to/dir
# rm -rf /path/to/dir_old
ensureDatabases = map (db: db.value.database) (attrsToList postgresql.instances);
ensureUsers = map (db: { name = db.value.user; }) (attrsToList postgresql.instances);
};
postgresqlBackup =
{
enable = true;
pgdumpOptions = "-Fc";
compression = "none";
databases = map (db: db.value.database) (attrsToList postgresql.instances);
};
};
systemd.services.postgresql.postStart = mkAfter (concatStringsSep "\n" (map
(db:
let
passwordFile =
if db.value.passwordFile or null != null then db.value.passwordFile
else inputs.config.sops.secrets."postgresql/${db.value.user}".path;
in
# set user password
"$PSQL -tAc \"ALTER USER ${db.value.user} with encrypted password '$(cat ${passwordFile})'\""
# set db owner
+ "\n"
+ "$PSQL -tAc \"select pg_catalog.pg_get_userbyid(d.datdba) FROM pg_catalog.pg_database d"
+ " WHERE d.datname = '${db.value.database}' ORDER BY 1\""
+ " | grep -E '^${db.value.user}$' -q"
+ " || $PSQL -tAc \"ALTER DATABASE ${db.value.database} OWNER TO ${db.value.user}\"")
(attrsToList postgresql.instances)));
sops.secrets = listToAttrs (map
(db: { name = "postgresql/${db.value.user}"; value.owner = inputs.config.users.users.postgres.name; })
(filter (db: db.value.passwordFile == null) (attrsToList postgresql.instances)));
};
}
# sops.secrets.drone-agent = {
# owner = config.systemd.services.drone-agent.serviceConfig.User;

View File

@@ -1,45 +1,45 @@
inputs:
{
options.nixos.services.redis = let inherit (inputs.lib) mkOption types; in
{
instances = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
user = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
passwordFile = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
port = mkOption { type = types.ints.unsigned; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) redis;
inherit (inputs.localLib) attrsToList;
inherit (builtins) map listToAttrs filter;
in
{
services.redis.servers = listToAttrs (map
(server:
{
inherit (server) name;
value =
{
enable = true;
bind = null;
port = server.value.port;
user = server.value.user;
# unixSocket = null; # bug
unixSocketPerm = 600;
requirePassFile =
if server.value.passwordFile == null then inputs.config.sops.secrets."redis/${server.name}".path
else server.value.passwordFile;
};
})
(attrsToList redis.instances));
sops.secrets = listToAttrs (map
(server: { name = "redis/${server.name}"; value.owner = inputs.config.users.users.${server.name}.name; })
(filter (server: server.value.passwordFile == null) (attrsToList redis.instances)));
};
options.nixos.services.redis = let inherit (inputs.lib) mkOption types; in
{
instances = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
user = mkOption { type = types.nonEmptyStr; default = submoduleInputs.config._module.args.name; };
passwordFile = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
port = mkOption { type = types.ints.unsigned; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) redis;
inherit (inputs.localLib) attrsToList;
inherit (builtins) map listToAttrs filter;
in
{
services.redis.servers = listToAttrs (map
(server:
{
inherit (server) name;
value =
{
enable = true;
bind = null;
port = server.value.port;
user = server.value.user;
# unixSocket = null; # bug
unixSocketPerm = 600;
requirePassFile =
if server.value.passwordFile == null then inputs.config.sops.secrets."redis/${server.name}".path
else server.value.passwordFile;
};
})
(attrsToList redis.instances));
sops.secrets = listToAttrs (map
(server: { name = "redis/${server.name}"; value.owner = inputs.config.users.users.${server.name}.name; })
(filter (server: server.value.passwordFile == null) (attrsToList redis.instances)));
};
}

View File

@@ -1,71 +1,71 @@
inputs:
{
options.nixos.services.rsshub = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
port = mkOption { type = types.ints.unsigned; default = 5221; };
hostname = mkOption { type = types.str; default = "rsshub.chn.moe"; };
};
config =
let
inherit (inputs.config.nixos.services) rsshub;
inherit (inputs.localLib) stripeTabs;
inherit (inputs.lib) mkIf;
inherit (builtins) map listToAttrs toString;
in mkIf rsshub.enable
{
systemd.services.rsshub =
{
description = "rsshub";
after = [ "network.target" "redis-rsshub.service" ];
requires = [ "redis-rsshub.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig =
{
User = inputs.config.users.users.rsshub.name;
Group = inputs.config.users.users.rsshub.group;
EnvironmentFile = inputs.config.sops.templates."rsshub/env".path;
ExecStart = "${inputs.pkgs.localPackages.rsshub}/bin/rsshub";
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
};
};
sops =
{
templates."rsshub/env".content =
let
placeholder = inputs.config.sops.placeholder;
redis = inputs.config.nixos.services.redis.instances.rsshub;
in stripeTabs
''
PORT=${toString rsshub.port}
CACHE_TYPE=redis
REDIS_URL='redis://:${placeholder."redis/rsshub"}@127.0.0.1:${toString redis.port}'
PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}'
YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}'
YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}'
YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}'
YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}'
'';
secrets = (listToAttrs (map (secret: { name = "rsshub/${secret}"; value = {}; })
[
"pixiv-refreshtoken"
"youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token"
]));
};
users = { users.rsshub = { isSystemUser = true; group = "rsshub"; }; groups.rsshub = {}; };
nixos.services =
{
redis.instances.rsshub.port = 7116;
nginx =
{
enable = true;
httpProxy.${rsshub.hostname} =
{
upstream = "http://127.0.0.1:${toString rsshub.port}";
setHeaders.Host = rsshub.hostname;
};
};
};
};
options.nixos.services.rsshub = let inherit (inputs.lib) mkOption types; in
{
enable = mkOption { type = types.bool; default = false; };
port = mkOption { type = types.ints.unsigned; default = 5221; };
hostname = mkOption { type = types.str; default = "rsshub.chn.moe"; };
};
config =
let
inherit (inputs.config.nixos.services) rsshub;
inherit (inputs.localLib) stripeTabs;
inherit (inputs.lib) mkIf;
inherit (builtins) map listToAttrs toString;
in mkIf rsshub.enable
{
systemd.services.rsshub =
{
description = "rsshub";
after = [ "network.target" "redis-rsshub.service" ];
requires = [ "redis-rsshub.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig =
{
User = inputs.config.users.users.rsshub.name;
Group = inputs.config.users.users.rsshub.group;
EnvironmentFile = inputs.config.sops.templates."rsshub/env".path;
ExecStart = "${inputs.pkgs.localPackages.rsshub}/bin/rsshub";
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
};
};
sops =
{
templates."rsshub/env".content =
let
placeholder = inputs.config.sops.placeholder;
redis = inputs.config.nixos.services.redis.instances.rsshub;
in
''
PORT=${toString rsshub.port}
CACHE_TYPE=redis
REDIS_URL='redis://:${placeholder."redis/rsshub"}@127.0.0.1:${toString redis.port}'
PIXIV_REFRESHTOKEN='${placeholder."rsshub/pixiv-refreshtoken"}'
YOUTUBE_KEY='${placeholder."rsshub/youtube-key"}'
YOUTUBE_CLIENT_ID='${placeholder."rsshub/youtube-client-id"}'
YOUTUBE_CLIENT_SECRET='${placeholder."rsshub/youtube-client-secret"}'
YOUTUBE_REFRESH_TOKEN='${placeholder."rsshub/youtube-refresh-token"}'
'';
secrets = (listToAttrs (map (secret: { name = "rsshub/${secret}"; value = {}; })
[
"pixiv-refreshtoken"
"youtube-key" "youtube-client-id" "youtube-client-secret" "youtube-refresh-token"
]));
};
users = { users.rsshub = { isSystemUser = true; group = "rsshub"; }; groups.rsshub = {}; };
nixos.services =
{
redis.instances.rsshub.port = 7116;
nginx =
{
enable = true;
httpProxy.${rsshub.hostname} =
{
upstream = "http://127.0.0.1:${toString rsshub.port}";
setHeaders.Host = rsshub.hostname;
};
};
};
};
}

View File

@@ -1,168 +1,168 @@
inputs:
{
options.nixos.services = let inherit (inputs.lib) mkOption types; in
{
synapse =
{
enable = mkOption { type = types.bool; default = false; };
port = mkOption { type = types.ints.unsigned; default = 8008; };
hostname = mkOption { type = types.str; default = "synapse.chn.moe"; };
};
synapse-proxy = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
hostname = mkOption { type = types.str; default = submoduleInputs.config._module.args.name; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) synapse synapse-proxy;
inherit (inputs.localLib) attrsToList;
inherit (inputs.lib) mkIf mkMerge;
inherit (builtins) map listToAttrs;
in mkMerge
[
(mkIf synapse.enable
{
services.matrix-synapse =
{
enable = true;
settings =
{
server_name = synapse.hostname;
listeners =
[{
bind_addresses = [ "127.0.0.1" ];
port = 8008;
resources = [{ names = [ "client" "federation" ]; compress = false; }];
tls = false;
type = "http";
x_forwarded = true;
}];
database =
{
name = "psycopg2";
args =
{
user = "synapse";
database = "synapse";
host = "127.0.0.1";
port = "5432";
};
};
admin_contact = "mailto:chn@chn.moe";
enable_registration = true;
registrations_require_3pid = [ "email" ];
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
max_upload_size = "1024M";
web_client_location = "https://element.chn.moe/";
serve_server_wellknown = true;
report_stats = true;
trusted_key_servers = [{ server_name = "matrix.org"; }];
suppress_key_server_warning = true;
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
{
version = 1;
formatters.precise.format =
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
root = { level = "INFO"; handlers = [ "console" ]; };
disable_existing_loggers = true;
};
};
extraConfigFiles = [ inputs.config.sops.templates."synapse/password.yaml".path ];
};
sops =
{
templates."synapse/password.yaml" =
{
owner = inputs.config.systemd.services.matrix-synapse.serviceConfig.User;
group = inputs.config.systemd.services.matrix-synapse.serviceConfig.Group;
content = builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "password.yaml"
{
database =
{
name = "psycopg2";
args =
{
user = "synapse";
password = inputs.config.sops.placeholder."postgresql/synapse";
database = "synapse";
host = "127.0.0.1";
port = "5432";
};
allow_unsafe_locale = true;
};
turn_shared_secret = inputs.config.sops.placeholder."synapse/coturn";
registration_shared_secret = inputs.config.sops.placeholder."synapse/registration";
macaroon_secret_key = inputs.config.sops.placeholder."synapse/macaroon";
form_secret = inputs.config.sops.placeholder."synapse/form";
signing_key_path = inputs.config.sops.secrets."synapse/signing-key".path;
email =
{
smtp_host = "mail.chn.moe";
smtp_port = 25;
smtp_user = "bot@chn.moe";
smtp_pass = inputs.config.sops.placeholder."mail/bot";
require_transport_security = true;
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
app_name = "Haonan Chen's synapse";
};
});
};
secrets = (listToAttrs (map
(secret: { name = "synapse/${secret}"; value = {}; })
[ "coturn" "registration" "macaroon" "form" ]))
// { "synapse/signing-key".owner = inputs.config.systemd.services.matrix-synapse.serviceConfig.User; }
// { "mail/bot" = {}; };
};
nixos.services =
{
nginx =
{
enable = true;
httpProxy =
{
"${synapse.hostname}" =
{
upstream = "http://127.0.0.1:${toString synapse.port}";
websocket = true;
setHeaders.Host = synapse.hostname;
};
"direct.${synapse.hostname}" =
{
upstream = "http://127.0.0.1:${toString synapse.port}";
websocket = true;
setHeaders.Host = synapse.hostname;
detectAuth = true;
};
};
};
postgresql = { enable = true; instances.synapse = {}; };
};
})
(mkIf (synapse-proxy != {})
{
nixos.services.nginx =
{
enable = true;
httpProxy = listToAttrs (map
(proxy:
{
name = proxy.value.hostname;
value =
{
upstream = "https://direct.${proxy.value.hostname}";
websocket = true;
setHeaders.Host = "direct.${proxy.value.hostname}";
addAuth = true;
};
})
(attrsToList synapse-proxy));
};
})
];
options.nixos.services = let inherit (inputs.lib) mkOption types; in
{
synapse =
{
enable = mkOption { type = types.bool; default = false; };
port = mkOption { type = types.ints.unsigned; default = 8008; };
hostname = mkOption { type = types.str; default = "synapse.chn.moe"; };
};
synapse-proxy = mkOption
{
type = types.attrsOf (types.submodule (submoduleInputs: { options =
{
hostname = mkOption { type = types.str; default = submoduleInputs.config._module.args.name; };
};}));
default = {};
};
};
config =
let
inherit (inputs.config.nixos.services) synapse synapse-proxy;
inherit (inputs.localLib) attrsToList;
inherit (inputs.lib) mkIf mkMerge;
inherit (builtins) map listToAttrs;
in mkMerge
[
(mkIf synapse.enable
{
services.matrix-synapse =
{
enable = true;
settings =
{
server_name = synapse.hostname;
listeners =
[{
bind_addresses = [ "127.0.0.1" ];
port = 8008;
resources = [{ names = [ "client" "federation" ]; compress = false; }];
tls = false;
type = "http";
x_forwarded = true;
}];
database =
{
name = "psycopg2";
args =
{
user = "synapse";
database = "synapse";
host = "127.0.0.1";
port = "5432";
};
};
admin_contact = "mailto:chn@chn.moe";
enable_registration = true;
registrations_require_3pid = [ "email" ];
turn_uris = [ "turns:coturn.chn.moe" "turn:coturn.chn.moe" ];
max_upload_size = "1024M";
web_client_location = "https://element.chn.moe/";
serve_server_wellknown = true;
report_stats = true;
trusted_key_servers = [{ server_name = "matrix.org"; }];
suppress_key_server_warning = true;
log_config = (inputs.pkgs.formats.yaml {}).generate "log.yaml"
{
version = 1;
formatters.precise.format =
"%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s";
handlers.console = { class = "logging.StreamHandler"; formatter = "precise"; };
root = { level = "INFO"; handlers = [ "console" ]; };
disable_existing_loggers = true;
};
};
extraConfigFiles = [ inputs.config.sops.templates."synapse/password.yaml".path ];
};
sops =
{
templates."synapse/password.yaml" =
{
owner = inputs.config.systemd.services.matrix-synapse.serviceConfig.User;
group = inputs.config.systemd.services.matrix-synapse.serviceConfig.Group;
content = builtins.readFile ((inputs.pkgs.formats.yaml {}).generate "password.yaml"
{
database =
{
name = "psycopg2";
args =
{
user = "synapse";
password = inputs.config.sops.placeholder."postgresql/synapse";
database = "synapse";
host = "127.0.0.1";
port = "5432";
};
allow_unsafe_locale = true;
};
turn_shared_secret = inputs.config.sops.placeholder."synapse/coturn";
registration_shared_secret = inputs.config.sops.placeholder."synapse/registration";
macaroon_secret_key = inputs.config.sops.placeholder."synapse/macaroon";
form_secret = inputs.config.sops.placeholder."synapse/form";
signing_key_path = inputs.config.sops.secrets."synapse/signing-key".path;
email =
{
smtp_host = "mail.chn.moe";
smtp_port = 25;
smtp_user = "bot@chn.moe";
smtp_pass = inputs.config.sops.placeholder."mail/bot";
require_transport_security = true;
notif_from = "Your Friendly %(app)s homeserver <bot@chn.moe>";
app_name = "Haonan Chen's synapse";
};
});
};
secrets = (listToAttrs (map
(secret: { name = "synapse/${secret}"; value = {}; })
[ "coturn" "registration" "macaroon" "form" ]))
// { "synapse/signing-key".owner = inputs.config.systemd.services.matrix-synapse.serviceConfig.User; }
// { "mail/bot" = {}; };
};
nixos.services =
{
nginx =
{
enable = true;
httpProxy =
{
"${synapse.hostname}" =
{
upstream = "http://127.0.0.1:${toString synapse.port}";
websocket = true;
setHeaders.Host = synapse.hostname;
};
"direct.${synapse.hostname}" =
{
upstream = "http://127.0.0.1:${toString synapse.port}";
websocket = true;
setHeaders.Host = synapse.hostname;
detectAuth = true;
};
};
};
postgresql = { enable = true; instances.synapse = {}; };
};
})
(mkIf (synapse-proxy != {})
{
nixos.services.nginx =
{
enable = true;
httpProxy = listToAttrs (map
(proxy:
{
name = proxy.value.hostname;
value =
{
upstream = "https://direct.${proxy.value.hostname}";
websocket = true;
setHeaders.Host = "direct.${proxy.value.hostname}";
addAuth = true;
};
})
(attrsToList synapse-proxy));
};
})
];
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,264 +1,264 @@
inputs:
{
options.nixos.system = let inherit (inputs.lib) mkOption types; in
{
hostname = mkOption { type = types.nonEmptyStr; };
march = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
extraMarch = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
gui.enable = mkOption { type = types.bool; default = false; };
keepOutputs = mkOption { type = types.bool; default = false; };
};
config =
let
inherit (inputs.lib) mkMerge mkIf mkAfter;
inherit (inputs.localLib) mkConditional stripeTabs;
inherit (inputs.config.nixos) system;
in
mkMerge
[
# generic
{
nix =
{
settings =
{
system-features = [ "big-parallel" "nixos-test" "benchmark" ];
experimental-features = [ "nix-command" "flakes" ];
keep-outputs = inputs.config.nixos.system.keepOutputs;
keep-failed = true;
auto-optimise-store = true;
substituters = [ "https://cache.nixos.org/" "https://nix-store.chn.moe" ];
trusted-public-keys = [ "chn:Cc+nowW1LIpe1kyXOZmNaznFDiH1glXmpb4A+WD/DTE=" ];
show-trace = true;
max-jobs = 2;
cores = 0;
keep-going = true;
};
daemonIOSchedClass = "idle";
daemonCPUSchedPolicy = "idle";
registry =
{
nixpkgs.flake = inputs.topInputs.nixpkgs;
nixos.flake = inputs.topInputs.self;
};
nixPath = [ "nixpkgs=${inputs.topInputs.nixpkgs}" ];
};
services =
{
udev.extraRules = stripeTabs
''
ACTION=="add|change", KERNEL=="[sv]d[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="bfq"
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="bfq"
'';
dbus.implementation = "broker";
journald.extraConfig = "MaxRetentionSec=7d";
};
networking.networkmanager =
{
enable = true;
extraConfig = stripeTabs
"
[device]
keep-configuration=no
";
};
nixpkgs =
{
config.allowUnfree = true;
overlays = [(final: prev: { genericPackages = (inputs.topInputs.nixpkgs.lib.nixosSystem
{
system = "x86_64-linux";
modules = [{ config.nixpkgs.config.allowUnfree = true; }];
}).pkgs;})];
};
time.timeZone = "Asia/Shanghai";
system =
{
stateVersion = "22.11";
configurationRevision = inputs.topInputs.self.rev or "dirty";
};
boot =
{
kernel.sysctl =
{
"net.core.rmem_max" = 67108864;
"net.core.wmem_max" = 67108864;
"net.ipv4.tcp_rmem" = "4096 87380 67108864";
"net.ipv4.tcp_wmem" = "4096 65536 67108864";
"net.ipv4.tcp_mtu_probing" = true;
"net.ipv4.tcp_tw_reuse" = true;
"vm.swappiness" = 10;
"net.ipv4.tcp_max_syn_backlog" = 8388608;
"net.core.netdev_max_backlog" = 8388608;
"net.core.somaxconn" = 8388608;
"vm.oom_kill_allocating_task" = true;
"vm.oom_dump_tasks" = false;
"vm.overcommit_memory" = 1;
"dev.i915.perf_stream_paranoid" = false;
"net.ipv4.conf.all.route_localnet" = true;
"net.ipv4.conf.default.route_localnet" = true;
"net.ipv4.conf.all.accept_local" = true;
"net.ipv4.conf.default.accept_local" = true;
"net.ipv4.ip_forward" = true;
"net.ipv4.ip_nonlocal_bind" = true;
"net.bridge.bridge-nf-call-iptables" = false;
"net.bridge.bridge-nf-call-ip6tables" = false;
"net.bridge.bridge-nf-call-arptables" = false;
};
supportedFilesystems = [ "ntfs" ];
consoleLogLevel = 7;
};
hardware.enableAllFirmware = true;
systemd =
{
extraConfig = stripeTabs
"
DefaultTimeoutStopSec=10s
DefaultLimitNOFILE=1048576:1048576
";
user.extraConfig = "DefaultTimeoutStopSec=10s";
services =
{
nix-daemon =
{
serviceConfig = { CacheDirectory = "nix"; Slice = "-.slice"; Nice = "19"; };
environment = { TMPDIR = "/var/cache/nix"; };
};
systemd-tmpfiles-setup = { environment = { SYSTEMD_TMPFILES_FORCE_SUBVOL = "0"; }; };
};
timers.systemd-tmpfiles-clean.enable = false;
coredump.enable = false;
};
environment =
{
etc."channels/nixpkgs".source = inputs.topInputs.nixpkgs.outPath;
etc."nixos".source = inputs.topInputs.self.outPath;
sessionVariables = rec
{
XDG_CACHE_HOME = "$HOME/.cache";
XDG_CONFIG_HOME = "$HOME/.config";
XDG_DATA_HOME = "$HOME/.local/share";
XDG_STATE_HOME = "$HOME/.local/state";
# ANDROID_HOME = "${XDG_DATA_HOME}/android";
HISTFILE= "${XDG_STATE_HOME}/bash/history";
CUDA_CACHE_PATH = "${XDG_CACHE_HOME}/nv";
DOCKER_CONFIG = "${XDG_CONFIG_HOME}/docker";
GNUPGHOME = "${XDG_DATA_HOME}/gnupg";
GTK2_RC_FILES = "${XDG_CONFIG_HOME}/gtk-2.0/gtkrc";
XCOMPOSECACHE = "${XDG_CACHE_HOME}/X11/xcompose";
MATHEMATICA_USERBASE = "${XDG_CONFIG_HOME}/mathematica";
_JAVA_OPTIONS = "-Djava.util.prefs.userRoot=${XDG_CONFIG_HOME}/java";
};
};
i18n =
{
defaultLocale = "C.UTF-8";
supportedLocales = [ "zh_CN.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" "C.UTF-8/UTF-8" ];
};
# environment.pathsToLink = [ "/include" ];
# environment.variables.CPATH = "/run/current-system/sw/include";
# environment.variables.LIBRARY_PATH = "/run/current-system/sw/lib";
security.pam =
{
u2f =
{
enable = true;
cue = true;
appId = "pam://chn.moe";
origin = "pam://chn.moe";
# generate using `pamu2fcfg -u chn -o pam://chn.moe -i pam://chn.moe`
authFile = inputs.pkgs.writeText "yubikey_mappings" (builtins.concatStringsSep "\n"
[
(builtins.concatStringsSep ":"
[
"chn"
(builtins.concatStringsSep ","
[
"83Y3cLxhcmwbDOH1h67SQ1xy0dFBcoKYM0VO/YVq+9lpOpdPdmFaB7BNngO3xCmAxJeO/Fg9jNmEF9vMJEmAaw=="
"9bSjr+12JVwtHlyoa70J7w3bEQff+MwLxg5elzdP1OGHcfWGkolRvS+luAgcWjKn1g0swaYdnklCYWYOoCAJbA=="
"es256"
"+presence"
])
(builtins.concatStringsSep ","
[
"WgLCnlQcGP4uVHI8OZrJWoLK6ezHtl404NVGsfH2LXsq0TNVZ7l2OidGpbYqIJwTn5yKu6t0MI7KdHYD18T/HA=="
"GVPuwp38yb+A1Uur22hywW7mQJPOxuLXXKLlM9FU2bvVhpwdjWDvg+BB5YFAL9NjTW22V7Hy/a9UuSmZejs7dw=="
"es256"
"+presence"
])
])
]);
};
yubico =
{
enable = true;
id = "91291";
authFile = inputs.pkgs.writeText "yubikey_mappings" "chn:cccccbgrhnub";
};
};
virtualisation.oci-containers.backend = "docker";
}
# hostname
{ networking.hostName = system.hostname; }
# march
(
mkConditional (system.march != null)
{
nixpkgs =
{
hostPlatform = { system = "x86_64-linux"; gcc = { arch = system.march; tune = system.march; }; };
config.qchem-config.optArch = system.march;
};
nix.settings.system-features = [ "gccarch-${system.march}" ];
boot.kernelPatches =
[{
name = "native kernel";
patch = null;
extraStructuredConfig =
let
kernelConfig =
{
alderlake = "MALDERLAKE";
sandybridge = "MSANDYBRIDGE";
silvermont = "MSILVERMONT";
broadwell = "MBROADWELL";
znver2 = "MZEN2";
znver3 = "MZEN3";
};
in
{
GENERIC_CPU = inputs.lib.kernel.no;
${kernelConfig.${system.march}} = inputs.lib.kernel.yes;
};
}];
}
{ nixpkgs.hostPlatform = inputs.lib.mkDefault "x86_64-linux"; }
)
# extraMarch
{ nix.settings.system-features = map (march: "gccarch-${march}") system.extraMarch; }
# gui.enable
(mkIf inputs.config.nixos.system.gui.enable
{
services.xserver =
{
enable = true;
displayManager = { sddm.enable = true; defaultSession = "plasmawayland"; };
desktopManager.plasma5.enable = true;
videoDrivers = inputs.config.nixos.hardware.gpus;
};
systemd.services.display-manager.after = [ "network-online.target" ];
environment.sessionVariables."GTK_USE_PORTAL" = "1";
xdg.portal.extraPortals = with inputs.pkgs; [ xdg-desktop-portal-gtk xdg-desktop-portal-wlr ];
i18n.inputMethod =
{
enabled = "fcitx5";
fcitx5.addons = with inputs.pkgs; [ fcitx5-rime fcitx5-chinese-addons fcitx5-mozc ];
};
programs =
{
dconf.enable = true;
xwayland.enable = true;
};
})
];
options.nixos.system = let inherit (inputs.lib) mkOption types; in
{
hostname = mkOption { type = types.nonEmptyStr; };
march = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
extraMarch = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
gui.enable = mkOption { type = types.bool; default = false; };
keepOutputs = mkOption { type = types.bool; default = false; };
};
config =
let
inherit (inputs.lib) mkMerge mkIf mkAfter;
inherit (inputs.localLib) mkConditional stripeTabs;
inherit (inputs.config.nixos) system;
in
mkMerge
[
# generic
{
nix =
{
settings =
{
system-features = [ "big-parallel" "nixos-test" "benchmark" ];
experimental-features = [ "nix-command" "flakes" ];
keep-outputs = inputs.config.nixos.system.keepOutputs;
keep-failed = true;
auto-optimise-store = true;
substituters = [ "https://cache.nixos.org/" "https://nix-store.chn.moe" ];
trusted-public-keys = [ "chn:Cc+nowW1LIpe1kyXOZmNaznFDiH1glXmpb4A+WD/DTE=" ];
show-trace = true;
max-jobs = 2;
cores = 0;
keep-going = true;
};
daemonIOSchedClass = "idle";
daemonCPUSchedPolicy = "idle";
registry =
{
nixpkgs.flake = inputs.topInputs.nixpkgs;
nixos.flake = inputs.topInputs.self;
};
nixPath = [ "nixpkgs=${inputs.topInputs.nixpkgs}" ];
};
services =
{
udev.extraRules =
''
ACTION=="add|change", KERNEL=="[sv]d[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="bfq"
ACTION=="add|change", KERNEL=="nvme[0-9]n[0-9]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="bfq"
'';
dbus.implementation = "broker";
journald.extraConfig = "MaxRetentionSec=7d";
};
networking.networkmanager =
{
enable = true;
extraConfig =
''
[device]
keep-configuration=no
'';
};
nixpkgs =
{
config.allowUnfree = true;
overlays = [(final: prev: { genericPackages = (inputs.topInputs.nixpkgs.lib.nixosSystem
{
system = "x86_64-linux";
modules = [{ config.nixpkgs.config.allowUnfree = true; }];
}).pkgs;})];
};
time.timeZone = "Asia/Shanghai";
system =
{
stateVersion = "22.11";
configurationRevision = inputs.topInputs.self.rev or "dirty";
};
boot =
{
kernel.sysctl =
{
"net.core.rmem_max" = 67108864;
"net.core.wmem_max" = 67108864;
"net.ipv4.tcp_rmem" = "4096 87380 67108864";
"net.ipv4.tcp_wmem" = "4096 65536 67108864";
"net.ipv4.tcp_mtu_probing" = true;
"net.ipv4.tcp_tw_reuse" = true;
"vm.swappiness" = 10;
"net.ipv4.tcp_max_syn_backlog" = 8388608;
"net.core.netdev_max_backlog" = 8388608;
"net.core.somaxconn" = 8388608;
"vm.oom_kill_allocating_task" = true;
"vm.oom_dump_tasks" = false;
"vm.overcommit_memory" = 1;
"dev.i915.perf_stream_paranoid" = false;
"net.ipv4.conf.all.route_localnet" = true;
"net.ipv4.conf.default.route_localnet" = true;
"net.ipv4.conf.all.accept_local" = true;
"net.ipv4.conf.default.accept_local" = true;
"net.ipv4.ip_forward" = true;
"net.ipv4.ip_nonlocal_bind" = true;
"net.bridge.bridge-nf-call-iptables" = false;
"net.bridge.bridge-nf-call-ip6tables" = false;
"net.bridge.bridge-nf-call-arptables" = false;
};
supportedFilesystems = [ "ntfs" ];
consoleLogLevel = 7;
};
hardware.enableAllFirmware = true;
systemd =
{
extraConfig =
''
DefaultTimeoutStopSec=10s
DefaultLimitNOFILE=1048576:1048576
'';
user.extraConfig = "DefaultTimeoutStopSec=10s";
services =
{
nix-daemon =
{
serviceConfig = { CacheDirectory = "nix"; Slice = "-.slice"; Nice = "19"; };
environment = { TMPDIR = "/var/cache/nix"; };
};
systemd-tmpfiles-setup = { environment = { SYSTEMD_TMPFILES_FORCE_SUBVOL = "0"; }; };
};
timers.systemd-tmpfiles-clean.enable = false;
coredump.enable = false;
};
environment =
{
etc."channels/nixpkgs".source = inputs.topInputs.nixpkgs.outPath;
etc."nixos".source = inputs.topInputs.self.outPath;
sessionVariables = rec
{
XDG_CACHE_HOME = "$HOME/.cache";
XDG_CONFIG_HOME = "$HOME/.config";
XDG_DATA_HOME = "$HOME/.local/share";
XDG_STATE_HOME = "$HOME/.local/state";
# ANDROID_HOME = "${XDG_DATA_HOME}/android";
HISTFILE= "${XDG_STATE_HOME}/bash/history";
CUDA_CACHE_PATH = "${XDG_CACHE_HOME}/nv";
DOCKER_CONFIG = "${XDG_CONFIG_HOME}/docker";
GNUPGHOME = "${XDG_DATA_HOME}/gnupg";
GTK2_RC_FILES = "${XDG_CONFIG_HOME}/gtk-2.0/gtkrc";
XCOMPOSECACHE = "${XDG_CACHE_HOME}/X11/xcompose";
MATHEMATICA_USERBASE = "${XDG_CONFIG_HOME}/mathematica";
_JAVA_OPTIONS = "-Djava.util.prefs.userRoot=${XDG_CONFIG_HOME}/java";
};
};
i18n =
{
defaultLocale = "C.UTF-8";
supportedLocales = [ "zh_CN.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" "C.UTF-8/UTF-8" ];
};
# environment.pathsToLink = [ "/include" ];
# environment.variables.CPATH = "/run/current-system/sw/include";
# environment.variables.LIBRARY_PATH = "/run/current-system/sw/lib";
security.pam =
{
u2f =
{
enable = true;
cue = true;
appId = "pam://chn.moe";
origin = "pam://chn.moe";
# generate using `pamu2fcfg -u chn -o pam://chn.moe -i pam://chn.moe`
authFile = inputs.pkgs.writeText "yubikey_mappings" (builtins.concatStringsSep "\n"
[
(builtins.concatStringsSep ":"
[
"chn"
(builtins.concatStringsSep ","
[
"83Y3cLxhcmwbDOH1h67SQ1xy0dFBcoKYM0VO/YVq+9lpOpdPdmFaB7BNngO3xCmAxJeO/Fg9jNmEF9vMJEmAaw=="
"9bSjr+12JVwtHlyoa70J7w3bEQff+MwLxg5elzdP1OGHcfWGkolRvS+luAgcWjKn1g0swaYdnklCYWYOoCAJbA=="
"es256"
"+presence"
])
(builtins.concatStringsSep ","
[
"WgLCnlQcGP4uVHI8OZrJWoLK6ezHtl404NVGsfH2LXsq0TNVZ7l2OidGpbYqIJwTn5yKu6t0MI7KdHYD18T/HA=="
"GVPuwp38yb+A1Uur22hywW7mQJPOxuLXXKLlM9FU2bvVhpwdjWDvg+BB5YFAL9NjTW22V7Hy/a9UuSmZejs7dw=="
"es256"
"+presence"
])
])
]);
};
yubico =
{
enable = true;
id = "91291";
authFile = inputs.pkgs.writeText "yubikey_mappings" "chn:cccccbgrhnub";
};
};
virtualisation.oci-containers.backend = "docker";
}
# hostname
{ networking.hostName = system.hostname; }
# march
(
mkConditional (system.march != null)
{
nixpkgs =
{
hostPlatform = { system = "x86_64-linux"; gcc = { arch = system.march; tune = system.march; }; };
config.qchem-config.optArch = system.march;
};
nix.settings.system-features = [ "gccarch-${system.march}" ];
boot.kernelPatches =
[{
name = "native kernel";
patch = null;
extraStructuredConfig =
let
kernelConfig =
{
alderlake = "MALDERLAKE";
sandybridge = "MSANDYBRIDGE";
silvermont = "MSILVERMONT";
broadwell = "MBROADWELL";
znver2 = "MZEN2";
znver3 = "MZEN3";
};
in
{
GENERIC_CPU = inputs.lib.kernel.no;
${kernelConfig.${system.march}} = inputs.lib.kernel.yes;
};
}];
}
{ nixpkgs.hostPlatform = inputs.lib.mkDefault "x86_64-linux"; }
)
# extraMarch
{ nix.settings.system-features = map (march: "gccarch-${march}") system.extraMarch; }
# gui.enable
(mkIf inputs.config.nixos.system.gui.enable
{
services.xserver =
{
enable = true;
displayManager = { sddm.enable = true; defaultSession = "plasmawayland"; };
desktopManager.plasma5.enable = true;
videoDrivers = inputs.config.nixos.hardware.gpus;
};
systemd.services.display-manager.after = [ "network-online.target" ];
environment.sessionVariables."GTK_USE_PORTAL" = "1";
xdg.portal.extraPortals = with inputs.pkgs; [ xdg-desktop-portal-gtk xdg-desktop-portal-wlr ];
i18n.inputMethod =
{
enabled = "fcitx5";
fcitx5.addons = with inputs.pkgs; [ fcitx5-rime fcitx5-chinese-addons fcitx5-mozc ];
};
programs =
{
dconf.enable = true;
xwayland.enable = true;
};
})
];
}

View File

@@ -1,311 +1,311 @@
inputs:
{
config =
let
inherit (inputs.lib) listToAttrs mkMerge;
inherit (builtins) map;
inherit (inputs.localLib) stripeTabs;
in mkMerge
[
{
users =
{
users =
{
root =
{
shell = inputs.pkgs.zsh;
hashedPassword = "$y$j9T$.UyKKvDnmlJaYZAh6./rf/$65dRqishAiqxCE6LEMjqruwJPZte7uiyYLVKpzdZNH5";
openssh.authorizedKeys.keys =
[
("sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIPLByi05vCA95EfpgrCIXzkuyUWsyh"
+ "+Vso8FsUNFwPXFAAAABHNzaDo= chn@chn.moe")
];
};
chn =
{
isNormalUser = true;
extraGroups = inputs.lib.intersectLists
[ "adbusers" "networkmanager" "wheel" "wireshark" "libvirtd" "video" "audio" ]
(builtins.attrNames inputs.config.users.groups);
shell = inputs.pkgs.zsh;
autoSubUidGidRange = true;
hashedPassword = "$y$j9T$xJwVBoGENJEDSesJ0LfkU1$VEExaw7UZtFyB4VY1yirJvl7qS7oiF49KbEBrV0.hhC";
};
};
mutableUsers = false;
};
}
# (mkMerge (map (user:
# {
# sops.secrets."password/${user}".neededForUsers = true;
# users.users.${user}.passwordFile = inputs.config.sops.secrets."password/${user}".path;
# }) [ "root" "chn" ]))
{
home-manager =
{
useGlobalPkgs = true;
useUserPackages = true;
users =
let
normal = { gui ? false }: { pkgs, ...}:
{
home.stateVersion = "22.11";
programs =
{
zsh =
{
enable = true;
initExtraBeforeCompInit = stripeTabs
''
# p10k instant prompt
typeset -g POWERLEVEL9K_INSTANT_PROMPT=off
P10K_INSTANT_PROMPT="$XDG_CACHE_HOME/p10k-instant-prompt-''${(%):-%n}.zsh"
[[ ! -r "$P10K_INSTANT_PROMPT" ]] || source "$P10K_INSTANT_PROMPT"
config =
let
inherit (inputs.lib) listToAttrs mkMerge;
inherit (builtins) map;
inherit (inputs.localLib) stripeTabs;
in mkMerge
[
{
users =
{
users =
{
root =
{
shell = inputs.pkgs.zsh;
hashedPassword = "$y$j9T$.UyKKvDnmlJaYZAh6./rf/$65dRqishAiqxCE6LEMjqruwJPZte7uiyYLVKpzdZNH5";
openssh.authorizedKeys.keys =
[
("sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIPLByi05vCA95EfpgrCIXzkuyUWsyh"
+ "+Vso8FsUNFwPXFAAAABHNzaDo= chn@chn.moe")
];
};
chn =
{
isNormalUser = true;
extraGroups = inputs.lib.intersectLists
[ "adbusers" "networkmanager" "wheel" "wireshark" "libvirtd" "video" "audio" ]
(builtins.attrNames inputs.config.users.groups);
shell = inputs.pkgs.zsh;
autoSubUidGidRange = true;
hashedPassword = "$y$j9T$xJwVBoGENJEDSesJ0LfkU1$VEExaw7UZtFyB4VY1yirJvl7qS7oiF49KbEBrV0.hhC";
};
};
mutableUsers = false;
};
}
# (mkMerge (map (user:
# {
# sops.secrets."password/${user}".neededForUsers = true;
# users.users.${user}.passwordFile = inputs.config.sops.secrets."password/${user}".path;
# }) [ "root" "chn" ]))
{
home-manager =
{
useGlobalPkgs = true;
useUserPackages = true;
users =
let
normal = { gui ? false }: { pkgs, ...}:
{
home.stateVersion = "22.11";
programs =
{
zsh =
{
enable = true;
initExtraBeforeCompInit =
''
# p10k instant prompt
typeset -g POWERLEVEL9K_INSTANT_PROMPT=off
P10K_INSTANT_PROMPT="$XDG_CACHE_HOME/p10k-instant-prompt-''${(%):-%n}.zsh"
[[ ! -r "$P10K_INSTANT_PROMPT" ]] || source "$P10K_INSTANT_PROMPT"
HYPHEN_INSENSITIVE="true"
HYPHEN_INSENSITIVE="true"
export PATH=~/bin:$PATH
export PATH=~/bin:$PATH
function br
{
local cmd cmd_file code
cmd_file=$(mktemp)
if broot --outcmd "$cmd_file" "$@"; then
cmd=$(<"$cmd_file")
command rm -f "$cmd_file"
eval "$cmd"
else
code=$?
command rm -f "$cmd_file"
return "$code"
fi
}
function br
{
local cmd cmd_file code
cmd_file=$(mktemp)
if broot --outcmd "$cmd_file" "$@"; then
cmd=$(<"$cmd_file")
command rm -f "$cmd_file"
eval "$cmd"
else
code=$?
command rm -f "$cmd_file"
return "$code"
fi
}
alias todo="todo.sh"
'';
plugins =
[
{
file = "powerlevel10k.zsh-theme";
name = "powerlevel10k";
src = "${pkgs.zsh-powerlevel10k}/share/zsh-powerlevel10k";
}
{
file = "p10k.zsh";
name = "powerlevel10k-config";
src = ./p10k-config;
}
{
name = "zsh-lsd";
src = pkgs.fetchFromGitHub
{
owner = "z-shell";
repo = "zsh-lsd";
rev = "029a9cb0a9b39c9eb6c5b5100dd9182813332250";
sha256 = "sha256-oWjWnhiimlGBMaZlZB+OM47jd9hporKlPNwCx6524Rk=";
};
}
];
history =
{
extended = true;
save = 100000000;
size = 100000000;
share = true;
};
};
direnv = { enable = true; nix-direnv.enable = true; };
git =
{
enable = true;
lfs.enable = true;
userEmail = "chn@chn.moe";
userName = "chn";
extraConfig =
{
core.editor = if gui then "code --wait" else "vim";
advice.detachedHead = false;
merge.conflictstyle = "diff3";
diff.colorMoved = "default";
};
package = pkgs.gitFull;
delta =
{
enable = true;
options =
{
side-by-side = true;
navigate = true;
syntax-theme = "GitHub";
light = true;
zero-style = "syntax white";
line-numbers-zero-style = "#ffffff";
};
};
};
ssh =
{
enable = true;
controlMaster = "auto";
controlPersist = "1m";
compression = true;
matchBlocks = builtins.listToAttrs
(
(map
(host:
{
name = host.name;
value = { host = host.name; hostname = host.value; user = "chn"; };
})
(inputs.localLib.attrsToList
{
vps3 = "vps3.chn.moe";
vps4 = "vps4.chn.moe";
vps5 = "vps5.chn.moe";
vps6 = "vps6.chn.moe";
vps7 = "vps7.chn.moe";
nas = "192.168.1.188";
}))
++ (map
(host:
{
name = host;
value =
{
host = host;
hostname = "hpc.xmu.edu.cn";
user = host;
extraOptions = { PubkeyAcceptedAlgorithms = "+ssh-rsa"; HostkeyAlgorithms = "+ssh-rsa"; };
};
})
[ "wlin" "jykang" "hwang" ])
)
// {
xmupc1 =
{
host = "xmupc1";
hostname = "office.chn.moe";
user = "chn";
port = 6007;
};
xmupc1-ext =
{
host = "xmupc1-ext";
hostname = "vps3.chn.moe";
user = "chn";
port = 6007;
};
xmuhk =
{
host = "xmuhk";
hostname = "10.26.14.56";
user = "xmuhk";
# identityFile = "~/.ssh/xmuhk_id_rsa";
};
xmuhk2 =
{
host = "xmuhk2";
hostname = "183.233.219.132";
user = "xmuhk";
port = 62022;
};
};
};
vim =
{
enable = true;
defaultEditor = true;
settings =
{
number = true;
expandtab = false;
shiftwidth = 2;
tabstop = 2;
};
extraConfig = inputs.localLib.stripeTabs
''
set clipboard=unnamedplus
colorscheme evening
'';
};
chromium =
{
package = inputs.topInputs.nixpkgs-stable.legacyPackages.x86_64-linux.chromium;
enable = inputs.config.programs.chromium.enable && gui;
extensions =
[
{ id = "mpkodccbngfoacfalldjimigbofkhgjn"; } # Aria2 Explorer
{ id = "nngceckbapebfimnlniiiahkandclblb"; } # Bitwarden
{ id = "kbfnbcaeplbcioakkpcpgfkobkghlhen"; } # Grammarly
{ id = "ihnfpdchjnmlehnoeffgcbakfmdjcckn"; } # Pixiv Fanbox Downloader
{ id = "cimiefiiaegbelhefglklhhakcgmhkai"; } # Plasma Integration
{ id = "dkndmhgdcmjdmkdonmbgjpijejdcilfh"; } # Powerful Pixiv Downloader
{ id = "padekgcemlokbadohgkifijomclgjgif"; } # Proxy SwitchyOmega
{ id = "kefjpfngnndepjbopdmoebkipbgkggaa"; } # RSSHub Radar
{ id = "abpdnfjocnmdomablahdcfnoggeeiedb"; } # Save All Resources
{ id = "nbokbjkabcmbfdlbddjidfmibcpneigj"; } # SmoothScroll
{ id = "onepmapfbjohnegdmfhndpefjkppbjkm"; } # SuperCopy 超级复制
{ id = "cjpalhdlnbpafiamejdnhcphjbkeiagm"; } # uBlock Origin
{ id = "gppongmhjkpfnbhagpmjfkannfbllamg"; } # Wappalyzer
{ id = "hkbdddpiemdeibjoknnofflfgbgnebcm"; } # YouTube™ 双字幕
{ id = "ekhagklcjbdpajgpjgmbionohlpdbjgc"; } # Zotero Connector
{ id = "ikhdkkncnoglghljlkmcimlnlhkeamad"; } # 划词翻译
{ id = "dhdgffkkebhmkfjojejmpbldmpobfkfo"; } # 篡改猴
{ id = "hipekcciheckooncpjeljhnekcoolahp"; } # Tabliss
];
};
};
};
in
{
root = normal { gui = false; };
chn = normal { gui = inputs.config.nixos.system.gui.enable; };
};
};
}
];
alias todo="todo.sh"
'';
plugins =
[
{
file = "powerlevel10k.zsh-theme";
name = "powerlevel10k";
src = "${pkgs.zsh-powerlevel10k}/share/zsh-powerlevel10k";
}
{
file = "p10k.zsh";
name = "powerlevel10k-config";
src = ./p10k-config;
}
{
name = "zsh-lsd";
src = pkgs.fetchFromGitHub
{
owner = "z-shell";
repo = "zsh-lsd";
rev = "029a9cb0a9b39c9eb6c5b5100dd9182813332250";
sha256 = "sha256-oWjWnhiimlGBMaZlZB+OM47jd9hporKlPNwCx6524Rk=";
};
}
];
history =
{
extended = true;
save = 100000000;
size = 100000000;
share = true;
};
};
direnv = { enable = true; nix-direnv.enable = true; };
git =
{
enable = true;
lfs.enable = true;
userEmail = "chn@chn.moe";
userName = "chn";
extraConfig =
{
core.editor = if gui then "code --wait" else "vim";
advice.detachedHead = false;
merge.conflictstyle = "diff3";
diff.colorMoved = "default";
};
package = pkgs.gitFull;
delta =
{
enable = true;
options =
{
side-by-side = true;
navigate = true;
syntax-theme = "GitHub";
light = true;
zero-style = "syntax white";
line-numbers-zero-style = "#ffffff";
};
};
};
ssh =
{
enable = true;
controlMaster = "auto";
controlPersist = "1m";
compression = true;
matchBlocks = builtins.listToAttrs
(
(map
(host:
{
name = host.name;
value = { host = host.name; hostname = host.value; user = "chn"; };
})
(inputs.localLib.attrsToList
{
vps3 = "vps3.chn.moe";
vps4 = "vps4.chn.moe";
vps5 = "vps5.chn.moe";
vps6 = "vps6.chn.moe";
vps7 = "vps7.chn.moe";
nas = "192.168.1.188";
}))
++ (map
(host:
{
name = host;
value =
{
host = host;
hostname = "hpc.xmu.edu.cn";
user = host;
extraOptions = { PubkeyAcceptedAlgorithms = "+ssh-rsa"; HostkeyAlgorithms = "+ssh-rsa"; };
};
})
[ "wlin" "jykang" "hwang" ])
)
// {
xmupc1 =
{
host = "xmupc1";
hostname = "office.chn.moe";
user = "chn";
port = 6007;
};
xmupc1-ext =
{
host = "xmupc1-ext";
hostname = "vps3.chn.moe";
user = "chn";
port = 6007;
};
xmuhk =
{
host = "xmuhk";
hostname = "10.26.14.56";
user = "xmuhk";
# identityFile = "~/.ssh/xmuhk_id_rsa";
};
xmuhk2 =
{
host = "xmuhk2";
hostname = "183.233.219.132";
user = "xmuhk";
port = 62022;
};
};
};
vim =
{
enable = true;
defaultEditor = true;
settings =
{
number = true;
expandtab = false;
shiftwidth = 2;
tabstop = 2;
};
extraConfig =
''
set clipboard=unnamedplus
colorscheme evening
'';
};
chromium =
{
package = inputs.topInputs.nixpkgs-stable.legacyPackages.x86_64-linux.chromium;
enable = inputs.config.programs.chromium.enable && gui;
extensions =
[
{ id = "mpkodccbngfoacfalldjimigbofkhgjn"; } # Aria2 Explorer
{ id = "nngceckbapebfimnlniiiahkandclblb"; } # Bitwarden
{ id = "kbfnbcaeplbcioakkpcpgfkobkghlhen"; } # Grammarly
{ id = "ihnfpdchjnmlehnoeffgcbakfmdjcckn"; } # Pixiv Fanbox Downloader
{ id = "cimiefiiaegbelhefglklhhakcgmhkai"; } # Plasma Integration
{ id = "dkndmhgdcmjdmkdonmbgjpijejdcilfh"; } # Powerful Pixiv Downloader
{ id = "padekgcemlokbadohgkifijomclgjgif"; } # Proxy SwitchyOmega
{ id = "kefjpfngnndepjbopdmoebkipbgkggaa"; } # RSSHub Radar
{ id = "abpdnfjocnmdomablahdcfnoggeeiedb"; } # Save All Resources
{ id = "nbokbjkabcmbfdlbddjidfmibcpneigj"; } # SmoothScroll
{ id = "onepmapfbjohnegdmfhndpefjkppbjkm"; } # SuperCopy 超级复制
{ id = "cjpalhdlnbpafiamejdnhcphjbkeiagm"; } # uBlock Origin
{ id = "gppongmhjkpfnbhagpmjfkannfbllamg"; } # Wappalyzer
{ id = "hkbdddpiemdeibjoknnofflfgbgnebcm"; } # YouTube™ 双字幕
{ id = "ekhagklcjbdpajgpjgmbionohlpdbjgc"; } # Zotero Connector
{ id = "ikhdkkncnoglghljlkmcimlnlhkeamad"; } # 划词翻译
{ id = "dhdgffkkebhmkfjojejmpbldmpobfkfo"; } # 篡改猴
{ id = "hipekcciheckooncpjeljhnekcoolahp"; } # Tabliss
];
};
};
};
in
{
root = normal { gui = false; };
chn = normal { gui = inputs.config.nixos.system.gui.enable; };
};
};
}
];
}
# environment.persistence."/impermanence".users.chn =
# {
# directories =
# [
# "Desktop"
# "Documents"
# "Downloads"
# "Music"
# "repo"
# "Pictures"
# "Videos"
# directories =
# [
# "Desktop"
# "Documents"
# "Downloads"
# "Music"
# "repo"
# "Pictures"
# "Videos"
# ".cache"
# ".config"
# ".gnupg"
# ".local"
# ".ssh"
# ".android"
# ".exa"
# ".gnome"
# ".Mathematica"
# ".mozilla"
# ".pki"
# ".steam"
# ".tcc"
# ".vim"
# ".vscode"
# ".Wolfram"
# ".zotero"
# ".cache"
# ".config"
# ".gnupg"
# ".local"
# ".ssh"
# ".android"
# ".exa"
# ".gnome"
# ".Mathematica"
# ".mozilla"
# ".pki"
# ".steam"
# ".tcc"
# ".vim"
# ".vscode"
# ".Wolfram"
# ".zotero"
# ];
# files =
# [
# ".bash_history"
# ".cling_history"
# ".gitconfig"
# ".gtkrc-2.0"
# ".root_hist"
# ".viminfo"
# ".zsh_history"
# ];
# ];
# files =
# [
# ".bash_history"
# ".cling_history"
# ".gitconfig"
# ".gtkrc-2.0"
# ".root_hist"
# ".viminfo"
# ".zsh_history"
# ];
# };

View File

@@ -1,162 +1,162 @@
inputs:
{
options.nixos.virtualization = let inherit (inputs.lib) mkOption types; in
{
waydroid.enable = mkOption { default = false; type = types.bool; };
docker.enable = mkOption { default = false; type = types.bool; };
kvmHost =
{
enable = mkOption { default = false; type = types.bool; };
gui = mkOption { default = false; type = types.bool; };
autoSuspend = mkOption { type = types.listOf types.string; default = []; };
};
kvmGuest.enable = mkOption { default = false; type = types.bool; };
nspawn = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
config = let inherit (inputs.lib) mkMerge mkIf; in mkMerge
[
# waydroid
(mkIf inputs.config.nixos.virtualization.waydroid.enable { virtualisation = { waydroid.enable = true; }; })
# docker
(
mkIf inputs.config.nixos.virtualization.docker.enable
{
virtualisation.docker =
{
# enable = true;
rootless =
{
enable = true; setSocketVariable = true;
daemon.settings =
{
features.buildkit = true;
dns = [ "1.1.1.1" ];
};
};
enableNvidia = builtins.elem "nvidia" inputs.config.nixos.hardware.gpus;
storageDriver = "overlay2";
};
nixos.services.firewall.trustedInterfaces = [ "docker0" ];
}
)
# kvmHost
(
mkIf inputs.config.nixos.virtualization.kvmHost.enable
{
nix.settings.system-features = [ "kvm" ];
boot =
{
kernelModules =
let
modules =
{
intel = [ "kvm-intel" ];
amd = [];
};
in
builtins.concatLists (builtins.map (cpu: modules.${cpu}) inputs.config.nixos.hardware.cpus);
extraModprobeConfig =
let
configs =
{
intel = "options kvm_intel nested=1";
amd = "";
};
in
builtins.concatStringsSep "\n" (builtins.map (cpu: configs.${cpu}) inputs.config.nixos.hardware.cpus);
};
virtualisation =
{
libvirtd = { enable = true; qemu.runAsRoot = false; onBoot = "ignore"; onShutdown = "shutdown"; };
spiceUSBRedirection.enable = true;
};
environment.systemPackages = with inputs.pkgs; [ qemu_full win-spice ] ++
(if (inputs.config.nixos.virtualization.kvmHost.gui) then [ virt-manager ] else []);
systemd.services =
let
virsh = "${inputs.pkgs.libvirt}/bin/virsh";
hibernate = inputs.pkgs.writeShellScript "libvirt-hibernate" (inputs.localLib.stripeTabs
''
if [ "$(LANG=C ${virsh} domstate $1)" = 'running' ]
then
if ${virsh} dompmsuspend "$1" disk
then
echo "Waiting for $1 to suspend"
while ! [ "$(LANG=C ${virsh} domstate $1)" = 'shut off' ]
do
sleep 1
done
echo "$1 suspended"
touch "/tmp/libvirt.$1.suspended"
else
echo "Failed to suspend $1"
fi
fi
'');
resume = inputs.pkgs.writeShellScript "libvirt-resume" (inputs.localLib.stripeTabs
''
if [ "$(LANG=C ${virsh} domstate $1)" = 'shut off' ] && [ -f "/tmp/libvirt.$1.suspended" ]
then
if ${virsh} start "$1"
then
echo "Waiting for $1 to resume"
while ! [ "$(LANG=C ${virsh} domstate $1)" = 'running' ]
do
sleep 1
done
echo "$1 resumed"
rm "/tmp/libvirt.$1.suspended"
else
echo "Failed to resume $1"
fi
fi
'');
makeHibernate = machine:
{
name = "libvirt-hibernate-${machine}";
value =
{
description = "libvirt hibernate ${machine}";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
before = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig = { Type = "oneshot"; ExecStart = "${hibernate} ${machine}"; };
};
};
makeResume = machine:
{
name = "libvirt-resume-${machine}";
value =
{
description = "libvirt resume ${machine}";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
after = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig = { Type = "oneshot"; ExecStart = "${resume} ${machine}"; };
};
};
makeServices = serviceFunction: builtins.map serviceFunction
inputs.config.nixos.virtualization.kvmHost.autoSuspend;
in
builtins.listToAttrs (makeServices makeHibernate ++ makeServices makeResume);
}
)
# kvmGuest
(
mkIf inputs.config.nixos.virtualization.kvmGuest.enable
{ services = { qemuGuest.enable = true; spice-vdagentd.enable = true; xserver.videoDrivers = [ "qxl" ]; }; }
)
# nspawn
{
systemd.nspawn =
let
f = name: { inherit name; value =
{
execConfig.PrivateUsers = false;
networkConfig.VirtualEthernet = false;
}; };
in
builtins.listToAttrs (builtins.map f inputs.config.nixos.virtualization.nspawn);
}
];
options.nixos.virtualization = let inherit (inputs.lib) mkOption types; in
{
waydroid.enable = mkOption { default = false; type = types.bool; };
docker.enable = mkOption { default = false; type = types.bool; };
kvmHost =
{
enable = mkOption { default = false; type = types.bool; };
gui = mkOption { default = false; type = types.bool; };
autoSuspend = mkOption { type = types.listOf types.string; default = []; };
};
kvmGuest.enable = mkOption { default = false; type = types.bool; };
nspawn = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
config = let inherit (inputs.lib) mkMerge mkIf; in mkMerge
[
# waydroid
(mkIf inputs.config.nixos.virtualization.waydroid.enable { virtualisation = { waydroid.enable = true; }; })
# docker
(
mkIf inputs.config.nixos.virtualization.docker.enable
{
virtualisation.docker =
{
# enable = true;
rootless =
{
enable = true; setSocketVariable = true;
daemon.settings =
{
features.buildkit = true;
dns = [ "1.1.1.1" ];
};
};
enableNvidia = builtins.elem "nvidia" inputs.config.nixos.hardware.gpus;
storageDriver = "overlay2";
};
nixos.services.firewall.trustedInterfaces = [ "docker0" ];
}
)
# kvmHost
(
mkIf inputs.config.nixos.virtualization.kvmHost.enable
{
nix.settings.system-features = [ "kvm" ];
boot =
{
kernelModules =
let
modules =
{
intel = [ "kvm-intel" ];
amd = [];
};
in
builtins.concatLists (builtins.map (cpu: modules.${cpu}) inputs.config.nixos.hardware.cpus);
extraModprobeConfig =
let
configs =
{
intel = "options kvm_intel nested=1";
amd = "";
};
in
builtins.concatStringsSep "\n" (builtins.map (cpu: configs.${cpu}) inputs.config.nixos.hardware.cpus);
};
virtualisation =
{
libvirtd = { enable = true; qemu.runAsRoot = false; onBoot = "ignore"; onShutdown = "shutdown"; };
spiceUSBRedirection.enable = true;
};
environment.systemPackages = with inputs.pkgs; [ qemu_full win-spice ] ++
(if (inputs.config.nixos.virtualization.kvmHost.gui) then [ virt-manager ] else []);
systemd.services =
let
virsh = "${inputs.pkgs.libvirt}/bin/virsh";
hibernate = inputs.pkgs.writeShellScript "libvirt-hibernate"
''
if [ "$(LANG=C ${virsh} domstate $1)" = 'running' ]
then
if ${virsh} dompmsuspend "$1" disk
then
echo "Waiting for $1 to suspend"
while ! [ "$(LANG=C ${virsh} domstate $1)" = 'shut off' ]
do
sleep 1
done
echo "$1 suspended"
touch "/tmp/libvirt.$1.suspended"
else
echo "Failed to suspend $1"
fi
fi
'';
resume = inputs.pkgs.writeShellScript "libvirt-resume"
''
if [ "$(LANG=C ${virsh} domstate $1)" = 'shut off' ] && [ -f "/tmp/libvirt.$1.suspended" ]
then
if ${virsh} start "$1"
then
echo "Waiting for $1 to resume"
while ! [ "$(LANG=C ${virsh} domstate $1)" = 'running' ]
do
sleep 1
done
echo "$1 resumed"
rm "/tmp/libvirt.$1.suspended"
else
echo "Failed to resume $1"
fi
fi
'';
makeHibernate = machine:
{
name = "libvirt-hibernate-${machine}";
value =
{
description = "libvirt hibernate ${machine}";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
before = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig = { Type = "oneshot"; ExecStart = "${hibernate} ${machine}"; };
};
};
makeResume = machine:
{
name = "libvirt-resume-${machine}";
value =
{
description = "libvirt resume ${machine}";
wantedBy = [ "systemd-hibernate.service" "systemd-suspend.service" ];
after = [ "systemd-hibernate.service" "systemd-suspend.service" ];
serviceConfig = { Type = "oneshot"; ExecStart = "${resume} ${machine}"; };
};
};
makeServices = serviceFunction: builtins.map serviceFunction
inputs.config.nixos.virtualization.kvmHost.autoSuspend;
in
builtins.listToAttrs (makeServices makeHibernate ++ makeServices makeResume);
}
)
# kvmGuest
(
mkIf inputs.config.nixos.virtualization.kvmGuest.enable
{ services = { qemuGuest.enable = true; spice-vdagentd.enable = true; xserver.videoDrivers = [ "qxl" ]; }; }
)
# nspawn
{
systemd.nspawn =
let
f = name: { inherit name; value =
{
execConfig.PrivateUsers = false;
networkConfig.VirtualEthernet = false;
}; };
in
builtins.listToAttrs (builtins.map f inputs.config.nixos.virtualization.nspawn);
}
];
}
# sudo waydroid shell wm set-fix-to-user-rotation enabled