mirror of
https://github.com/oqyude/nixos.git
synced 2026-10-07 20:47:14 +03:00
big refactoring
This commit is contained in:
+115
-80
@@ -7,7 +7,11 @@
|
||||
}:
|
||||
let
|
||||
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 =
|
||||
if certDomain == null then
|
||||
[ ]
|
||||
@@ -28,94 +32,125 @@ let
|
||||
];
|
||||
# VDS-only: nginx stream forwards host:443 → 127.0.0.1:15380 →
|
||||
# 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
|
||||
{
|
||||
virtualisation = {
|
||||
podman = {
|
||||
enable = true;
|
||||
autoPrune = {
|
||||
options.host."3x-ui" = {
|
||||
# Domain whose LE cert should be mounted into the 3x-ui container at
|
||||
# /root/cert/fullchain.pem and key.pem. 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).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation = {
|
||||
podman = {
|
||||
enable = true;
|
||||
flags = [ "--all" ];
|
||||
};
|
||||
dockerCompat = true;
|
||||
};
|
||||
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";
|
||||
autoPrune = {
|
||||
enable = true;
|
||||
flags = [ "--all" ];
|
||||
};
|
||||
volumes = [
|
||||
"${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;
|
||||
dockerCompat = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
"podman-3xui_app" = {
|
||||
serviceConfig.Restart = lib.mkOverride 90 "always";
|
||||
partOf = [ "podman-compose-3x-ui-root.target" ];
|
||||
wantedBy = [ "podman-compose-3x-ui-root.target" ];
|
||||
};
|
||||
"podman-update-3xui_app" = {
|
||||
path = [ pkgs.podman ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
TimeoutSec = 300;
|
||||
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 = [
|
||||
"${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;
|
||||
};
|
||||
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 ];
|
||||
systemd = {
|
||||
services = {
|
||||
"podman-3xui_app" = {
|
||||
serviceConfig.Restart = lib.mkOverride 90 "always";
|
||||
partOf = [ "podman-compose-3x-ui-root.target" ];
|
||||
wantedBy = [ "podman-compose-3x-ui-root.target" ];
|
||||
};
|
||||
"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
-25
@@ -3,30 +3,20 @@ let
|
||||
# NixOS-only modules. termux runs nix-on-droid (its own module system,
|
||||
# class = "nixOnDroid"): options like services.*, users.*, sops.*, disko.*
|
||||
# and nixpkgs.overlays (flake assertion) do not exist there.
|
||||
moduleArgs = config: {
|
||||
inherit inputs;
|
||||
xlib = config.xlib;
|
||||
};
|
||||
#
|
||||
# `xlib` arrives as a module argument (see lib/mkSystem.nix) and is plain
|
||||
# data, not a module option, so nothing here has to declare or set it.
|
||||
defaultModule =
|
||||
{
|
||||
config,
|
||||
deviceType,
|
||||
lib,
|
||||
xlib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
isDesktop = builtins.elem deviceType [
|
||||
"primary"
|
||||
"secondary"
|
||||
];
|
||||
in
|
||||
{
|
||||
imports =
|
||||
with inputs;
|
||||
[
|
||||
./essentials
|
||||
./options.nix
|
||||
./users.nix
|
||||
|
||||
home-manager.nixosModules.home-manager # home-manager module
|
||||
@@ -37,33 +27,27 @@ let
|
||||
self.homeConfigurations.default.nixosModule # default homeConfigurations
|
||||
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
|
||||
++ lib.optional (!isDesktop && deviceType != "minimal") (./. + "/${deviceType}");
|
||||
++ lib.optional (!xlib.isDesktop && xlib.device.type != "minimal") (./. + "/${xlib.device.type}");
|
||||
nixpkgs.overlays = with inputs; [
|
||||
self.nixosOverlays.default
|
||||
];
|
||||
networking.hostName = lib.mkDefault config.xlib.device.hostname;
|
||||
_module.args = moduleArgs config;
|
||||
networking.hostName = lib.mkDefault xlib.device.hostname;
|
||||
};
|
||||
strictModule =
|
||||
{
|
||||
config,
|
||||
deviceType,
|
||||
lib,
|
||||
xlib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = with inputs; [
|
||||
imports = [
|
||||
# ./essentials
|
||||
# ./users.nix
|
||||
./options.nix
|
||||
(./. + "/${deviceType}")
|
||||
(./. + "/${xlib.device.type}")
|
||||
# sops-nix.nixosModules.sops
|
||||
];
|
||||
|
||||
_module.args = moduleArgs config;
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
+25
-15
@@ -3,21 +3,31 @@
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
lib.mkIf config.xlib.ssh.enable {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
allowSFTP = true;
|
||||
openFirewall = lib.mkDefault false;
|
||||
hostKeys = [
|
||||
{
|
||||
path = "/etc/ssh/id_ed25519";
|
||||
type = "ed25519";
|
||||
}
|
||||
];
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
PermitRootLogin = "yes";
|
||||
UsePAM = true;
|
||||
{
|
||||
options.host.ssh = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "Enable the SSH server with the shared config below.";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.host.ssh.enable {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
allowSFTP = true;
|
||||
openFirewall = lib.mkDefault false;
|
||||
hostKeys = [
|
||||
{
|
||||
path = "/etc/ssh/id_ed25519";
|
||||
type = "ed25519";
|
||||
}
|
||||
];
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
PermitRootLogin = "yes";
|
||||
UsePAM = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# Option factory for the xlib.dirs namespace
|
||||
mkDir =
|
||||
default: description:
|
||||
lib.mkOption {
|
||||
type = lib.types.str;
|
||||
inherit default description;
|
||||
};
|
||||
|
||||
helpers = import ../lib/xlib.nix { inherit lib; };
|
||||
in
|
||||
{
|
||||
options = {
|
||||
xlib = {
|
||||
device = {
|
||||
type = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"minimal"
|
||||
"primary"
|
||||
"secondary"
|
||||
"server"
|
||||
"vds"
|
||||
"wsl"
|
||||
"termux"
|
||||
];
|
||||
default = "minimal";
|
||||
description = "Type of device for this host.";
|
||||
};
|
||||
username = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "oqyude";
|
||||
description = "Username for host.";
|
||||
};
|
||||
hostname = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "nixos";
|
||||
description = "Hostname...";
|
||||
};
|
||||
};
|
||||
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
|
||||
# case 3x-ui is later reconfigured to terminate TLS itself (e.g. for
|
||||
# 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 = [
|
||||
(xlib.helpers.mkTmpfile "d" "/mnt" "0755" "root" "root")
|
||||
(xlib.helpers.mkTmpfile "d" xlib.dirs.services-mnt-folder "0755" "root" "root")
|
||||
|
||||
@@ -37,8 +37,6 @@ let
|
||||
);
|
||||
in
|
||||
{
|
||||
xlib.device.username = "oqyude";
|
||||
|
||||
users = {
|
||||
mutableUsers = false;
|
||||
users = {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
];
|
||||
# VDS hosts the public-facing Xray REALITY inbound on container:443,
|
||||
# fronted by nginx stream on host:443 → host:15380 → container:443.
|
||||
xlib.services."3x-ui" = {
|
||||
host."3x-ui" = {
|
||||
certDomain = "pubray1.zeroq.su";
|
||||
reality443Forwarding = true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user