{ config, lib, pkgs, xlib, ... }: let panel = "${xlib.dirs.services-nodes-folder}/${xlib.device.hostname}/3x-ui"; in { virtualisation = { podman = { enable = true; autoPrune = { 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"; }; volumes = [ "${panel}/cert/:/root/cert:rw" "${panel}/db/:/etc/x-ui:rw" ]; log-driver = "journald"; # Port-forwarded networking (replaces --network=host). # Bridges the same ports that were previously reachable while # --network=host was set: # 2049/tcp — 3x-ui web panel (reverse-proxied by nginx) # 2096/tcp — subscription endpoint (reverse-proxied by nginx) # 14380-15380/tcp+udp — Xray inbounds (matches firewall open range) # Adding a new inbound through the 3x-ui panel on a port outside # this range will require extending this list and rebuilding. ports = [ "0.0.0.0:2049:2049/tcp" "0.0.0.0:2096:2096/tcp" "0.0.0.0:14380-15380:14380-15380/tcp" "0.0.0.0:14380-15380:14380-15380/udp" ]; }; }; }; 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" ]; }; # Update "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 ''; }; # Builds # "podman-build-3xui_app" = { # path = [ # pkgs.podman # pkgs.git # ]; # serviceConfig = { # Type = "oneshot"; # TimeoutSec = 300; # }; # script = '' # cd /mnt/containers/3x-ui # podman build -t compose2nix/3xui_app -f ./Dockerfile . # ''; # }; }; # Root service # When started, this will automatically create all resources and start # the containers. When stopped, this will teardown all 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; }; }; # Folders tmpfiles.rules = [ "d ${xlib.dirs.services-mnt-folder} 0755 root root -" "d ${xlib.dirs.services-nodes-folder} 0755 root root -" "d ${xlib.dirs.services-nodes-folder}/${xlib.device.hostname} 0755 root root -" "d ${panel} 0755 root root -" "d ${panel}/db 0755 root root -" "d ${panel}/cert 0755 root root -" "Z ${panel} 0755 root root -" ]; }; # Enable container name DNS for all Podman networks. networking.firewall = { allowedUDPPortRanges = [ { from = 14380; to = 15380; } ]; allowedTCPPortRanges = [ { from = 14380; to = 15380; } ]; interfaces = let matchAll = if !config.networking.nftables.enable then "podman+" else "podman*"; in { "${matchAll}".allowedUDPPorts = [ 53 ]; }; }; }