mirror of
https://github.com/oqyude/nixos.git
synced 2026-10-07 20:47:14 +03:00
Compare commits
2
Commits
417c7abda6
...
c05cc88843
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c05cc88843 | ||
|
|
d49fd5a358 |
+12
-15
@@ -1,18 +1,15 @@
|
|||||||
|
# Host: "default" (device: minimal)
|
||||||
|
#
|
||||||
|
# The host record lives in configurations/default.nix; this file is only the
|
||||||
|
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
|
||||||
{
|
{
|
||||||
deviceType = "minimal";
|
inputs,
|
||||||
modules = [
|
...
|
||||||
(
|
}:
|
||||||
{
|
{
|
||||||
inputs,
|
imports = [
|
||||||
...
|
inputs.self.nixosModules.default
|
||||||
}:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
inputs.self.nixosModules.default
|
|
||||||
];
|
|
||||||
|
|
||||||
system.stateVersion = "26.05";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
system.stateVersion = "26.05";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,73 @@
|
|||||||
{ inputs, ... }@flakeContext:
|
{ inputs, ... }@flakeContext:
|
||||||
let
|
let
|
||||||
|
lib = inputs.nixpkgs.lib;
|
||||||
mkSystem = import ../lib/mkSystem.nix flakeContext;
|
mkSystem = import ../lib/mkSystem.nix flakeContext;
|
||||||
|
xlibLib = import ../lib/xlib { inherit lib; };
|
||||||
|
|
||||||
|
# One record per host. The attribute name IS the hostname, so it is written
|
||||||
|
# exactly once; `hostname` is only needed where the attribute name is not
|
||||||
|
# the real hostname (the `default` entry).
|
||||||
|
#
|
||||||
|
# device device type, must be a key of `devices` in lib/xlib/device.nix
|
||||||
|
# modules module body for this host
|
||||||
|
hosts = {
|
||||||
|
default = {
|
||||||
|
hostname = "nixos";
|
||||||
|
device = "minimal";
|
||||||
|
modules = [ ./any.nix ];
|
||||||
|
};
|
||||||
|
atoridu = {
|
||||||
|
device = "primary";
|
||||||
|
modules = [ ./mini-pc.nix ];
|
||||||
|
};
|
||||||
|
rydiwo = {
|
||||||
|
device = "secondary";
|
||||||
|
modules = [ ./mini-laptop.nix ];
|
||||||
|
};
|
||||||
|
otreca = {
|
||||||
|
device = "vds";
|
||||||
|
modules = [ ./vds.nix ];
|
||||||
|
};
|
||||||
|
sapphira = {
|
||||||
|
device = "server";
|
||||||
|
modules = [ ./server.nix ];
|
||||||
|
};
|
||||||
|
wsl = {
|
||||||
|
device = "wsl";
|
||||||
|
modules = [ ./wsl.nix ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkHost =
|
||||||
|
name:
|
||||||
|
{
|
||||||
|
device,
|
||||||
|
modules,
|
||||||
|
hostname ? name,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
xlib = xlibLib.mkXlib {
|
||||||
|
inherit hostname;
|
||||||
|
type = device;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit xlib;
|
||||||
|
system = mkSystem { inherit xlib modules; };
|
||||||
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
nixosConfigurations = {
|
nixosConfigurations = lib.mapAttrs' (
|
||||||
default = mkSystem (import ./any.nix); # default
|
name: spec: lib.nameValuePair name (mkHost name spec).system
|
||||||
atoridu = mkSystem (import ./mini-pc.nix); # atoridu
|
) hosts;
|
||||||
rydiwo = mkSystem (import ./mini-laptop.nix); # rydiwo
|
|
||||||
otreca = mkSystem (import ./vds.nix); # vds
|
# Per-host xlib values, for code that lives outside the module system
|
||||||
sapphira = mkSystem (import ./server.nix); # sapphira
|
# (deploy, overlays, pkgs).
|
||||||
wsl = mkSystem (import ./wsl.nix); # wsl
|
xlib = lib.mapAttrs' (name: spec: lib.nameValuePair name (mkHost name spec).xlib) hosts;
|
||||||
};
|
|
||||||
nixOnDroidConfigurations = {
|
nixOnDroidConfigurations = {
|
||||||
epral = import ./mobile.nix flakeContext; # epral (Android via nix-on-droid)
|
epral = import ./mobile.nix flakeContext; # epral (Android device via nix-on-droid)
|
||||||
# Alias so a plain `nix-on-droid switch` from a local clone
|
# Alias so a plain `nix-on-droid switch` from a local clone
|
||||||
# (~/.config/nix-on-droid) picks up the device config without `#epral`.
|
# (~/.config/nix-on-droid) picks up the device config without `#epral`.
|
||||||
default = import ./mobile.nix flakeContext;
|
default = import ./mobile.nix flakeContext;
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
|
# Host: "rydiwo" (device: secondary)
|
||||||
|
#
|
||||||
|
# The host record lives in configurations/default.nix; this file is only the
|
||||||
|
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
|
||||||
{
|
{
|
||||||
deviceType = "secondary";
|
lib,
|
||||||
hostname = "rydiwo";
|
pkgs,
|
||||||
modules = [
|
xlib,
|
||||||
(
|
inputs,
|
||||||
{
|
...
|
||||||
lib,
|
}:
|
||||||
pkgs,
|
{
|
||||||
xlib,
|
imports = with inputs; [
|
||||||
inputs,
|
nixos-hardware.nixosModules.chuwi-minibook-x
|
||||||
...
|
./hardware/mini-laptop.nix
|
||||||
}:
|
self.nixosModules.default
|
||||||
{
|
|
||||||
imports = with inputs; [
|
|
||||||
nixos-hardware.nixosModules.chuwi-minibook-x
|
|
||||||
./hardware/mini-laptop.nix
|
|
||||||
self.nixosModules.default
|
|
||||||
];
|
|
||||||
|
|
||||||
boot = {
|
|
||||||
kernelPackages = lib.mkDefault pkgs.linuxPackages_xanmod_stable;
|
|
||||||
loader = {
|
|
||||||
systemd-boot.enable = lib.mkDefault true;
|
|
||||||
efi.canTouchEfiVariables = lib.mkDefault true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems = xlib.helpers.mkNtfsMount {
|
|
||||||
path = xlib.dirs.lamet-drive;
|
|
||||||
uuid = "DC76BD3576BD116E";
|
|
||||||
mask = "0000";
|
|
||||||
};
|
|
||||||
|
|
||||||
xlib.ssh.enable = true;
|
|
||||||
hardware.intel-gpu-tools.enable = true;
|
|
||||||
|
|
||||||
system.stateVersion = "26.05";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
boot = {
|
||||||
|
kernelPackages = lib.mkDefault pkgs.linuxPackages_xanmod_stable;
|
||||||
|
loader = {
|
||||||
|
systemd-boot.enable = lib.mkDefault true;
|
||||||
|
efi.canTouchEfiVariables = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems = xlib.helpers.mkNtfsMount {
|
||||||
|
path = xlib.dirs.lamet-drive;
|
||||||
|
uuid = "DC76BD3576BD116E";
|
||||||
|
mask = "0000";
|
||||||
|
};
|
||||||
|
|
||||||
|
host.ssh.enable = true;
|
||||||
|
hardware.intel-gpu-tools.enable = true;
|
||||||
|
|
||||||
|
system.stateVersion = "26.05";
|
||||||
}
|
}
|
||||||
|
|||||||
+81
-80
@@ -1,83 +1,84 @@
|
|||||||
|
# Host: "atoridu" (device: primary)
|
||||||
|
#
|
||||||
|
# The host record lives in configurations/default.nix; this file is only the
|
||||||
|
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
|
||||||
{
|
{
|
||||||
deviceType = "primary";
|
lib,
|
||||||
hostname = "atoridu";
|
pkgs,
|
||||||
modules = [
|
xlib,
|
||||||
(
|
inputs,
|
||||||
{
|
...
|
||||||
lib,
|
}:
|
||||||
pkgs,
|
{
|
||||||
xlib,
|
imports = with inputs; [
|
||||||
inputs,
|
./hardware/mini-pc.nix
|
||||||
...
|
./disko/mini-pc.nix
|
||||||
}:
|
./hardware/logitech.nix
|
||||||
{
|
self.nixosModules.default
|
||||||
imports = with inputs; [
|
|
||||||
./hardware/mini-pc.nix
|
|
||||||
./disko/mini-pc.nix
|
|
||||||
./hardware/logitech.nix
|
|
||||||
self.nixosModules.default
|
|
||||||
];
|
|
||||||
|
|
||||||
fileSystems = lib.listToAttrs (
|
|
||||||
map (xlib.helpers.mkNtfsMount) [
|
|
||||||
{
|
|
||||||
path = xlib.dirs.therima-drive;
|
|
||||||
uuid = "C0A2DDEFA2DDEA44";
|
|
||||||
enable = false;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
path = xlib.dirs.vetymae-drive;
|
|
||||||
uuid = "6408433908430A0E";
|
|
||||||
enable = false;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
path = xlib.dirs.soptur-drive;
|
|
||||||
uuid = "C00C56E40C56D54E";
|
|
||||||
enable = false;
|
|
||||||
}
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
boot = {
|
|
||||||
kernelPackages = lib.mkDefault pkgs.linuxPackages_xanmod_stable;
|
|
||||||
loader = {
|
|
||||||
systemd-boot.enable = lib.mkDefault true;
|
|
||||||
efi.canTouchEfiVariables = lib.mkDefault true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.xserver = {
|
|
||||||
videoDrivers = [
|
|
||||||
"amdgpu"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
services.pipewire = {
|
|
||||||
enable = lib.mkDefault true;
|
|
||||||
systemWide = true;
|
|
||||||
alsa.enable = false;
|
|
||||||
alsa.support32Bit = true;
|
|
||||||
pulse.enable = true;
|
|
||||||
jack.enable = true;
|
|
||||||
extraConfig.pipewire = {
|
|
||||||
"99-default.conf" = {
|
|
||||||
"context.properties" = {
|
|
||||||
"default.clock.rate" = 96000;
|
|
||||||
"default.clock.allowed-rates" = [
|
|
||||||
44100
|
|
||||||
48000
|
|
||||||
96000
|
|
||||||
];
|
|
||||||
"default.clock.quantum" = 1024;
|
|
||||||
"default.clock.min-quantum" = 256;
|
|
||||||
"default.clock.max-quantum" = 2048;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
nixpkgs.config.pulseaudio = true;
|
|
||||||
|
|
||||||
system.stateVersion = "26.05";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# mkNtfsMount returns a `{ "<path>" = { ... }; }` attrset (the shape
|
||||||
|
# fileSystems itself wants), so several mounts are combined with
|
||||||
|
# mergeAttrsList — not listToAttrs, which would demand `name`/`value`.
|
||||||
|
#
|
||||||
|
# These three ntfs3 drives are intentionally left unmounted. The entries
|
||||||
|
# are kept commented out rather than deleted, so restoring a drive is a
|
||||||
|
# matter of uncommenting its block. `enable = false` would declare a drive
|
||||||
|
# without mounting it; dropping the field mounts it.
|
||||||
|
fileSystems = lib.mergeAttrsList (
|
||||||
|
map (xlib.helpers.mkNtfsMount) [
|
||||||
|
# {
|
||||||
|
# path = xlib.dirs.therima-drive;
|
||||||
|
# uuid = "C0A2DDEFA2DDEA44";
|
||||||
|
# }
|
||||||
|
# {
|
||||||
|
# path = xlib.dirs.vetymae-drive;
|
||||||
|
# uuid = "6408433908430A0E";
|
||||||
|
# }
|
||||||
|
# {
|
||||||
|
# path = xlib.dirs.soptur-drive;
|
||||||
|
# uuid = "C00C56E40C56D54E";
|
||||||
|
# }
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
boot = {
|
||||||
|
kernelPackages = lib.mkDefault pkgs.linuxPackages_xanmod_stable;
|
||||||
|
loader = {
|
||||||
|
systemd-boot.enable = lib.mkDefault true;
|
||||||
|
efi.canTouchEfiVariables = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.xserver = {
|
||||||
|
videoDrivers = [
|
||||||
|
"amdgpu"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
services.pipewire = {
|
||||||
|
enable = lib.mkDefault true;
|
||||||
|
systemWide = true;
|
||||||
|
alsa.enable = false;
|
||||||
|
alsa.support32Bit = true;
|
||||||
|
pulse.enable = true;
|
||||||
|
jack.enable = true;
|
||||||
|
extraConfig.pipewire = {
|
||||||
|
"99-default.conf" = {
|
||||||
|
"context.properties" = {
|
||||||
|
"default.clock.rate" = 96000;
|
||||||
|
"default.clock.allowed-rates" = [
|
||||||
|
44100
|
||||||
|
48000
|
||||||
|
96000
|
||||||
|
];
|
||||||
|
"default.clock.quantum" = 1024;
|
||||||
|
"default.clock.min-quantum" = 256;
|
||||||
|
"default.clock.max-quantum" = 2048;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nixpkgs.config.pulseaudio = true;
|
||||||
|
|
||||||
|
system.stateVersion = "26.05";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ let
|
|||||||
# (essentials, users.nix, home-manager, sops-nix, disko, grub2-themes)
|
# (essentials, users.nix, home-manager, sops-nix, disko, grub2-themes)
|
||||||
# and nixpkgs.overlays are skipped so it evaluates under nix-on-droid's
|
# and nixpkgs.overlays are skipped so it evaluates under nix-on-droid's
|
||||||
# module system (class = "nixOnDroid").
|
# module system (class = "nixOnDroid").
|
||||||
|
xlib = import ../lib/xlib.nix { lib = inputs.nixpkgs.lib; };
|
||||||
nixOnDroidModule =
|
nixOnDroidModule =
|
||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
@@ -21,11 +22,6 @@ let
|
|||||||
inputs.self.nixosModules.strict
|
inputs.self.nixosModules.strict
|
||||||
];
|
];
|
||||||
|
|
||||||
xlib.device = {
|
|
||||||
type = "termux";
|
|
||||||
hostname = "epral";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Login shell. nix-on-droid writes /etc/passwd from user.shell on every
|
# Login shell. nix-on-droid writes /etc/passwd from user.shell on every
|
||||||
# activation, so `chsh` is useless here — set it in nix instead.
|
# activation, so `chsh` is useless here — set it in nix instead.
|
||||||
# (default is bashInteractive)
|
# (default is bashInteractive)
|
||||||
@@ -120,6 +116,13 @@ inputs.nix-on-droid.lib.nixOnDroidConfiguration {
|
|||||||
nixOnDroidModule
|
nixOnDroidModule
|
||||||
];
|
];
|
||||||
extraSpecialArgs = {
|
extraSpecialArgs = {
|
||||||
deviceType = "termux";
|
# `xlib` is the same value shape NixOS hosts get (lib/mkSystem.nix);
|
||||||
|
# the hostname lives here because nixOnDroidConfigurations is keyed by
|
||||||
|
# both "epral" and the "default" alias, so it cannot come from the
|
||||||
|
# attribute name.
|
||||||
|
xlib = xlib.mkXlib {
|
||||||
|
hostname = "epral";
|
||||||
|
type = "termux";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+76
-80
@@ -1,83 +1,79 @@
|
|||||||
|
# Host: "sapphira" (device: server)
|
||||||
|
#
|
||||||
|
# The host record lives in configurations/default.nix; this file is only the
|
||||||
|
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
|
||||||
{
|
{
|
||||||
deviceType = "server";
|
lib,
|
||||||
hostname = "sapphira";
|
pkgs,
|
||||||
modules = [
|
xlib,
|
||||||
(
|
inputs,
|
||||||
{
|
...
|
||||||
lib,
|
}:
|
||||||
pkgs,
|
{
|
||||||
xlib,
|
imports = [
|
||||||
inputs,
|
./hardware/server.nix
|
||||||
...
|
inputs.self.nixosModules.default
|
||||||
}:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./hardware/server.nix
|
|
||||||
inputs.self.nixosModules.default
|
|
||||||
];
|
|
||||||
|
|
||||||
boot = {
|
|
||||||
# kernelPackages = pkgs.linuxPackages_xanmod_stable;
|
|
||||||
hardwareScan = true;
|
|
||||||
loader = {
|
|
||||||
systemd-boot.enable = lib.mkDefault true;
|
|
||||||
efi.canTouchEfiVariables = lib.mkDefault true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
hardware = {
|
|
||||||
bluetooth.enable = true;
|
|
||||||
graphics = {
|
|
||||||
enable = true;
|
|
||||||
extraPackages = with pkgs; [
|
|
||||||
intel-media-driver
|
|
||||||
intel-ocl
|
|
||||||
intel-vaapi-driver
|
|
||||||
];
|
|
||||||
};
|
|
||||||
intel-gpu-tools.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems =
|
|
||||||
(xlib.helpers.mkExfatMount {
|
|
||||||
path = xlib.dirs.archive-drive;
|
|
||||||
label = "archive";
|
|
||||||
})
|
|
||||||
// (xlib.helpers.mkExfatMount {
|
|
||||||
path = xlib.dirs.mobile-drive;
|
|
||||||
uuid = "7EB1-DC99";
|
|
||||||
})
|
|
||||||
// (xlib.helpers.mkBindMount {
|
|
||||||
what = xlib.dirs.services-folder;
|
|
||||||
where = xlib.dirs.services-mnt-folder;
|
|
||||||
})
|
|
||||||
// {
|
|
||||||
# External drive
|
|
||||||
"${xlib.dirs.server-home}" = {
|
|
||||||
device = "/dev/disk/by-uuid/37e53ebc-5343-a94d-9fe2-0ca39e13a8de";
|
|
||||||
fsType = "ext4";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"z ${xlib.dirs.services-mnt-folder} 0777 root root -"
|
|
||||||
];
|
|
||||||
|
|
||||||
xlib.ssh.enable = true;
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
networkmanager.enable = true;
|
|
||||||
firewall.enable = false;
|
|
||||||
# nameservers = [
|
|
||||||
# "192.168.1.1"
|
|
||||||
# "127.0.0.1"
|
|
||||||
# ];
|
|
||||||
};
|
|
||||||
|
|
||||||
system = {
|
|
||||||
stateVersion = "25.05";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
boot = {
|
||||||
|
# kernelPackages = pkgs.linuxPackages_xanmod_stable;
|
||||||
|
hardwareScan = true;
|
||||||
|
loader = {
|
||||||
|
systemd-boot.enable = lib.mkDefault true;
|
||||||
|
efi.canTouchEfiVariables = lib.mkDefault true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
hardware = {
|
||||||
|
bluetooth.enable = true;
|
||||||
|
graphics = {
|
||||||
|
enable = true;
|
||||||
|
extraPackages = with pkgs; [
|
||||||
|
intel-media-driver
|
||||||
|
intel-ocl
|
||||||
|
intel-vaapi-driver
|
||||||
|
];
|
||||||
|
};
|
||||||
|
intel-gpu-tools.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems =
|
||||||
|
(xlib.helpers.mkExfatMount {
|
||||||
|
path = xlib.dirs.archive-drive;
|
||||||
|
label = "archive";
|
||||||
|
})
|
||||||
|
// (xlib.helpers.mkExfatMount {
|
||||||
|
path = xlib.dirs.mobile-drive;
|
||||||
|
uuid = "7EB1-DC99";
|
||||||
|
})
|
||||||
|
// (xlib.helpers.mkBindMount {
|
||||||
|
what = xlib.dirs.services-folder;
|
||||||
|
where = xlib.dirs.services-mnt-folder;
|
||||||
|
})
|
||||||
|
// {
|
||||||
|
# External drive
|
||||||
|
"${xlib.dirs.server-home}" = {
|
||||||
|
device = "/dev/disk/by-uuid/37e53ebc-5343-a94d-9fe2-0ca39e13a8de";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"z ${xlib.dirs.services-mnt-folder} 0777 root root -"
|
||||||
|
];
|
||||||
|
|
||||||
|
host.ssh.enable = true;
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
networkmanager.enable = true;
|
||||||
|
firewall.enable = false;
|
||||||
|
# nameservers = [
|
||||||
|
# "192.168.1.1"
|
||||||
|
# "127.0.0.1"
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
|
||||||
|
system = {
|
||||||
|
stateVersion = "25.05";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+112
-117
@@ -1,122 +1,117 @@
|
|||||||
|
# Host: "otreca" (device: vds)
|
||||||
|
#
|
||||||
|
# The host record lives in configurations/default.nix; this file is only the
|
||||||
|
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
|
||||||
{
|
{
|
||||||
deviceType = "vds";
|
lib,
|
||||||
hostname = "otreca";
|
modulesPath,
|
||||||
modules = [
|
pkgs,
|
||||||
(
|
xlib,
|
||||||
{
|
inputs,
|
||||||
config,
|
...
|
||||||
lib,
|
}:
|
||||||
modulesPath,
|
{
|
||||||
pkgs,
|
imports = [
|
||||||
xlib,
|
(modulesPath + "/installer/scan/not-detected.nix")
|
||||||
inputs,
|
(modulesPath + "/profiles/qemu-guest.nix")
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
(modulesPath + "/installer/scan/not-detected.nix")
|
|
||||||
(modulesPath + "/profiles/qemu-guest.nix")
|
|
||||||
|
|
||||||
./disko/vds.nix
|
./disko/vds.nix
|
||||||
./hardware/vds.nix
|
./hardware/vds.nix
|
||||||
|
|
||||||
inputs.self.nixosModules.default
|
inputs.self.nixosModules.default
|
||||||
];
|
|
||||||
|
|
||||||
boot = {
|
|
||||||
# kernelPackages = pkgs.linuxPackages_xanmod_stable;
|
|
||||||
hardwareScan = true;
|
|
||||||
loader = {
|
|
||||||
grub = {
|
|
||||||
enable = true;
|
|
||||||
device = "nodev";
|
|
||||||
useOSProber = false;
|
|
||||||
efiSupport = false;
|
|
||||||
};
|
|
||||||
systemd-boot.enable = lib.mkDefault false;
|
|
||||||
};
|
|
||||||
kernel.sysctl = {
|
|
||||||
"net.ipv4.tcp_syncookies" = 1;
|
|
||||||
"net.ipv4.tcp_max_syn_backlog" = 4096;
|
|
||||||
"net.ipv4.tcp_synack_retries" = 3;
|
|
||||||
"net.ipv4.tcp_syn_retries" = 3;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
xlib.ssh.enable = true;
|
|
||||||
services.openssh.openFirewall = true;
|
|
||||||
|
|
||||||
services.tailscale = {
|
|
||||||
enable = true;
|
|
||||||
openFirewall = true;
|
|
||||||
};
|
|
||||||
networking = {
|
|
||||||
nameservers = [
|
|
||||||
"1.1.1.1"
|
|
||||||
"8.8.8.8"
|
|
||||||
];
|
|
||||||
networkmanager.enable = true;
|
|
||||||
tempAddresses = "disabled";
|
|
||||||
dhcpcd = {
|
|
||||||
enable = true;
|
|
||||||
IPv6rs = false;
|
|
||||||
};
|
|
||||||
firewall = {
|
|
||||||
enable = true;
|
|
||||||
allowPing = true;
|
|
||||||
};
|
|
||||||
nftables = {
|
|
||||||
enable = true;
|
|
||||||
ruleset = ''
|
|
||||||
table inet filter {
|
|
||||||
chain input {
|
|
||||||
type filter hook input priority 0;
|
|
||||||
|
|
||||||
# loopback
|
|
||||||
iif lo accept
|
|
||||||
|
|
||||||
# уже установленные
|
|
||||||
ct state established,related accept
|
|
||||||
|
|
||||||
# РЕЖЕМ SYN СРАЗУ
|
|
||||||
tcp flags syn tcp dport {80,443} limit rate 20/second burst 40 packets accept
|
|
||||||
tcp flags syn tcp dport {80,443} drop
|
|
||||||
|
|
||||||
# остальное по необходимости
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
enableIPv6 = false;
|
|
||||||
interfaces.ens3 = {
|
|
||||||
useDHCP = true;
|
|
||||||
# ipv4.addresses = [
|
|
||||||
# {
|
|
||||||
# address = "31.57.158.109";
|
|
||||||
# prefixLength = 24;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
# ipv6.addresses = [
|
|
||||||
# {
|
|
||||||
# address = "2a13:7c00:6:102:f816:3eff:fe91:6b9e";
|
|
||||||
# prefixLength = 64;
|
|
||||||
# }
|
|
||||||
# ];
|
|
||||||
};
|
|
||||||
# defaultGateway = {
|
|
||||||
# address = "31.57.158.1";
|
|
||||||
# interface = "ens3";
|
|
||||||
# };
|
|
||||||
# defaultGateway6 = {
|
|
||||||
# address = "2a13:7c00:6:102::1";
|
|
||||||
# interface = "ens3";
|
|
||||||
# };
|
|
||||||
};
|
|
||||||
|
|
||||||
system = {
|
|
||||||
stateVersion = "25.05";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
boot = {
|
||||||
|
# kernelPackages = pkgs.linuxPackages_xanmod_stable;
|
||||||
|
hardwareScan = true;
|
||||||
|
loader = {
|
||||||
|
grub = {
|
||||||
|
enable = true;
|
||||||
|
device = "nodev";
|
||||||
|
useOSProber = false;
|
||||||
|
efiSupport = false;
|
||||||
|
};
|
||||||
|
systemd-boot.enable = lib.mkDefault false;
|
||||||
|
};
|
||||||
|
kernel.sysctl = {
|
||||||
|
"net.ipv4.tcp_syncookies" = 1;
|
||||||
|
"net.ipv4.tcp_max_syn_backlog" = 4096;
|
||||||
|
"net.ipv4.tcp_synack_retries" = 3;
|
||||||
|
"net.ipv4.tcp_syn_retries" = 3;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
host.ssh.enable = true;
|
||||||
|
services.openssh.openFirewall = true;
|
||||||
|
|
||||||
|
services.tailscale = {
|
||||||
|
enable = true;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
networking = {
|
||||||
|
nameservers = [
|
||||||
|
"1.1.1.1"
|
||||||
|
"8.8.8.8"
|
||||||
|
];
|
||||||
|
networkmanager.enable = true;
|
||||||
|
tempAddresses = "disabled";
|
||||||
|
dhcpcd = {
|
||||||
|
enable = true;
|
||||||
|
IPv6rs = false;
|
||||||
|
};
|
||||||
|
firewall = {
|
||||||
|
enable = true;
|
||||||
|
allowPing = true;
|
||||||
|
};
|
||||||
|
nftables = {
|
||||||
|
enable = true;
|
||||||
|
ruleset = ''
|
||||||
|
table inet filter {
|
||||||
|
chain input {
|
||||||
|
type filter hook input priority 0;
|
||||||
|
|
||||||
|
# loopback
|
||||||
|
iif lo accept
|
||||||
|
|
||||||
|
# уже установленные
|
||||||
|
ct state established,related accept
|
||||||
|
|
||||||
|
# РЕЖЕМ SYN СРАЗУ
|
||||||
|
tcp flags syn tcp dport {80,443} limit rate 20/second burst 40 packets accept
|
||||||
|
tcp flags syn tcp dport {80,443} drop
|
||||||
|
|
||||||
|
# остальное по необходимости
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
enableIPv6 = false;
|
||||||
|
interfaces.ens3 = {
|
||||||
|
useDHCP = true;
|
||||||
|
# ipv4.addresses = [
|
||||||
|
# {
|
||||||
|
# address = "31.57.158.109";
|
||||||
|
# prefixLength = 24;
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# ipv6.addresses = [
|
||||||
|
# {
|
||||||
|
# address = "2a13:7c00:6:102:f816:3eff:fe91:6b9e";
|
||||||
|
# prefixLength = 64;
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
# defaultGateway = {
|
||||||
|
# address = "31.57.158.1";
|
||||||
|
# interface = "ens3";
|
||||||
|
# };
|
||||||
|
# defaultGateway6 = {
|
||||||
|
# address = "2a13:7c00:6:102::1";
|
||||||
|
# interface = "ens3";
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
|
||||||
|
system = {
|
||||||
|
stateVersion = "25.05";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-41
@@ -1,44 +1,39 @@
|
|||||||
|
# Host: "wsl" (device: wsl)
|
||||||
|
#
|
||||||
|
# The host record lives in configurations/default.nix; this file is only the
|
||||||
|
# module body. `xlib` (identity, dirs, helpers) arrives as a module argument.
|
||||||
{
|
{
|
||||||
deviceType = "wsl";
|
lib,
|
||||||
hostname = "wsl";
|
modulesPath,
|
||||||
modules = [
|
pkgs,
|
||||||
(
|
xlib,
|
||||||
{
|
inputs,
|
||||||
config,
|
...
|
||||||
lib,
|
}:
|
||||||
pkgs,
|
{
|
||||||
modulesPath,
|
imports = [
|
||||||
xlib,
|
inputs.nixos-wsl.nixosModules.default
|
||||||
inputs,
|
inputs.self.nixosModules.default
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
inputs.nixos-wsl.nixosModules.default
|
|
||||||
inputs.self.nixosModules.default
|
|
||||||
];
|
|
||||||
|
|
||||||
hardware = {
|
|
||||||
graphics.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
networking = {
|
|
||||||
firewall = {
|
|
||||||
enable = false;
|
|
||||||
allowPing = true;
|
|
||||||
};
|
|
||||||
enableIPv6 = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
wsl = {
|
|
||||||
enable = true;
|
|
||||||
startMenuLaunchers = true;
|
|
||||||
useWindowsDriver = true;
|
|
||||||
defaultUser = config.xlib.device.username;
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "24.11";
|
|
||||||
}
|
|
||||||
)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
hardware = {
|
||||||
|
graphics.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking = {
|
||||||
|
firewall = {
|
||||||
|
enable = false;
|
||||||
|
allowPing = true;
|
||||||
|
};
|
||||||
|
enableIPv6 = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
wsl = {
|
||||||
|
enable = true;
|
||||||
|
startMenuLaunchers = true;
|
||||||
|
useWindowsDriver = true;
|
||||||
|
defaultUser = xlib.device.username;
|
||||||
|
};
|
||||||
|
|
||||||
|
system.stateVersion = "24.11";
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -6,7 +6,9 @@ let
|
|||||||
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos inputs.self.nixosConfigurations.${hostname};
|
path = inputs.deploy-rs.lib.x86_64-linux.activate.nixos inputs.self.nixosConfigurations.${hostname};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
user = "${inputs.self.nixosConfigurations.default.config.xlib.device.username}";
|
# Login user for every deploy target. Read from the hoisted xlib instead of
|
||||||
|
# digging through a built NixOS configuration.
|
||||||
|
user = "${inputs.self.xlib.default.device.username}";
|
||||||
server = "sapphira";
|
server = "sapphira";
|
||||||
vds = "otreca";
|
vds = "otreca";
|
||||||
mini-laptop = "rydiwo";
|
mini-laptop = "rydiwo";
|
||||||
|
|||||||
+1
-5
@@ -53,11 +53,7 @@ let
|
|||||||
imports = [
|
imports = [
|
||||||
(./. + "/${xlib.device.type}.nix")
|
(./. + "/${xlib.device.type}.nix")
|
||||||
];
|
];
|
||||||
headless = builtins.elem xlib.device.type [
|
headless = xlib.isHeadless;
|
||||||
"server"
|
|
||||||
"vds"
|
|
||||||
"wsl"
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
sharedModules = [
|
sharedModules = [
|
||||||
|
|||||||
+14
-12
@@ -2,26 +2,28 @@
|
|||||||
inputs,
|
inputs,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
# Builds a NixOS system from a host record.
|
||||||
|
#
|
||||||
|
# `xlib` is the pure host value (lib/xlib.nix `mkXlib`) built in
|
||||||
|
# configurations/default.nix. It is handed to every module as the `xlib`
|
||||||
|
# argument, so modules read plain `xlib.*` data instead of `config.xlib.*`
|
||||||
|
# and the host record stays the single source of truth.
|
||||||
{
|
{
|
||||||
deviceType,
|
xlib,
|
||||||
hostname ? null,
|
|
||||||
modules ? [ ],
|
modules ? [ ],
|
||||||
system ? "x86_64-linux",
|
system ? "x86_64-linux",
|
||||||
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
lib = inputs.nixpkgs.lib;
|
lib = inputs.nixpkgs.lib;
|
||||||
in
|
in
|
||||||
lib.nixosSystem {
|
lib.nixosSystem {
|
||||||
inherit system;
|
inherit
|
||||||
modules = modules ++ [
|
system
|
||||||
{
|
modules
|
||||||
xlib.device = {
|
;
|
||||||
type = deviceType;
|
|
||||||
}
|
|
||||||
// lib.optionalAttrs (hostname != null) { inherit hostname; };
|
|
||||||
}
|
|
||||||
];
|
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
inherit deviceType inputs;
|
inherit inputs;
|
||||||
|
inherit xlib;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# Pure host library: no module system involved.
|
||||||
|
#
|
||||||
|
# Aggregates the four concerns a host record is built from:
|
||||||
|
# device.nix identity + capability flags from the device type
|
||||||
|
# dirs.nix well-known paths, derived from username
|
||||||
|
# helpers.nix pure helper functions shared by modules
|
||||||
|
#
|
||||||
|
# `mkXlib` is called in flake-level code (configurations/default.nix) and
|
||||||
|
# handed to every module as the `xlib` argument via lib/mkSystem.nix, so
|
||||||
|
# modules read plain `xlib.*` values instead of `config.xlib.*` and nothing in
|
||||||
|
# xlib can be overridden per host — the host record is the only place to
|
||||||
|
# change it.
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
inherit (import ./device.nix { inherit lib; })
|
||||||
|
devices
|
||||||
|
mkDevice
|
||||||
|
;
|
||||||
|
|
||||||
|
# dirs.nix is itself a function of `username`, not an attrset.
|
||||||
|
mkDirs = import ./dirs.nix;
|
||||||
|
|
||||||
|
helpers = (import ./helpers.nix { inherit lib; });
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
devices
|
||||||
|
helpers
|
||||||
|
mkDevice
|
||||||
|
mkDirs
|
||||||
|
;
|
||||||
|
|
||||||
|
# Full host record: identity + capability flags + well-known paths +
|
||||||
|
# shared helpers.
|
||||||
|
mkXlib =
|
||||||
|
{
|
||||||
|
hostname,
|
||||||
|
type,
|
||||||
|
username ? "oqyude",
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
device = mkDevice {
|
||||||
|
inherit
|
||||||
|
hostname
|
||||||
|
type
|
||||||
|
username
|
||||||
|
;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
device = {
|
||||||
|
inherit
|
||||||
|
hostname
|
||||||
|
type
|
||||||
|
username
|
||||||
|
;
|
||||||
|
};
|
||||||
|
isDesktop = device.isDesktop;
|
||||||
|
isHeadless = device.isHeadless;
|
||||||
|
dirs = mkDirs username;
|
||||||
|
inherit helpers;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
# Supported device types and the identity record built from one.
|
||||||
|
#
|
||||||
|
# Single source of truth for host identity: hostname, type, username and the
|
||||||
|
# capability flags derived from the type. Replaces the old `lib.types.enum`
|
||||||
|
# in modules/options.nix and the hand-written type lists in modules/default.nix
|
||||||
|
# and home/home.nix.
|
||||||
|
let
|
||||||
|
devices = {
|
||||||
|
minimal = {
|
||||||
|
desktop = false;
|
||||||
|
headless = false;
|
||||||
|
};
|
||||||
|
primary = {
|
||||||
|
desktop = true;
|
||||||
|
headless = false;
|
||||||
|
};
|
||||||
|
secondary = {
|
||||||
|
desktop = true;
|
||||||
|
headless = false;
|
||||||
|
};
|
||||||
|
server = {
|
||||||
|
desktop = false;
|
||||||
|
headless = true;
|
||||||
|
};
|
||||||
|
vds = {
|
||||||
|
desktop = false;
|
||||||
|
headless = true;
|
||||||
|
};
|
||||||
|
wsl = {
|
||||||
|
desktop = false;
|
||||||
|
headless = true;
|
||||||
|
};
|
||||||
|
termux = {
|
||||||
|
desktop = false;
|
||||||
|
headless = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit devices;
|
||||||
|
|
||||||
|
# Unknown device type fails here, at flake level, with the valid list.
|
||||||
|
mkDevice =
|
||||||
|
{
|
||||||
|
hostname,
|
||||||
|
type,
|
||||||
|
username ? "oqyude",
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
capabilities = devices.${type} or (throw "xlib: unknown device type '${type}', expected one of ${lib.concatStringsSep ", " (builtins.attrNames devices)}");
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
hostname
|
||||||
|
type
|
||||||
|
username
|
||||||
|
;
|
||||||
|
isDesktop = capabilities.desktop;
|
||||||
|
isHeadless = capabilities.headless;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Well-known paths. Everything derives from `username`, which is why the
|
||||||
|
# whole set can be computed outside the module system.
|
||||||
|
username:
|
||||||
|
let
|
||||||
|
user-home = "/home/${username}";
|
||||||
|
wsl-home = "/mnt/c/Users/${username}";
|
||||||
|
server-home = "${user-home}/External";
|
||||||
|
services-mnt-folder = "/mnt/services";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit
|
||||||
|
user-home
|
||||||
|
wsl-home
|
||||||
|
server-home
|
||||||
|
services-mnt-folder
|
||||||
|
;
|
||||||
|
|
||||||
|
user-storage = "${user-home}/Storage";
|
||||||
|
wsl-storage = "${wsl-home}/Storage";
|
||||||
|
server-credentials = "${server-home}/Credentials/server";
|
||||||
|
storage = "${server-home}/Storage";
|
||||||
|
calibre-library = "${server-home}/Books-Library";
|
||||||
|
services-folder = "${server-home}/Services";
|
||||||
|
services-nodes-folder = "${services-mnt-folder}/nodes";
|
||||||
|
postgresql-folder = "${services-mnt-folder}/postgresql";
|
||||||
|
music-library = "${user-home}/Music";
|
||||||
|
|
||||||
|
archive-drive = "/mnt/archive";
|
||||||
|
lamet-drive = "/mnt/lamet";
|
||||||
|
mobile-drive = "/mnt/mobile";
|
||||||
|
therima-drive = "/mnt/therima";
|
||||||
|
vetymae-drive = "/mnt/vetymae";
|
||||||
|
soptur-drive = "/mnt/soptur";
|
||||||
|
}
|
||||||
@@ -2,8 +2,11 @@
|
|||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
# Shared pure helper functions for module definitions.
|
# Pure helper functions for module definitions.
|
||||||
# Injected into every module via `xlib.helpers` (see options.nix).
|
# Injected into every module via `xlib.helpers` (see default.nix).
|
||||||
|
#
|
||||||
|
# Defined in a `let` because they reference each other (mkTmpDirs uses
|
||||||
|
# mkTmpfile, mkServiceStorage uses mkTmpDirs + mkSystemdBind).
|
||||||
let
|
let
|
||||||
# tmpfiles rule: "type dir mode user group -"
|
# tmpfiles rule: "type dir mode user group -"
|
||||||
mkTmpfile =
|
mkTmpfile =
|
||||||
@@ -150,4 +153,4 @@ in
|
|||||||
mkExfatMount
|
mkExfatMount
|
||||||
mkSymlinks
|
mkSymlinks
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,11 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
panel = "${xlib.dirs.services-nodes-folder}/${xlib.device.hostname}/3x-ui";
|
panel = "${xlib.dirs.services-nodes-folder}/${xlib.device.hostname}/3x-ui";
|
||||||
certDomain = xlib.services."3x-ui".certDomain or null;
|
# Domain whose Let's Encrypt cert (at /var/lib/acme/<domain>/) gets mounted
|
||||||
|
# read-only into the 3x-ui container so the panel can terminate TLS itself.
|
||||||
|
# Null when 3x-ui serves plain HTTP and TLS is terminated by an upstream
|
||||||
|
# nginx.
|
||||||
|
certDomain = config.host."3x-ui".certDomain;
|
||||||
certMounts =
|
certMounts =
|
||||||
if certDomain == null then
|
if certDomain == null then
|
||||||
[ ]
|
[ ]
|
||||||
@@ -28,94 +32,99 @@ let
|
|||||||
];
|
];
|
||||||
# VDS-only: nginx stream forwards host:443 → 127.0.0.1:15380 →
|
# VDS-only: nginx stream forwards host:443 → 127.0.0.1:15380 →
|
||||||
# container:443, so Xray sees its REALITY inbound on port 443.
|
# container:443, so Xray sees its REALITY inbound on port 443.
|
||||||
realityPorts = lib.optional xlib.services."3x-ui".reality443Forwarding "127.0.0.1:15380:443/tcp";
|
realityPorts = lib.optional config.host."3x-ui".reality443Forwarding "127.0.0.1:15380:443/tcp";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
virtualisation = {
|
# `host."3x-ui"` options are declared in modules/options.nix: they are set
|
||||||
podman = {
|
# by modules/server and modules/vds, so this module cannot be the only place
|
||||||
enable = true;
|
# that knows they exist.
|
||||||
autoPrune = {
|
config = {
|
||||||
|
virtualisation = {
|
||||||
|
podman = {
|
||||||
enable = true;
|
enable = true;
|
||||||
flags = [ "--all" ];
|
autoPrune = {
|
||||||
};
|
enable = true;
|
||||||
dockerCompat = true;
|
flags = [ "--all" ];
|
||||||
};
|
|
||||||
oci-containers = {
|
|
||||||
backend = "podman";
|
|
||||||
containers."3xui_app" = {
|
|
||||||
image = "ghcr.io/mhsanaei/3x-ui:latest";
|
|
||||||
environment = {
|
|
||||||
"XRAY_VMESS_AEAD_FORCED" = "false";
|
|
||||||
"XUI_ENABLE_FAIL2BAN" = "true";
|
|
||||||
"TZ" = "Europe/Moscow";
|
|
||||||
};
|
};
|
||||||
volumes = [
|
dockerCompat = true;
|
||||||
"${panel}/cert/:/root/cert:rw"
|
|
||||||
"${panel}/db/:/etc/x-ui:rw"
|
|
||||||
]
|
|
||||||
++ certMounts;
|
|
||||||
log-driver = "journald";
|
|
||||||
# Adding a new inbound through the 3x-ui panel on a port outside
|
|
||||||
# the 14380-15379 range requires extending basePorts and rebuilding.
|
|
||||||
ports = basePorts ++ realityPorts;
|
|
||||||
};
|
};
|
||||||
};
|
oci-containers = {
|
||||||
};
|
backend = "podman";
|
||||||
|
containers."3xui_app" = {
|
||||||
systemd = {
|
image = "ghcr.io/mhsanaei/3x-ui:latest";
|
||||||
services = {
|
environment = {
|
||||||
"podman-3xui_app" = {
|
"XRAY_VMESS_AEAD_FORCED" = "false";
|
||||||
serviceConfig.Restart = lib.mkOverride 90 "always";
|
"XUI_ENABLE_FAIL2BAN" = "true";
|
||||||
partOf = [ "podman-compose-3x-ui-root.target" ];
|
"TZ" = "Europe/Moscow";
|
||||||
wantedBy = [ "podman-compose-3x-ui-root.target" ];
|
};
|
||||||
};
|
volumes = [
|
||||||
"podman-update-3xui_app" = {
|
"${panel}/cert/:/root/cert:rw"
|
||||||
path = [ pkgs.podman ];
|
"${panel}/db/:/etc/x-ui:rw"
|
||||||
serviceConfig = {
|
]
|
||||||
Type = "oneshot";
|
++ certMounts;
|
||||||
TimeoutSec = 300;
|
log-driver = "journald";
|
||||||
|
# Adding a new inbound through the 3x-ui panel on a port outside
|
||||||
|
# the 14380-15379 range requires extending basePorts and rebuilding.
|
||||||
|
ports = basePorts ++ realityPorts;
|
||||||
};
|
};
|
||||||
script = ''
|
|
||||||
podman pull ghcr.io/mhsanaei/3x-ui:latest
|
|
||||||
systemctl restart podman-3xui_app.service
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
# Starts/stops together with all 3x-ui compose resources.
|
|
||||||
targets."podman-compose-3x-ui-root" = {
|
|
||||||
unitConfig.Description = "Root target generated by compose2nix.";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
# timers."podman-update-3xui_app" = {
|
|
||||||
# wantedBy = [ "timers.target" ];
|
|
||||||
# timerConfig = {
|
|
||||||
# OnCalendar = "weekly";
|
|
||||||
# Persistent = true;
|
|
||||||
# };
|
|
||||||
# };
|
|
||||||
tmpfiles.rules = [
|
|
||||||
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-mnt-folder "0755" "root" "root")
|
|
||||||
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-nodes-folder "0755" "root" "root")
|
|
||||||
(xlib.helpers.mkTmpfile "d" "${xlib.dirs.services-nodes-folder}/${xlib.device.hostname}" "0755"
|
|
||||||
"root"
|
|
||||||
"root"
|
|
||||||
)
|
|
||||||
(xlib.helpers.mkTmpfile "d" panel "0755" "root" "root")
|
|
||||||
(xlib.helpers.mkTmpfile "d" "${panel}/db" "0755" "root" "root")
|
|
||||||
(xlib.helpers.mkTmpfile "d" "${panel}/cert" "0755" "root" "root")
|
|
||||||
# Relabel panel dir for SELinux so containers can access it.
|
|
||||||
(xlib.helpers.mkTmpfile "Z" panel "0755" "root" "root")
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Enable container name DNS for all Podman networks.
|
systemd = {
|
||||||
networking.firewall = {
|
services = {
|
||||||
interfaces =
|
"podman-3xui_app" = {
|
||||||
let
|
serviceConfig.Restart = lib.mkOverride 90 "always";
|
||||||
matchAll = if !config.networking.nftables.enable then "podman+" else "podman*";
|
partOf = [ "podman-compose-3x-ui-root.target" ];
|
||||||
in
|
wantedBy = [ "podman-compose-3x-ui-root.target" ];
|
||||||
{
|
};
|
||||||
"${matchAll}".allowedUDPPorts = [ 53 ];
|
"podman-update-3xui_app" = {
|
||||||
|
path = [ pkgs.podman ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
TimeoutSec = 300;
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
podman pull ghcr.io/mhsanaei/3x-ui:latest
|
||||||
|
systemctl restart podman-3xui_app.service
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
# Starts/stops together with all 3x-ui compose resources.
|
||||||
|
targets."podman-compose-3x-ui-root" = {
|
||||||
|
unitConfig.Description = "Root target generated by compose2nix.";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
};
|
||||||
|
# timers."podman-update-3xui_app" = {
|
||||||
|
# wantedBy = [ "timers.target" ];
|
||||||
|
# timerConfig = {
|
||||||
|
# OnCalendar = "weekly";
|
||||||
|
# Persistent = true;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
tmpfiles.rules = [
|
||||||
|
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-mnt-folder "0755" "root" "root")
|
||||||
|
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-nodes-folder "0755" "root" "root")
|
||||||
|
(xlib.helpers.mkTmpfile "d" "${xlib.dirs.services-nodes-folder}/${xlib.device.hostname}" "0755"
|
||||||
|
"root"
|
||||||
|
"root"
|
||||||
|
)
|
||||||
|
(xlib.helpers.mkTmpfile "d" panel "0755" "root" "root")
|
||||||
|
(xlib.helpers.mkTmpfile "d" "${panel}/db" "0755" "root" "root")
|
||||||
|
(xlib.helpers.mkTmpfile "d" "${panel}/cert" "0755" "root" "root")
|
||||||
|
# Relabel panel dir for SELinux so containers can access it.
|
||||||
|
(xlib.helpers.mkTmpfile "Z" panel "0755" "root" "root")
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Enable container name DNS for all Podman networks.
|
||||||
|
networking.firewall = {
|
||||||
|
interfaces =
|
||||||
|
let
|
||||||
|
matchAll = if !config.networking.nftables.enable then "podman+" else "podman*";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"${matchAll}".allowedUDPPorts = [ 53 ];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-23
@@ -3,24 +3,15 @@ let
|
|||||||
# NixOS-only modules. termux runs nix-on-droid (its own module system,
|
# NixOS-only modules. termux runs nix-on-droid (its own module system,
|
||||||
# class = "nixOnDroid"): options like services.*, users.*, sops.*, disko.*
|
# class = "nixOnDroid"): options like services.*, users.*, sops.*, disko.*
|
||||||
# and nixpkgs.overlays (flake assertion) do not exist there.
|
# and nixpkgs.overlays (flake assertion) do not exist there.
|
||||||
moduleArgs = config: {
|
#
|
||||||
inherit inputs;
|
# `xlib` arrives as a module argument (see lib/mkSystem.nix) and is plain
|
||||||
xlib = config.xlib;
|
# data, not a module option, so nothing here has to declare or set it.
|
||||||
};
|
|
||||||
defaultModule =
|
defaultModule =
|
||||||
{
|
{
|
||||||
config,
|
|
||||||
deviceType,
|
|
||||||
lib,
|
lib,
|
||||||
xlib,
|
xlib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
|
||||||
isDesktop = builtins.elem deviceType [
|
|
||||||
"primary"
|
|
||||||
"secondary"
|
|
||||||
];
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
imports =
|
imports =
|
||||||
with inputs;
|
with inputs;
|
||||||
@@ -37,33 +28,28 @@ let
|
|||||||
self.homeConfigurations.default.nixosModule # default homeConfigurations
|
self.homeConfigurations.default.nixosModule # default homeConfigurations
|
||||||
disko.nixosModules.disko # disko module
|
disko.nixosModules.disko # disko module
|
||||||
]
|
]
|
||||||
++ lib.optional isDesktop ./desktop # desktop class: primary/secondary
|
# desktop class: primary/secondary
|
||||||
|
++ lib.optional xlib.isDesktop ./desktop
|
||||||
# device-type module dir; "minimal" has no extra modules
|
# device-type module dir; "minimal" has no extra modules
|
||||||
++ lib.optional (!isDesktop && deviceType != "minimal") (./. + "/${deviceType}");
|
++ lib.optional (!xlib.isDesktop && xlib.device.type != "minimal") (./. + "/${xlib.device.type}");
|
||||||
nixpkgs.overlays = with inputs; [
|
nixpkgs.overlays = with inputs; [
|
||||||
self.nixosOverlays.default
|
self.nixosOverlays.default
|
||||||
];
|
];
|
||||||
networking.hostName = lib.mkDefault config.xlib.device.hostname;
|
networking.hostName = lib.mkDefault xlib.device.hostname;
|
||||||
_module.args = moduleArgs config;
|
|
||||||
};
|
};
|
||||||
strictModule =
|
strictModule =
|
||||||
{
|
{
|
||||||
config,
|
|
||||||
deviceType,
|
|
||||||
lib,
|
|
||||||
xlib,
|
xlib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
imports = with inputs; [
|
imports = [
|
||||||
# ./essentials
|
# ./essentials
|
||||||
# ./users.nix
|
# ./users.nix
|
||||||
./options.nix
|
./options.nix
|
||||||
(./. + "/${deviceType}")
|
(./. + "/${xlib.device.type}")
|
||||||
# sops-nix.nixosModules.sops
|
# sops-nix.nixosModules.sops
|
||||||
];
|
];
|
||||||
|
|
||||||
_module.args = moduleArgs config;
|
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
|||||||
+25
-15
@@ -3,21 +3,31 @@
|
|||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
lib.mkIf config.xlib.ssh.enable {
|
{
|
||||||
services.openssh = {
|
options.host.ssh = {
|
||||||
enable = true;
|
enable = lib.mkOption {
|
||||||
allowSFTP = true;
|
type = lib.types.bool;
|
||||||
openFirewall = lib.mkDefault false;
|
default = false;
|
||||||
hostKeys = [
|
description = "Enable the SSH server with the shared config below.";
|
||||||
{
|
};
|
||||||
path = "/etc/ssh/id_ed25519";
|
};
|
||||||
type = "ed25519";
|
|
||||||
}
|
config = lib.mkIf config.host.ssh.enable {
|
||||||
];
|
services.openssh = {
|
||||||
settings = {
|
enable = true;
|
||||||
PasswordAuthentication = false;
|
allowSFTP = true;
|
||||||
PermitRootLogin = "yes";
|
openFirewall = lib.mkDefault false;
|
||||||
UsePAM = true;
|
hostKeys = [
|
||||||
|
{
|
||||||
|
path = "/etc/ssh/id_ed25519";
|
||||||
|
type = "ed25519";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
settings = {
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
PermitRootLogin = "yes";
|
||||||
|
UsePAM = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-102
@@ -1,109 +1,41 @@
|
|||||||
{
|
{
|
||||||
config,
|
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
# Cross-module options: declared here, not in the module that reads them.
|
||||||
# Option factory for the xlib.dirs namespace
|
#
|
||||||
mkDir =
|
# An option belongs in this file when at least one context *sets* it while
|
||||||
default: description:
|
# another module *reads* it — the reader cannot be the only place that knows
|
||||||
lib.mkOption {
|
# the option exists. `modules/essentials/ssh.nix` does not belong here: it
|
||||||
type = lib.types.str;
|
# declares and reads `host.ssh.enable` itself, within one module.
|
||||||
inherit default description;
|
|
||||||
};
|
|
||||||
|
|
||||||
helpers = import ../lib/xlib.nix { inherit lib; };
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
options = {
|
options.host."3x-ui" = {
|
||||||
xlib = {
|
# Domain whose Let's Encrypt cert (at /var/lib/acme/<domain>/)
|
||||||
device = {
|
# gets mounted read-only into the 3x-ui container so the panel
|
||||||
type = lib.mkOption {
|
# can terminate TLS itself. Set null if 3x-ui serves plain HTTP
|
||||||
type = lib.types.enum [
|
# and TLS is terminated by an upstream nginx.
|
||||||
"minimal"
|
certDomain = lib.mkOption {
|
||||||
"primary"
|
type = lib.types.nullOr lib.types.str;
|
||||||
"secondary"
|
default = null;
|
||||||
"server"
|
example = "pubray1.zeroq.su";
|
||||||
"vds"
|
description = ''
|
||||||
"wsl"
|
Domain whose LE cert should be mounted into the 3x-ui
|
||||||
"termux"
|
container at /root/cert/fullchain.pem and key.pem.
|
||||||
];
|
'';
|
||||||
default = "minimal";
|
};
|
||||||
description = "Type of device for this host.";
|
# Publish host:15380 → container:443. Only nodes that host an
|
||||||
};
|
# Xray REALITY inbound on container:443 need this (so nginx
|
||||||
username = lib.mkOption {
|
# stream can forward TLS to Xray via 127.0.0.1:15380 while Xray
|
||||||
type = lib.types.str;
|
# itself sees incoming connections on its configured port 443).
|
||||||
default = "oqyude";
|
# Set false on nodes that only run the 3x-ui panel.
|
||||||
description = "Username for host.";
|
reality443Forwarding = lib.mkOption {
|
||||||
};
|
type = lib.types.bool;
|
||||||
hostname = lib.mkOption {
|
default = false;
|
||||||
type = lib.types.str;
|
description = ''
|
||||||
default = "nixos";
|
When true, publish host:15380 → container:443 so Xray
|
||||||
description = "Hostname...";
|
inside the container can serve REALITY on its real
|
||||||
};
|
configured port 443 (nginx stream forwards 443 → 15380).
|
||||||
};
|
'';
|
||||||
ssh = {
|
|
||||||
enable = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "Enable SSH server with the standard config.";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
dirs = {
|
|
||||||
user-home = mkDir "/home/${config.xlib.device.username}" "User home directory.";
|
|
||||||
user-storage = mkDir "${config.xlib.dirs.user-home}/Storage" "User storage directory.";
|
|
||||||
archive-drive = mkDir "/mnt/archive" "Archive drive mount point.";
|
|
||||||
lamet-drive = mkDir "/mnt/lamet" "Lamet drive mount point.";
|
|
||||||
mobile-drive = mkDir "/mnt/mobile" "Mobile drive mount point.";
|
|
||||||
therima-drive = mkDir "/mnt/therima" "Therima drive mount point.";
|
|
||||||
vetymae-drive = mkDir "/mnt/vetymae" "Vetymae drive mount point.";
|
|
||||||
soptur-drive = mkDir "/mnt/soptur" "Soptur drive mount point.";
|
|
||||||
wsl-home = mkDir "/mnt/c/Users/${config.xlib.device.username}" "WSL home directory.";
|
|
||||||
wsl-storage = mkDir "${config.xlib.dirs.wsl-home}/Storage" "WSL storage directory.";
|
|
||||||
server-home = mkDir "/home/${config.xlib.device.username}/External" "Server home directory.";
|
|
||||||
server-credentials = mkDir "${config.xlib.dirs.server-home}/Credentials/server" "Server credentials directory.";
|
|
||||||
storage = mkDir "${config.xlib.dirs.server-home}/Storage" "General storage directory.";
|
|
||||||
calibre-library = mkDir "${config.xlib.dirs.server-home}/Books-Library" "Calibre library directory.";
|
|
||||||
music-library = mkDir "${config.xlib.dirs.user-home}/Music" "Music library directory.";
|
|
||||||
services-folder = mkDir "${config.xlib.dirs.server-home}/Services" "All services folder.";
|
|
||||||
services-mnt-folder = mkDir "/mnt/services" "All services folder.";
|
|
||||||
services-nodes-folder = mkDir "${config.xlib.dirs.services-mnt-folder}/nodes" "All nodes folder.";
|
|
||||||
postgresql-folder = mkDir "${config.xlib.dirs.services-mnt-folder}/postgresql" "PostgreSQL service folder.";
|
|
||||||
};
|
|
||||||
helpers = lib.mkOption {
|
|
||||||
type = lib.types.anything;
|
|
||||||
default = helpers;
|
|
||||||
description = "Shared helper functions (see lib/xlib.nix).";
|
|
||||||
};
|
|
||||||
services."3x-ui" = {
|
|
||||||
# Domain whose Let's Encrypt cert (at /var/lib/acme/<domain>/)
|
|
||||||
# gets mounted read-only into the 3x-ui container so the panel
|
|
||||||
# can terminate TLS itself. Set null if 3x-ui serves plain HTTP
|
|
||||||
# and TLS is terminated by an upstream nginx.
|
|
||||||
certDomain = lib.mkOption {
|
|
||||||
type = lib.types.nullOr lib.types.str;
|
|
||||||
default = null;
|
|
||||||
example = "pubray1.zeroq.su";
|
|
||||||
description = ''
|
|
||||||
Domain whose LE cert should be mounted into the 3x-ui
|
|
||||||
container at /root/cert/fullchain.pem and key.pem.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
# Publish host:15380 → container:443. Only nodes that host an
|
|
||||||
# Xray REALITY inbound on container:443 need this (so nginx
|
|
||||||
# stream can forward TLS to Xray via 127.0.0.1:15380 while Xray
|
|
||||||
# itself sees incoming connections on its configured port 443).
|
|
||||||
# Set false on nodes that only run the 3x-ui panel.
|
|
||||||
reality443Forwarding = lib.mkOption {
|
|
||||||
type = lib.types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
When true, publish host:15380 → container:443 so Xray
|
|
||||||
inside the container can serve REALITY on its real
|
|
||||||
configured port 443 (nginx stream forwards 443 → 15380).
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
# there are other vhosts on the same port). Cert is still mounted in
|
# there are other vhosts on the same port). Cert is still mounted in
|
||||||
# case 3x-ui is later reconfigured to terminate TLS itself (e.g. for
|
# case 3x-ui is later reconfigured to terminate TLS itself (e.g. for
|
||||||
# direct node-API access); nginx doesn't have to use it.
|
# direct node-API access); nginx doesn't have to use it.
|
||||||
xlib.services."3x-ui".certDomain = "x.zeroq.su";
|
host."3x-ui".certDomain = "x.zeroq.su";
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
(xlib.helpers.mkTmpfile "d" "/mnt" "0755" "root" "root")
|
(xlib.helpers.mkTmpfile "d" "/mnt" "0755" "root" "root")
|
||||||
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-mnt-folder "0755" "root" "root")
|
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-mnt-folder "0755" "root" "root")
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ let
|
|||||||
);
|
);
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
xlib.device.username = "oqyude";
|
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
mutableUsers = false;
|
mutableUsers = false;
|
||||||
users = {
|
users = {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
];
|
];
|
||||||
# VDS hosts the public-facing Xray REALITY inbound on container:443,
|
# VDS hosts the public-facing Xray REALITY inbound on container:443,
|
||||||
# fronted by nginx stream on host:443 → host:15380 → container:443.
|
# fronted by nginx stream on host:443 → host:15380 → container:443.
|
||||||
xlib.services."3x-ui" = {
|
host."3x-ui" = {
|
||||||
certDomain = "pubray1.zeroq.su";
|
certDomain = "pubray1.zeroq.su";
|
||||||
reality443Forwarding = true;
|
reality443Forwarding = true;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user