2023-07-25 23:33:37 +08:00
|
|
|
inputs:
|
|
|
|
{
|
|
|
|
options.nixos.services = let inherit (inputs.lib) mkOption types; in
|
|
|
|
{
|
|
|
|
impermanence =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
persistence = mkOption { type = types.nonEmptyStr; default = "/nix/persistent"; };
|
2023-08-04 18:46:20 +08:00
|
|
|
root = mkOption { type = types.nonEmptyStr; default = "/nix/rootfs/current"; };
|
2023-07-25 23:33:37 +08:00
|
|
|
};
|
|
|
|
snapper =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
configs = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
|
|
|
};
|
2023-07-26 11:24:27 +08:00
|
|
|
kmscon.enable = mkOption { type = types.bool; default = false; };
|
2023-07-26 17:03:09 +08:00
|
|
|
fontconfig.enable = mkOption { type = types.bool; default = false; };
|
2023-07-26 17:08:32 +08:00
|
|
|
u2f.enable = mkOption { type = types.bool; default = false; };
|
2023-07-26 21:05:46 +08:00
|
|
|
sops =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
keyPathPrefix = mkOption { type = types.str; default = ""; };
|
|
|
|
};
|
|
|
|
samba =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
wsdd = mkOption { type = types.bool; default = false; };
|
|
|
|
private = mkOption { type = types.bool; default = false; };
|
|
|
|
hostsAllowed = mkOption { type = types.str; default = "127."; };
|
|
|
|
shares = mkOption
|
2023-07-25 23:33:37 +08:00
|
|
|
{
|
2023-07-26 21:05:46 +08:00
|
|
|
type = types.attrsOf (types.submodule { options =
|
2023-07-25 23:33:37 +08:00
|
|
|
{
|
2023-07-26 21:05:46 +08:00
|
|
|
comment = mkOption { type = types.nullOr types.nonEmptyStr; default = null; };
|
|
|
|
path = mkOption { type = types.nonEmptyStr; };
|
|
|
|
};});
|
|
|
|
default = {};
|
|
|
|
};
|
|
|
|
};
|
2023-07-27 00:07:20 +08:00
|
|
|
sshd.enable = mkOption { type = types.bool; default = false; };
|
2023-07-27 19:01:58 +08:00
|
|
|
xrayClient =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
2023-08-10 20:14:41 +08:00
|
|
|
serverAddress = mkOption { type = types.nonEmptyStr; };
|
|
|
|
serverName = mkOption { type = types.nonEmptyStr; };
|
2023-07-27 21:50:51 +08:00
|
|
|
dns = mkOption { type = types.submodule { options =
|
|
|
|
{
|
|
|
|
hosts = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
|
|
|
extraInterfaces = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
|
|
|
|
}; }; };
|
2023-07-27 19:01:58 +08:00
|
|
|
};
|
2023-08-10 19:41:33 +08:00
|
|
|
xrayServer =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
serverName = mkOption { type = types.nonEmptyStr; };
|
|
|
|
};
|
2023-07-27 19:01:58 +08:00
|
|
|
firewall.trustedInterfaces = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
|
2023-08-04 20:07:57 +08:00
|
|
|
acme =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
certs = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
|
|
|
|
};
|
2023-08-07 21:16:49 +08:00
|
|
|
frpClient =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
serverName = mkOption { type = types.nonEmptyStr; };
|
|
|
|
user = mkOption { type = types.nonEmptyStr; };
|
|
|
|
tcp = mkOption
|
|
|
|
{
|
2023-08-14 14:24:39 +08:00
|
|
|
type = types.attrsOf (types.submodule (inputs:
|
2023-08-07 21:16:49 +08:00
|
|
|
{
|
|
|
|
options =
|
|
|
|
{
|
2023-08-14 14:24:39 +08:00
|
|
|
localIp = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; };
|
2023-08-07 21:16:49 +08:00
|
|
|
localPort = mkOption { type = types.ints.unsigned; };
|
2023-08-14 14:24:39 +08:00
|
|
|
remoteIp = mkOption { type = types.nonEmptyStr; default = "127.0.0.1"; };
|
|
|
|
remotePort = mkOption { type = types.ints.unsigned; default = inputs.config.localPort; };
|
2023-08-07 21:16:49 +08:00
|
|
|
};
|
2023-08-14 14:24:39 +08:00
|
|
|
}));
|
2023-08-07 21:16:49 +08:00
|
|
|
default = {};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
frpServer =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
serverName = mkOption { type = types.nonEmptyStr; };
|
|
|
|
};
|
2023-08-14 13:55:27 +08:00
|
|
|
nix-serve =
|
|
|
|
{
|
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
|
|
|
hostname = mkOption { type = types.nonEmptyStr; };
|
|
|
|
};
|
2023-08-10 10:15:21 +08:00
|
|
|
smartd.enable = mkOption { type = types.bool; default = false; };
|
2023-08-10 17:50:08 +08:00
|
|
|
nginx =
|
|
|
|
{
|
2023-08-13 21:02:56 +08:00
|
|
|
enable = mkOption { type = types.bool; default = false; };
|
2023-08-10 17:50:08 +08:00
|
|
|
transparentProxy =
|
|
|
|
{
|
2023-08-14 13:49:17 +08:00
|
|
|
enable = mkOption { type = types.bool; default = true; };
|
2023-08-10 19:41:33 +08:00
|
|
|
externalIp = mkOption { type = types.nonEmptyStr; };
|
2023-08-15 00:00:48 +08:00
|
|
|
map = mkOption { type = types.attrsOf types.ints.unsigned; default = {};};
|
2023-08-10 17:50:08 +08:00
|
|
|
};
|
2023-08-12 11:58:01 +08:00
|
|
|
httpProxy = mkOption
|
|
|
|
{
|
|
|
|
type = types.attrsOf (types.submodule { options =
|
|
|
|
{
|
|
|
|
upstream = mkOption { type = types.nonEmptyStr; };
|
|
|
|
rewriteHttps = mkOption { type = types.bool; default = false; };
|
2023-08-13 22:20:03 +08:00
|
|
|
websocket = mkOption { type = types.bool; default = false; };
|
2023-08-13 22:43:34 +08:00
|
|
|
http2 = mkOption { type = types.bool; default = true; };
|
2023-08-12 11:58:01 +08:00
|
|
|
# setHeaders = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
|
|
|
|
# addPin = mkOption { type = types.bool; default = false; };
|
|
|
|
# detectPin = mkOption { type = types.bool; default = false; };
|
|
|
|
}; });
|
|
|
|
default = {};
|
|
|
|
};
|
2023-08-10 17:50:08 +08:00
|
|
|
};
|
2023-08-13 23:24:47 +08:00
|
|
|
fileshelter.enable = mkOption { type = types.bool; default = false; };
|
2023-08-14 17:07:57 +08:00
|
|
|
postgresql.enable = mkOption { type = types.bool; default = false; };
|
2023-08-14 21:40:01 +08:00
|
|
|
rsshub.enable = mkOption { type = types.bool; default = false; };
|
2023-08-15 00:53:30 +08:00
|
|
|
wallabag.enable = mkOption { type = types.bool; default = false; };
|
2023-08-16 19:51:55 +08:00
|
|
|
docker = mkOption
|
|
|
|
{
|
|
|
|
type = types.attrsOf (types.submodule (inputs: { options =
|
|
|
|
{
|
|
|
|
user = mkOption { type = types.nullOr 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 = {};
|
|
|
|
};
|
2023-07-26 21:05:46 +08:00
|
|
|
};
|
|
|
|
config =
|
|
|
|
let
|
2023-08-04 20:07:57 +08:00
|
|
|
inherit (inputs.lib) mkMerge mkIf;
|
2023-07-26 21:05:46 +08:00
|
|
|
inherit (inputs.localLib) stripeTabs attrsToList;
|
2023-07-26 21:11:47 +08:00
|
|
|
inherit (inputs.config.nixos) services;
|
2023-08-16 20:22:27 +08:00
|
|
|
inherit (builtins) map listToAttrs concatStringsSep toString elemAt genList length attrNames attrValues
|
|
|
|
concatLists;
|
2023-07-26 21:05:46 +08:00
|
|
|
in mkMerge
|
|
|
|
[
|
|
|
|
(
|
|
|
|
mkIf services.impermanence.enable
|
2023-07-26 11:24:27 +08:00
|
|
|
{
|
2023-08-04 18:46:20 +08:00
|
|
|
environment.persistence =
|
2023-07-26 21:05:46 +08:00
|
|
|
{
|
2023-08-04 18:46:20 +08:00
|
|
|
"${services.impermanence.persistence}" =
|
|
|
|
{
|
|
|
|
hideMounts = true;
|
|
|
|
directories =
|
|
|
|
[
|
|
|
|
"/etc/NetworkManager/system-connections"
|
|
|
|
"/home"
|
|
|
|
"/root"
|
|
|
|
"/var/db"
|
|
|
|
"/var/lib"
|
|
|
|
"/var/log"
|
|
|
|
"/var/spool"
|
|
|
|
];
|
|
|
|
files =
|
|
|
|
[
|
|
|
|
"/etc/machine-id"
|
|
|
|
"/etc/ssh/ssh_host_ed25519_key.pub"
|
|
|
|
"/etc/ssh/ssh_host_ed25519_key"
|
|
|
|
"/etc/ssh/ssh_host_rsa_key.pub"
|
|
|
|
"/etc/ssh/ssh_host_rsa_key"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
"${services.impermanence.root}" =
|
|
|
|
{
|
|
|
|
hideMounts = true;
|
|
|
|
directories = []
|
|
|
|
++ (if inputs.config.services.xserver.displayManager.sddm.enable then
|
|
|
|
[{ directory = "/var/lib/sddm"; user = "sddm"; group = "sddm"; mode = "0700"; }] else []);
|
|
|
|
};
|
2023-07-26 21:05:46 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
(
|
|
|
|
mkIf services.snapper.enable
|
|
|
|
{
|
|
|
|
services.snapper.configs =
|
|
|
|
let
|
|
|
|
f = (config:
|
|
|
|
{
|
|
|
|
inherit (config) name;
|
|
|
|
value =
|
|
|
|
{
|
|
|
|
SUBVOLUME = config.value;
|
|
|
|
TIMELINE_CREATE = true;
|
|
|
|
TIMELINE_CLEANUP = true;
|
|
|
|
TIMELINE_MIN_AGE = 1800;
|
|
|
|
TIMELINE_LIMIT_HOURLY = "10";
|
|
|
|
TIMELINE_LIMIT_DAILY = "7";
|
|
|
|
TIMELINE_LIMIT_WEEKLY = "1";
|
|
|
|
TIMELINE_LIMIT_MONTHLY = "0";
|
|
|
|
TIMELINE_LIMIT_YEARLY = "0";
|
|
|
|
};
|
|
|
|
});
|
|
|
|
in
|
2023-08-04 20:07:57 +08:00
|
|
|
listToAttrs (map f (attrsToList services.snapper.configs));
|
2023-08-04 22:18:39 +08:00
|
|
|
nixpkgs.config.packageOverrides = pkgs:
|
|
|
|
{
|
|
|
|
snapper = pkgs.snapper.overrideAttrs (attrs:
|
|
|
|
{
|
|
|
|
patches = (if (attrs ? patches) then attrs.patches else []) ++ [ ./snapper.patch ];
|
|
|
|
});
|
|
|
|
};
|
2023-07-26 21:05:46 +08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
(
|
|
|
|
mkIf services.kmscon.enable
|
2023-07-26 17:03:09 +08:00
|
|
|
{
|
2023-07-26 21:05:46 +08:00
|
|
|
services.kmscon =
|
2023-07-26 17:03:09 +08:00
|
|
|
{
|
2023-07-26 21:05:46 +08:00
|
|
|
enable = true;
|
|
|
|
fonts = [{ name = "FiraCode Nerd Font Mono"; package = inputs.pkgs.nerdfonts; }];
|
2023-07-26 17:03:09 +08:00
|
|
|
};
|
2023-07-26 21:05:46 +08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
(
|
|
|
|
mkIf services.fontconfig.enable
|
|
|
|
{
|
|
|
|
fonts =
|
|
|
|
{
|
|
|
|
fontDir.enable = true;
|
2023-08-09 22:05:51 +08:00
|
|
|
packages = with inputs.pkgs;
|
2023-07-26 21:05:46 +08:00
|
|
|
[ noto-fonts source-han-sans source-han-serif source-code-pro hack-font jetbrains-mono nerdfonts ];
|
|
|
|
fontconfig.defaultFonts =
|
|
|
|
{
|
|
|
|
emoji = [ "Noto Color Emoji" ];
|
|
|
|
monospace = [ "Noto Sans Mono CJK SC" "Sarasa Mono SC" "DejaVu Sans Mono"];
|
|
|
|
sansSerif = [ "Noto Sans CJK SC" "Source Han Sans SC" "DejaVu Sans" ];
|
|
|
|
serif = [ "Noto Serif CJK SC" "Source Han Serif SC" "DejaVu Serif" ];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
(
|
|
|
|
mkIf services.sops.enable
|
|
|
|
{
|
|
|
|
sops =
|
|
|
|
{
|
|
|
|
defaultSopsFile = ../../secrets/${inputs.config.networking.hostName}.yaml;
|
|
|
|
# sops start before impermanence, so we need to use the absolute path
|
|
|
|
age.sshKeyPaths = [ "${services.sops.keyPathPrefix}/etc/ssh/ssh_host_ed25519_key" ];
|
2023-07-27 00:07:20 +08:00
|
|
|
gnupg.sshKeyPaths = [ "${services.sops.keyPathPrefix}/etc/ssh/ssh_host_rsa_key" ];
|
2023-07-26 21:05:46 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
|
|
|
(
|
|
|
|
mkIf services.samba.enable
|
2023-07-26 17:08:32 +08:00
|
|
|
{
|
2023-07-26 21:05:46 +08:00
|
|
|
# make shares visible for windows 10 clients
|
|
|
|
services =
|
|
|
|
{
|
|
|
|
samba-wsdd.enable = services.samba.wsdd;
|
|
|
|
samba =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
openFirewall = !services.samba.private;
|
|
|
|
securityType = "user";
|
|
|
|
extraConfig = stripeTabs
|
|
|
|
''
|
|
|
|
workgroup = WORKGROUP
|
|
|
|
server string = Samba Server
|
|
|
|
server role = standalone server
|
|
|
|
hosts allow = ${services.samba.hostsAllowed}
|
|
|
|
dns proxy = no
|
|
|
|
'';
|
|
|
|
# obey pam restrictions = yes
|
|
|
|
# encrypt passwords = no
|
2023-08-04 20:07:57 +08:00
|
|
|
shares = listToAttrs (map
|
2023-07-26 21:05:46 +08:00
|
|
|
(share:
|
|
|
|
{
|
|
|
|
name = share.name;
|
|
|
|
value =
|
|
|
|
{
|
|
|
|
comment = if share.value.comment != null then share.value.comment else share.name;
|
|
|
|
path = share.value.path;
|
|
|
|
browseable = true;
|
|
|
|
writeable = true;
|
|
|
|
"create mask" = "664";
|
|
|
|
"force create mode" = "644";
|
|
|
|
"directory mask" = "2755";
|
|
|
|
"force directory mode" = "2755";
|
|
|
|
};
|
|
|
|
})
|
|
|
|
(attrsToList services.samba.shares));
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
2023-07-27 00:07:20 +08:00
|
|
|
(
|
2023-08-02 16:49:43 +08:00
|
|
|
mkIf services.sshd.enable
|
|
|
|
{
|
|
|
|
services.openssh =
|
|
|
|
{
|
|
|
|
enable = true;
|
2023-08-02 18:10:22 +08:00
|
|
|
settings =
|
|
|
|
{
|
2023-08-08 16:36:34 +08:00
|
|
|
X11Forwarding = true;
|
2023-08-02 18:10:22 +08:00
|
|
|
TrustedUserCAKeys = "${inputs.config.security.pam.ussh.caFile}";
|
|
|
|
ChallengeResponseAuthentication = false;
|
2023-08-03 17:03:54 +08:00
|
|
|
PasswordAuthentication = false;
|
|
|
|
KbdInteractiveAuthentication = false;
|
2023-08-02 18:10:22 +08:00
|
|
|
UsePAM = true;
|
|
|
|
};
|
2023-08-02 16:49:43 +08:00
|
|
|
};
|
|
|
|
}
|
2023-07-27 00:07:20 +08:00
|
|
|
)
|
2023-07-27 19:01:58 +08:00
|
|
|
(
|
|
|
|
mkIf services.xrayClient.enable
|
|
|
|
{
|
|
|
|
services =
|
|
|
|
{
|
|
|
|
dnsmasq =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
settings =
|
|
|
|
{
|
|
|
|
no-poll = true;
|
2023-08-10 20:47:59 +08:00
|
|
|
log-queries = true;
|
2023-07-27 19:01:58 +08:00
|
|
|
server = [ "127.0.0.1#10853" ];
|
2023-07-27 21:50:51 +08:00
|
|
|
interface = services.xrayClient.dns.extraInterfaces ++ [ "lo" ];
|
2023-07-27 23:41:04 +08:00
|
|
|
bind-dynamic = true;
|
2023-07-27 19:01:58 +08:00
|
|
|
ipset =
|
|
|
|
[
|
|
|
|
"/developer.download.nvidia.com/noproxy_net"
|
|
|
|
"/yuanshen.com/noproxy_net"
|
|
|
|
"/zoom.us/noproxy_net"
|
2023-07-27 21:50:51 +08:00
|
|
|
];
|
|
|
|
address = map (host: "/${host.name}/${host.value}") (attrsToList services.xrayClient.dns.hosts);
|
2023-07-27 19:01:58 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
xray = { enable = true; settingsFile = inputs.config.sops.templates."xray-client.json".path; };
|
|
|
|
v2ray-forwarder = { enable = true; proxyPort = 10880; xmuPort = 10881; };
|
|
|
|
};
|
2023-07-27 19:32:51 +08:00
|
|
|
sops =
|
2023-07-27 19:01:58 +08:00
|
|
|
{
|
2023-07-27 19:32:51 +08:00
|
|
|
templates."xray-client.json" =
|
2023-07-27 19:01:58 +08:00
|
|
|
{
|
2023-08-11 15:30:47 +08:00
|
|
|
owner = inputs.config.users.users.v2ray.name;
|
|
|
|
group = inputs.config.users.users.v2ray.group;
|
2023-07-27 19:32:51 +08:00
|
|
|
content = builtins.toJSON
|
2023-07-27 19:01:58 +08:00
|
|
|
{
|
2023-08-10 20:43:10 +08:00
|
|
|
log.loglevel = "info";
|
2023-07-27 19:32:51 +08:00
|
|
|
dns =
|
|
|
|
{
|
|
|
|
servers =
|
|
|
|
[
|
2023-08-13 02:38:16 +08:00
|
|
|
{ address = "223.5.5.5"; domains = [ "geosite:geolocation-cn" ]; port = 53; }
|
|
|
|
{ address = "8.8.8.8"; domains = [ "geosite:geolocation-!cn" ]; port = 53; }
|
2023-07-27 19:32:51 +08:00
|
|
|
{ address = "223.5.5.5"; expectIPs = [ "geoip:cn" ]; }
|
|
|
|
{ address = "8.8.8.8"; }
|
|
|
|
];
|
|
|
|
disableCache = true;
|
|
|
|
queryStrategy = "UseIPv4";
|
2023-08-13 02:38:16 +08:00
|
|
|
disableFallback = true;
|
2023-07-27 19:32:51 +08:00
|
|
|
tag = "dns-internal";
|
|
|
|
};
|
|
|
|
inbounds =
|
2023-07-27 19:01:58 +08:00
|
|
|
[
|
2023-07-27 19:32:51 +08:00
|
|
|
{
|
|
|
|
port = 10853;
|
|
|
|
protocol = "dokodemo-door";
|
|
|
|
settings = { address = "8.8.8.8"; network = "tcp,udp"; port = 53; };
|
|
|
|
tag = "dns-in";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
port = 10880;
|
|
|
|
protocol = "dokodemo-door";
|
|
|
|
settings = { network = "tcp,udp"; followRedirect = true; };
|
|
|
|
streamSettings.sockopt.tproxy = "tproxy";
|
2023-08-10 20:43:10 +08:00
|
|
|
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
|
2023-07-27 19:32:51 +08:00
|
|
|
tag = "common-in";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
port = 10881;
|
|
|
|
protocol = "dokodemo-door";
|
|
|
|
settings = { network = "tcp,udp"; followRedirect = true; };
|
|
|
|
streamSettings.sockopt.tproxy = "tproxy";
|
|
|
|
tag = "xmu-in";
|
|
|
|
}
|
|
|
|
{ port = 10882; protocol = "socks"; tag = "direct-in"; }
|
2023-07-27 19:01:58 +08:00
|
|
|
];
|
2023-07-27 19:32:51 +08:00
|
|
|
outbounds =
|
|
|
|
[
|
|
|
|
{
|
|
|
|
protocol = "vless";
|
|
|
|
settings.vnext =
|
2023-07-27 19:01:58 +08:00
|
|
|
[{
|
2023-08-10 20:14:41 +08:00
|
|
|
address = services.xrayClient.serverAddress;
|
2023-07-27 19:32:51 +08:00
|
|
|
port = 443;
|
|
|
|
users =
|
|
|
|
[{
|
|
|
|
id = inputs.config.sops.placeholder."xray-client/uuid";
|
|
|
|
encryption = "none";
|
|
|
|
flow = "xtls-rprx-vision-udp443";
|
|
|
|
}];
|
2023-07-27 19:01:58 +08:00
|
|
|
}];
|
2023-07-27 19:32:51 +08:00
|
|
|
streamSettings =
|
2023-07-27 19:01:58 +08:00
|
|
|
{
|
2023-07-27 19:32:51 +08:00
|
|
|
network = "tcp";
|
2023-08-12 23:58:18 +08:00
|
|
|
security = "reality";
|
|
|
|
realitySettings =
|
2023-07-27 19:32:51 +08:00
|
|
|
{
|
2023-08-10 20:14:41 +08:00
|
|
|
serverName = services.xrayClient.serverName;
|
2023-08-12 23:58:18 +08:00
|
|
|
publicKey = "Nl0eVZoDF9d71_3dVsZGJl3UWR9LCv3B14gu7G6vhjk";
|
2023-07-27 19:32:51 +08:00
|
|
|
fingerprint = "firefox";
|
|
|
|
};
|
2023-07-27 19:01:58 +08:00
|
|
|
};
|
2023-07-27 19:32:51 +08:00
|
|
|
tag = "proxy-vless";
|
|
|
|
}
|
|
|
|
{ protocol = "freedom"; tag = "direct"; }
|
|
|
|
{ protocol = "dns"; tag = "dns-out"; }
|
|
|
|
{
|
|
|
|
protocol = "socks";
|
|
|
|
settings.servers = [{ address = "127.0.0.1"; port = 10069; }];
|
|
|
|
tag = "xmu-out";
|
|
|
|
}
|
2023-07-27 19:01:58 +08:00
|
|
|
];
|
2023-07-27 19:32:51 +08:00
|
|
|
routing =
|
|
|
|
{
|
2023-08-10 20:43:10 +08:00
|
|
|
domainStrategy = "AsIs";
|
2023-07-27 19:32:51 +08:00
|
|
|
rules = builtins.map (rule: rule // { type = "field"; })
|
|
|
|
[
|
|
|
|
{ inboundTag = [ "dns-in" ]; outboundTag = "dns-out"; }
|
|
|
|
{ inboundTag = [ "xmu-in" ]; outboundTag = "xmu-out"; }
|
|
|
|
{ inboundTag = [ "direct-in" ]; outboundTag = "direct"; }
|
|
|
|
{ inboundTag = [ "common-in" ]; domain = [ "geosite:geolocation-cn" ]; outboundTag = "direct"; }
|
|
|
|
{
|
|
|
|
inboundTag = [ "common-in" ];
|
|
|
|
domain = [ "geosite:geolocation-!cn" ];
|
|
|
|
outboundTag = "proxy-vless";
|
|
|
|
}
|
|
|
|
{ inboundTag = [ "common-in" "dns-internal" ]; ip = [ "geoip:cn" ]; outboundTag = "direct"; }
|
|
|
|
{ inboundTag = [ "common-in" "dns-internal" ]; outboundTag = "proxy-vless"; }
|
|
|
|
];
|
|
|
|
};
|
2023-07-27 19:01:58 +08:00
|
|
|
};
|
|
|
|
};
|
2023-08-10 20:14:41 +08:00
|
|
|
secrets."xray-client/uuid" = {};
|
2023-07-27 19:01:58 +08:00
|
|
|
};
|
2023-07-27 23:40:39 +08:00
|
|
|
systemd.services.xray =
|
2023-07-27 19:01:58 +08:00
|
|
|
{
|
2023-07-27 23:40:39 +08:00
|
|
|
serviceConfig =
|
2023-07-27 20:12:20 +08:00
|
|
|
{
|
2023-07-27 23:40:39 +08:00
|
|
|
DynamicUser = inputs.lib.mkForce false;
|
|
|
|
User = "v2ray";
|
|
|
|
Group = "v2ray";
|
|
|
|
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
|
|
|
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
2023-08-14 01:58:33 +08:00
|
|
|
LimitNPROC = 65536;
|
|
|
|
LimitNOFILE = 524288;
|
2023-07-27 20:12:20 +08:00
|
|
|
};
|
2023-07-27 23:40:39 +08:00
|
|
|
restartTriggers = [ inputs.config.sops.templates."xray-client.json".file ];
|
2023-07-27 19:01:58 +08:00
|
|
|
};
|
|
|
|
users = { users.v2ray = { isSystemUser = true; group = "v2ray"; }; groups.v2ray = {}; };
|
|
|
|
environment.etc."resolv.conf".text = "nameserver 127.0.0.1";
|
|
|
|
}
|
|
|
|
)
|
2023-08-10 19:41:33 +08:00
|
|
|
(
|
2023-08-12 01:12:13 +08:00
|
|
|
mkIf services.xrayServer.enable (let userList = genList (n: n) 30; in
|
2023-08-10 19:41:33 +08:00
|
|
|
{
|
|
|
|
services =
|
|
|
|
{
|
|
|
|
xray = { enable = true; settingsFile = inputs.config.sops.templates."xray-server.json".path; };
|
2023-08-12 23:58:18 +08:00
|
|
|
nginx.virtualHosts.xray =
|
2023-08-10 19:41:33 +08:00
|
|
|
{
|
2023-08-12 23:58:18 +08:00
|
|
|
serverName = services.xrayServer.serverName;
|
|
|
|
default = true;
|
|
|
|
listen = [{ addr = "127.0.0.1"; port = 7233; ssl = true; }];
|
|
|
|
useACMEHost = services.xrayServer.serverName;
|
2023-08-13 00:17:06 +08:00
|
|
|
onlySSL = true;
|
2023-08-12 23:58:18 +08:00
|
|
|
locations."/".return = "400";
|
2023-08-10 19:41:33 +08:00
|
|
|
};
|
|
|
|
};
|
2023-08-11 13:57:25 +08:00
|
|
|
sops =
|
2023-08-10 19:41:33 +08:00
|
|
|
{
|
|
|
|
templates."xray-server.json" =
|
|
|
|
{
|
2023-08-11 15:30:47 +08:00
|
|
|
owner = inputs.config.users.users.v2ray.name;
|
|
|
|
group = inputs.config.users.users.v2ray.group;
|
2023-08-10 19:41:33 +08:00
|
|
|
content = builtins.toJSON
|
|
|
|
{
|
|
|
|
log.loglevel = "warning";
|
|
|
|
inbounds =
|
|
|
|
[
|
|
|
|
{
|
|
|
|
port = 4726;
|
|
|
|
listen = "127.0.0.1";
|
|
|
|
protocol = "vless";
|
|
|
|
settings =
|
|
|
|
{
|
|
|
|
clients = map
|
|
|
|
(n:
|
|
|
|
{
|
|
|
|
id = inputs.config.sops.placeholder."xray-server/clients/user${toString n}";
|
|
|
|
flow = "xtls-rprx-vision";
|
|
|
|
email = "${toString n}@xray.chn.moe";
|
|
|
|
})
|
|
|
|
userList;
|
|
|
|
decryption = "none";
|
|
|
|
fallbacks = [{ dest = "127.0.0.1:7233"; }];
|
|
|
|
};
|
|
|
|
streamSettings =
|
|
|
|
{
|
|
|
|
network = "tcp";
|
2023-08-12 23:58:18 +08:00
|
|
|
security = "reality";
|
|
|
|
realitySettings =
|
2023-08-10 19:41:33 +08:00
|
|
|
{
|
2023-08-12 23:58:18 +08:00
|
|
|
dest = "127.0.0.1:7233";
|
|
|
|
serverNames = [ services.xrayServer.serverName ];
|
|
|
|
privateKey = inputs.config.sops.placeholder."xray-server/private-key";
|
2023-08-13 01:35:00 +08:00
|
|
|
minClientVer = "1.8.0";
|
2023-08-12 23:58:18 +08:00
|
|
|
shortIds = [ "" ];
|
2023-08-10 19:41:33 +08:00
|
|
|
};
|
|
|
|
};
|
2023-08-11 00:47:02 +08:00
|
|
|
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; routeOnly = true; };
|
2023-08-10 19:41:33 +08:00
|
|
|
tag = "in";
|
|
|
|
}
|
2023-08-11 00:47:02 +08:00
|
|
|
{
|
|
|
|
port = 4638;
|
|
|
|
listen = "127.0.0.1";
|
|
|
|
protocol = "vless";
|
|
|
|
settings =
|
|
|
|
{
|
2023-08-11 02:34:52 +08:00
|
|
|
clients = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; }];
|
2023-08-11 00:47:02 +08:00
|
|
|
decryption = "none";
|
|
|
|
};
|
|
|
|
streamSettings.network = "tcp";
|
|
|
|
sniffing = { enabled = true; destOverride = [ "http" "tls" "quic" ]; };
|
|
|
|
tag = "in-localdns";
|
|
|
|
}
|
2023-08-11 12:52:20 +08:00
|
|
|
{
|
|
|
|
listen = "127.0.0.1";
|
|
|
|
port = 6149;
|
|
|
|
protocol = "dokodemo-door";
|
|
|
|
settings.address = "127.0.0.1";
|
|
|
|
tag = "api";
|
|
|
|
}
|
2023-08-11 00:47:02 +08:00
|
|
|
];
|
|
|
|
outbounds =
|
|
|
|
[
|
|
|
|
{ protocol = "freedom"; tag = "freedom"; }
|
|
|
|
{
|
|
|
|
protocol = "vless";
|
|
|
|
settings.vnext =
|
|
|
|
[{
|
|
|
|
address = "127.0.0.1";
|
|
|
|
port = 4638;
|
2023-08-11 02:34:52 +08:00
|
|
|
users = [{ id = "be01f0a0-9976-42f5-b9ab-866eba6ed393"; encryption = "none"; }];
|
2023-08-11 00:47:02 +08:00
|
|
|
}];
|
|
|
|
streamSettings.network = "tcp";
|
|
|
|
tag = "loopback-localdns";
|
|
|
|
}
|
2023-08-10 19:41:33 +08:00
|
|
|
];
|
2023-08-11 00:47:02 +08:00
|
|
|
routing =
|
|
|
|
{
|
|
|
|
domainStrategy = "AsIs";
|
|
|
|
rules = builtins.map (rule: rule // { type = "field"; })
|
|
|
|
[
|
|
|
|
{ inboundTag = [ "in" ]; domain = [ "domain:openai.com" ]; outboundTag = "loopback-localdns"; }
|
|
|
|
{ inboundTag = [ "in" ]; outboundTag = "freedom"; }
|
|
|
|
{ inboundTag = [ "in-localdns" ]; outboundTag = "freedom"; }
|
2023-08-11 12:52:20 +08:00
|
|
|
{ inboundTag = [ "api" ]; outboundTag = "api"; }
|
2023-08-11 00:47:02 +08:00
|
|
|
];
|
|
|
|
};
|
2023-08-11 12:52:20 +08:00
|
|
|
stats = {};
|
|
|
|
api = { tag = "api"; services = [ "StatsService" ]; };
|
|
|
|
policy =
|
|
|
|
{
|
|
|
|
levels."0" = { statsUserUplink = true; statsUserDownlink = true; };
|
|
|
|
system =
|
|
|
|
{
|
|
|
|
statsInboundUplink = true;
|
|
|
|
statsInboundDownlink = true;
|
|
|
|
statsOutboundUplink = true;
|
|
|
|
statsOutboundDownlink = true;
|
|
|
|
};
|
|
|
|
};
|
2023-08-10 19:41:33 +08:00
|
|
|
};
|
|
|
|
};
|
2023-08-11 13:57:25 +08:00
|
|
|
secrets = listToAttrs (map (n: { name = "xray-server/clients/user${toString n}"; value = {}; }) userList)
|
2023-08-11 15:30:47 +08:00
|
|
|
// (listToAttrs (map
|
|
|
|
(name:
|
|
|
|
{
|
|
|
|
name = "xray-server/telegram/${name}";
|
|
|
|
value =
|
|
|
|
{
|
|
|
|
owner = inputs.config.users.users.v2ray.name;
|
|
|
|
group = inputs.config.users.users.v2ray.group;
|
|
|
|
};
|
|
|
|
})
|
2023-08-12 23:58:18 +08:00
|
|
|
[ "token" "chat" ]))
|
|
|
|
// { "xray-server/private-key" = {}; };
|
2023-08-10 19:41:33 +08:00
|
|
|
};
|
2023-08-11 13:57:25 +08:00
|
|
|
systemd =
|
2023-08-10 19:41:33 +08:00
|
|
|
{
|
2023-08-11 13:57:25 +08:00
|
|
|
services =
|
2023-08-10 19:41:33 +08:00
|
|
|
{
|
2023-08-11 13:57:25 +08:00
|
|
|
xray =
|
|
|
|
{
|
|
|
|
serviceConfig =
|
|
|
|
{
|
|
|
|
DynamicUser = inputs.lib.mkForce false;
|
|
|
|
User = "v2ray";
|
|
|
|
Group = "v2ray";
|
|
|
|
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
|
|
|
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
2023-08-14 02:30:36 +08:00
|
|
|
LimitNPROC = 65536;
|
|
|
|
LimitNOFILE = 524288;
|
2023-08-11 13:57:25 +08:00
|
|
|
};
|
|
|
|
restartTriggers = [ inputs.config.sops.templates."xray-server.json".file ];
|
|
|
|
};
|
|
|
|
xray-stat =
|
|
|
|
{
|
|
|
|
script =
|
|
|
|
let
|
|
|
|
xray = "${inputs.pkgs.xray}/bin/xray";
|
2023-08-11 15:02:42 +08:00
|
|
|
awk = "${inputs.pkgs.gawk}/bin/awk";
|
2023-08-11 13:57:25 +08:00
|
|
|
curl = "${inputs.pkgs.curl}/bin/curl";
|
2023-08-12 00:58:28 +08:00
|
|
|
jq = "${inputs.pkgs.jq}/bin/jq";
|
|
|
|
sed = "${inputs.pkgs.gnused}/bin/sed";
|
|
|
|
cat = "${inputs.pkgs.coreutils}/bin/cat";
|
2023-08-11 13:57:25 +08:00
|
|
|
token = inputs.config.sops.secrets."xray-server/telegram/token".path;
|
|
|
|
chat = inputs.config.sops.secrets."xray-server/telegram/chat".path;
|
|
|
|
in stripeTabs
|
|
|
|
''
|
|
|
|
message='xray:\n'
|
|
|
|
for i in {0..${toString ((length userList) - 1)}}
|
|
|
|
do
|
2023-08-11 15:16:23 +08:00
|
|
|
upload_bytes=$(${xray} api stats --server=127.0.0.1:6149 \
|
2023-08-12 00:58:28 +08:00
|
|
|
-name "user>>>''${i}@xray.chn.moe>>>traffic>>>uplink" | ${jq} '.stat.value' | ${sed} 's/"//g')
|
2023-08-11 15:16:23 +08:00
|
|
|
[ -z "$upload_bytes" ] && upload_bytes=0
|
|
|
|
download_bytes=$(${xray} api stats --server=127.0.0.1:6149 \
|
2023-08-12 00:58:28 +08:00
|
|
|
-name "user>>>''${i}@xray.chn.moe>>>traffic>>>downlink" | ${jq} '.stat.value' | ${sed} 's/"//g')
|
2023-08-11 15:16:23 +08:00
|
|
|
[ -z "$download_bytes" ] && download_bytes=0
|
|
|
|
traffic_gb=$(echo | ${awk} "{printf \"%.3f\",(''${upload_bytes}+''${download_bytes})/1073741824}")
|
|
|
|
message="$message$i"'\t'"''${traffic_gb}"'G\n'
|
2023-08-11 13:57:25 +08:00
|
|
|
done
|
|
|
|
${curl} -X POST -H 'Content-Type: application/json' \
|
2023-08-12 00:58:28 +08:00
|
|
|
-d "{\"chat_id\": \"$(${cat} ${chat})\", \"text\": \"$message\"}" \
|
|
|
|
https://api.telegram.org/bot$(${cat} ${token})/sendMessage
|
2023-08-11 13:57:25 +08:00
|
|
|
'';
|
|
|
|
serviceConfig = { Type = "oneshot"; User = "v2ray"; Group = "v2ray"; };
|
|
|
|
};
|
|
|
|
};
|
|
|
|
timers.xray-stat =
|
|
|
|
{
|
|
|
|
wantedBy = [ "timers.target" ];
|
|
|
|
timerConfig = { OnCalendar = "*-*-* 0:00:00"; Unit = "xray-stat.service"; };
|
2023-08-10 19:41:33 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
users = { users.v2ray = { isSystemUser = true; group = "v2ray"; }; groups.v2ray = {}; };
|
|
|
|
nixos.services =
|
|
|
|
{
|
|
|
|
acme = { enable = true; certs = [ services.xrayServer.serverName ]; };
|
2023-08-14 13:51:59 +08:00
|
|
|
nginx.transparentProxy.map."${services.xrayServer.serverName}" = 4726;
|
2023-08-10 19:41:33 +08:00
|
|
|
};
|
2023-08-12 23:58:18 +08:00
|
|
|
security.acme.certs.${services.xrayServer.serverName}.group = inputs.config.users.users.nginx.group;
|
2023-08-10 19:41:33 +08:00
|
|
|
}
|
2023-08-11 13:57:25 +08:00
|
|
|
))
|
2023-07-27 19:01:58 +08:00
|
|
|
{ networking.firewall.trustedInterfaces = services.firewall.trustedInterfaces; }
|
2023-08-04 20:07:57 +08:00
|
|
|
(
|
|
|
|
mkIf services.acme.enable
|
|
|
|
{
|
|
|
|
security.acme =
|
|
|
|
{
|
|
|
|
acceptTerms = true;
|
|
|
|
defaults.email = "chn@chn.moe";
|
|
|
|
certs = listToAttrs (map
|
|
|
|
(name:
|
|
|
|
{
|
|
|
|
name = name; value =
|
|
|
|
{
|
2023-08-14 14:36:21 +08:00
|
|
|
dnsResolver = "8.8.8.8";
|
2023-08-04 20:07:57 +08:00
|
|
|
dnsProvider = "cloudflare";
|
|
|
|
credentialsFile = inputs.config.sops.secrets."acme/cloudflare.ini".path;
|
|
|
|
};
|
|
|
|
})
|
|
|
|
services.acme.certs);
|
|
|
|
};
|
|
|
|
sops.secrets."acme/cloudflare.ini" = {};
|
|
|
|
}
|
|
|
|
)
|
2023-08-07 21:16:49 +08:00
|
|
|
(
|
|
|
|
mkIf (services.frpClient.enable)
|
|
|
|
{
|
|
|
|
systemd.services.frpc =
|
|
|
|
let
|
|
|
|
frpc = "${inputs.pkgs.frp}/bin/frpc";
|
|
|
|
config = inputs.config.sops.templates."frpc.ini";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
description = "Frp Client Service";
|
|
|
|
after = [ "network.target" ];
|
|
|
|
serviceConfig =
|
|
|
|
{
|
|
|
|
Type = "simple";
|
|
|
|
User = "frp";
|
2023-08-08 22:52:38 +08:00
|
|
|
Restart = "always";
|
2023-08-07 21:16:49 +08:00
|
|
|
RestartSec = "5s";
|
|
|
|
ExecStart = "${frpc} -c ${config.path}";
|
|
|
|
LimitNOFILE = 1048576;
|
|
|
|
};
|
|
|
|
wantedBy= [ "multi-user.target" ];
|
|
|
|
restartTriggers = [ config.file ];
|
|
|
|
};
|
|
|
|
sops =
|
|
|
|
{
|
|
|
|
templates."frpc.ini" =
|
|
|
|
{
|
2023-08-11 15:30:47 +08:00
|
|
|
owner = inputs.config.users.users.frp.name;
|
|
|
|
group = inputs.config.users.users.frp.group;
|
2023-08-07 21:16:49 +08:00
|
|
|
content = inputs.lib.generators.toINI {}
|
|
|
|
(
|
|
|
|
{
|
|
|
|
common =
|
|
|
|
{
|
|
|
|
server_addr = services.frpClient.serverName;
|
|
|
|
server_port = 7000;
|
|
|
|
token = inputs.config.sops.placeholder."frp/token";
|
|
|
|
user = services.frpClient.user;
|
|
|
|
tls_enable = true;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
// (listToAttrs (map
|
|
|
|
(tcp:
|
|
|
|
{
|
|
|
|
name = tcp.name;
|
|
|
|
value =
|
|
|
|
{
|
|
|
|
type = "tcp";
|
|
|
|
local_ip = tcp.value.localIp;
|
|
|
|
local_port = tcp.value.localPort;
|
|
|
|
remote_port = tcp.value.remotePort;
|
|
|
|
use_compression = true;
|
|
|
|
};
|
|
|
|
})
|
|
|
|
(attrsToList services.frpClient.tcp))
|
|
|
|
)
|
|
|
|
);
|
|
|
|
};
|
|
|
|
secrets."frp/token" = {};
|
|
|
|
};
|
|
|
|
users = { users.frp = { isSystemUser = true; group = "frp"; }; groups.frp = {}; };
|
|
|
|
}
|
|
|
|
)
|
|
|
|
(
|
|
|
|
mkIf (services.frpServer.enable)
|
|
|
|
{
|
|
|
|
systemd.services.frps =
|
|
|
|
let
|
|
|
|
frps = "${inputs.pkgs.frp}/bin/frps";
|
|
|
|
config = inputs.config.sops.templates."frps.ini";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
description = "Frp Server Service";
|
|
|
|
after = [ "network.target" ];
|
|
|
|
serviceConfig =
|
|
|
|
{
|
|
|
|
Type = "simple";
|
|
|
|
User = "frp";
|
|
|
|
Restart = "on-failure";
|
|
|
|
RestartSec = "5s";
|
|
|
|
ExecStart = "${frps} -c ${config.path}";
|
|
|
|
LimitNOFILE = 1048576;
|
|
|
|
};
|
|
|
|
wantedBy= [ "multi-user.target" ];
|
|
|
|
restartTriggers = [ config.file ];
|
|
|
|
};
|
|
|
|
sops =
|
|
|
|
{
|
|
|
|
templates."frps.ini" =
|
|
|
|
{
|
2023-08-11 15:30:47 +08:00
|
|
|
owner = inputs.config.users.users.frp.name;
|
|
|
|
group = inputs.config.users.users.frp.group;
|
2023-08-07 21:16:49 +08:00
|
|
|
content = inputs.lib.generators.toINI {}
|
|
|
|
{
|
|
|
|
common = let cert = inputs.config.security.acme.certs.${services.frpServer.serverName}.directory; in
|
|
|
|
{
|
|
|
|
bind_port = 7000;
|
|
|
|
bind_udp_port = 7000;
|
|
|
|
token = inputs.config.sops.placeholder."frp/token";
|
2023-08-07 21:30:05 +08:00
|
|
|
tls_cert_file = "${cert}/full.pem";
|
|
|
|
tls_key_file = "${cert}/key.pem";
|
2023-08-07 21:16:49 +08:00
|
|
|
tls_only = true;
|
|
|
|
user_conn_timeout = 30;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
secrets."frp/token" = {};
|
|
|
|
};
|
|
|
|
nixos.services.acme = { enable = true; certs = [ services.frpServer.serverName ]; };
|
|
|
|
security.acme.certs.${services.frpServer.serverName}.group = "frp";
|
|
|
|
users = { users.frp = { isSystemUser = true; group = "frp"; }; groups.frp = {}; };
|
2023-08-07 21:30:05 +08:00
|
|
|
networking.firewall.allowedTCPPorts = [ 7000 ];
|
2023-08-07 21:16:49 +08:00
|
|
|
}
|
|
|
|
)
|
2023-08-07 21:44:46 +08:00
|
|
|
(
|
|
|
|
mkIf services.nix-serve.enable
|
|
|
|
{
|
|
|
|
services.nix-serve =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
openFirewall = true;
|
|
|
|
secretKeyFile = inputs.config.sops.secrets."store/signingKey".path;
|
|
|
|
};
|
|
|
|
sops.secrets."store/signingKey" = {};
|
2023-08-14 21:40:01 +08:00
|
|
|
nixos.services.nginx.httpProxy.${services.nix-serve.hostname}.upstream = "http://127.0.0.1:5000";
|
2023-08-07 21:44:46 +08:00
|
|
|
}
|
|
|
|
)
|
2023-08-10 10:15:21 +08:00
|
|
|
(mkIf services.smartd.enable { services.smartd.enable = true; })
|
2023-08-10 17:50:08 +08:00
|
|
|
(
|
2023-08-14 13:49:17 +08:00
|
|
|
mkIf services.nginx.enable (mkMerge
|
|
|
|
[
|
2023-08-10 17:50:08 +08:00
|
|
|
{
|
2023-08-14 13:49:17 +08:00
|
|
|
services =
|
|
|
|
{
|
|
|
|
nginx =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
eventsConfig = stripeTabs
|
|
|
|
''
|
|
|
|
worker_connections 524288;
|
|
|
|
use epoll;
|
|
|
|
'';
|
|
|
|
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;
|
|
|
|
};
|
2023-08-14 22:21:00 +08:00
|
|
|
addSSL = true;
|
2023-08-14 13:49:17 +08:00
|
|
|
forceSSL = site.value.rewriteHttps;
|
|
|
|
http2 = site.value.http2;
|
|
|
|
};
|
|
|
|
})
|
|
|
|
(attrsToList services.nginx.httpProxy));
|
|
|
|
recommendedZstdSettings = true;
|
|
|
|
recommendedTlsSettings = true;
|
|
|
|
recommendedProxySettings = true;
|
|
|
|
recommendedOptimisation = true;
|
|
|
|
recommendedGzipSettings = true;
|
|
|
|
recommendedBrotliSettings = true;
|
|
|
|
clientMaxBodySize = "0";
|
|
|
|
appendHttpConfig = stripeTabs
|
|
|
|
''
|
|
|
|
geoip2 ${inputs.config.services.geoipupdate.settings.DatabaseDirectory}/GeoLite2-Country.mmdb
|
|
|
|
{
|
|
|
|
$geoip2_data_country_code country iso_code;
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
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.secrets."nginx/maxmind-license".owner = inputs.config.users.users.nginx.name;
|
|
|
|
systemd.services.nginx.serviceConfig =
|
|
|
|
{
|
|
|
|
CapabilityBoundingSet = [ "CAP_NET_ADMIN" ];
|
|
|
|
AmbientCapabilities = [ "CAP_NET_ADMIN" ];
|
|
|
|
LimitNPROC = 65536;
|
|
|
|
LimitNOFILE = 524288;
|
|
|
|
};
|
|
|
|
nixos.services.acme =
|
2023-08-13 02:30:44 +08:00
|
|
|
{
|
|
|
|
enable = true;
|
2023-08-14 13:49:17 +08:00
|
|
|
certs = attrNames services.nginx.httpProxy;
|
|
|
|
};
|
|
|
|
security.acme.certs = listToAttrs (map
|
|
|
|
(cert: { name = cert; value.group = inputs.config.services.nginx.group; })
|
|
|
|
(attrNames services.nginx.httpProxy));
|
|
|
|
}
|
|
|
|
(
|
|
|
|
mkIf services.nginx.transparentProxy.enable
|
|
|
|
{
|
|
|
|
services.nginx.streamConfig = stripeTabs
|
2023-08-13 02:30:44 +08:00
|
|
|
''
|
2023-08-14 00:01:14 +08:00
|
|
|
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';
|
2023-08-13 02:30:44 +08:00
|
|
|
access_log syslog:server=unix:/dev/log stream;
|
|
|
|
map $ssl_preread_server_name $backend
|
|
|
|
{
|
|
|
|
${concatStringsSep "\n" (map
|
2023-08-14 13:49:17 +08:00
|
|
|
(x: '' "${x.name}" 127.0.0.1:${toString x.value};'')
|
2023-08-13 22:43:34 +08:00
|
|
|
(
|
|
|
|
(attrsToList services.nginx.transparentProxy.map)
|
|
|
|
++ (map
|
|
|
|
(site: { name = site.name; value = (if site.value.http2 then 443 else 3065); })
|
|
|
|
(attrsToList services.nginx.httpProxy)
|
|
|
|
)
|
|
|
|
))}
|
2023-08-13 02:30:44 +08:00
|
|
|
default 127.0.0.1:443;
|
|
|
|
}
|
|
|
|
server
|
|
|
|
{
|
|
|
|
listen ${services.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;
|
|
|
|
}
|
|
|
|
'';
|
2023-08-14 13:49:17 +08:00
|
|
|
networking.firewall.allowedTCPPorts = [ 443 ];
|
|
|
|
systemd.services.nginx-proxy =
|
2023-08-14 00:01:14 +08:00
|
|
|
let
|
2023-08-14 13:49:17 +08:00
|
|
|
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"
|
2023-08-10 20:04:32 +08:00
|
|
|
(
|
2023-08-14 13:49:17 +08:00
|
|
|
(
|
|
|
|
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}'')
|
2023-08-14 14:24:39 +08:00
|
|
|
(inputs.lib.unique ((attrValues services.nginx.transparentProxy.map) ++ [ 443 3065 ])))
|
2023-08-14 13:49:17 +08:00
|
|
|
);
|
|
|
|
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
|
2023-08-10 20:04:32 +08:00
|
|
|
{
|
2023-08-14 13:49:17 +08:00
|
|
|
description = "nginx transparent proxy";
|
|
|
|
after = [ "network.target" ];
|
|
|
|
serviceConfig =
|
|
|
|
{
|
|
|
|
Type = "simple";
|
|
|
|
RemainAfterExit = true;
|
|
|
|
ExecStart = start;
|
|
|
|
ExecStop = stop;
|
|
|
|
};
|
|
|
|
wants = [ "network.target" ];
|
|
|
|
wantedBy= [ "multi-user.target" ];
|
2023-08-10 20:04:32 +08:00
|
|
|
};
|
2023-08-14 13:49:17 +08:00
|
|
|
}
|
|
|
|
)
|
|
|
|
])
|
2023-08-12 11:58:01 +08:00
|
|
|
)
|
2023-08-14 17:07:57 +08:00
|
|
|
(
|
|
|
|
mkIf services.postgresql.enable
|
|
|
|
{
|
|
|
|
services.postgresql =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
package = inputs.pkgs.postgresql_15;
|
|
|
|
enableTCPIP = true;
|
2023-08-15 01:29:12 +08:00
|
|
|
authentication = "host all all 0.0.0.0/0 md5";
|
2023-08-14 21:40:01 +08:00
|
|
|
settings =
|
|
|
|
{
|
|
|
|
unix_socket_permissions = "0700";
|
|
|
|
shared_buffers = "2048MB";
|
|
|
|
work_mem = "128MB";
|
|
|
|
};
|
2023-08-14 17:07:57 +08:00
|
|
|
# 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";'
|
2023-08-15 01:10:28 +08:00
|
|
|
# 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
|
2023-08-14 17:07:57 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
)
|
2023-08-14 21:40:01 +08:00
|
|
|
(
|
|
|
|
mkIf services.rsshub.enable
|
|
|
|
{
|
|
|
|
virtualisation.oci-containers.containers.rsshub =
|
|
|
|
{
|
|
|
|
image = "diygod/rsshub:chromium-bundled-2023-08-14";
|
|
|
|
imageFile = inputs.pkgs.dockerTools.pullImage
|
|
|
|
{
|
|
|
|
imageName = "diygod/rsshub";
|
|
|
|
imageDigest = "sha256:16d19f68446f6b8915787d691394dd5a1b1b059dab9a8f219a0d42947dfda5d5";
|
|
|
|
sha256 = "02fsqkbzzwjiwd0j82r8qy4hnhz8gz7w72mblzxarc45s121ynxv";
|
|
|
|
finalImageName = "diygod/rsshub";
|
|
|
|
finalImageTag = "chromium-bundled-2023-08-14";
|
|
|
|
};
|
|
|
|
ports = [ "127.0.0.1:5221:5221/tcp" ];
|
|
|
|
extraOptions = [ "--add-host=host.docker.internal:host-gateway" ];
|
|
|
|
environmentFiles = [ inputs.config.sops.templates."rsshub/env".path ];
|
|
|
|
};
|
|
|
|
sops =
|
|
|
|
{
|
|
|
|
templates."rsshub/env".content =
|
|
|
|
let
|
|
|
|
placeholder = inputs.config.sops.placeholder;
|
|
|
|
in stripeTabs
|
|
|
|
''
|
|
|
|
PORT=5221
|
|
|
|
CACHE_TYPE=redis
|
|
|
|
REDIS_URL=redis://:${placeholder."redis/rsshub"}@host.docker.internal:7116
|
|
|
|
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 = { "redis/rsshub".owner = inputs.config.users.users.redis-rsshub.name; }
|
|
|
|
// (listToAttrs (map (secret: { name = secret; value = {}; })
|
|
|
|
[
|
|
|
|
"rsshub/pixiv-refreshtoken"
|
|
|
|
"rsshub/youtube-key"
|
|
|
|
"rsshub/youtube-client-id"
|
|
|
|
"rsshub/youtube-client-secret"
|
|
|
|
"rsshub/youtube-refresh-token"
|
|
|
|
]));
|
|
|
|
};
|
|
|
|
services.redis.servers.rsshub =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
bind = null;
|
|
|
|
# unixSocket = null; # bug
|
|
|
|
port = 7116;
|
|
|
|
requirePassFile = inputs.config.sops.secrets."redis/rsshub".path;
|
|
|
|
};
|
2023-08-14 23:18:14 +08:00
|
|
|
nixos =
|
|
|
|
{
|
2023-08-15 00:00:48 +08:00
|
|
|
services.nginx = { enable = true; httpProxy."rsshub.chn.moe".upstream = "http://127.0.0.1:5221"; };
|
2023-08-14 23:18:14 +08:00
|
|
|
virtualization.docker.enable = true;
|
|
|
|
};
|
2023-08-14 21:40:01 +08:00
|
|
|
}
|
|
|
|
)
|
2023-08-15 00:53:30 +08:00
|
|
|
(
|
|
|
|
mkIf services.wallabag.enable
|
|
|
|
{
|
|
|
|
virtualisation.oci-containers.containers.wallabag =
|
|
|
|
{
|
|
|
|
image = "wallabag/wallabag:2.6.2";
|
|
|
|
imageFile = inputs.pkgs.dockerTools.pullImage
|
|
|
|
{
|
|
|
|
imageName = "wallabag/wallabag";
|
|
|
|
imageDigest = "sha256:241e5c71f674ee3f383f428e8a10525cbd226d04af58a40ce9363ed47e0f1de9";
|
|
|
|
sha256 = "0zflrhgg502w3np7kqmxij8v44y491ar2qbk7qw981fysia5ix09";
|
|
|
|
finalImageName = "wallabag/wallabag";
|
|
|
|
finalImageTag = "2.6.2";
|
|
|
|
};
|
|
|
|
ports = [ "127.0.0.1:4398:80/tcp" ];
|
|
|
|
extraOptions = [ "--add-host=host.docker.internal:host-gateway" ];
|
|
|
|
environmentFiles = [ inputs.config.sops.templates."wallabag/env".path ];
|
|
|
|
};
|
2023-08-15 15:20:15 +08:00
|
|
|
# systemd.services.docker-wallabag.serviceConfig =
|
|
|
|
# {
|
|
|
|
# User = "wallabag";
|
|
|
|
# Group = "wallabag";
|
|
|
|
# };
|
2023-08-15 00:53:30 +08:00
|
|
|
sops =
|
|
|
|
{
|
|
|
|
templates."wallabag/env".content =
|
|
|
|
let
|
|
|
|
placeholder = inputs.config.sops.placeholder;
|
|
|
|
in stripeTabs
|
|
|
|
''
|
|
|
|
SYMFONY__ENV__DATABASE_DRIVER=pdo_pgsql
|
|
|
|
SYMFONY__ENV__DATABASE_HOST=host.docker.internal
|
|
|
|
SYMFONY__ENV__DATABASE_PORT=5432
|
|
|
|
SYMFONY__ENV__DATABASE_NAME=wallabag
|
|
|
|
SYMFONY__ENV__DATABASE_USER=wallabag
|
2023-08-15 01:10:28 +08:00
|
|
|
SYMFONY__ENV__DATABASE_PASSWORD=${placeholder."postgresql/wallabag"}
|
2023-08-15 00:53:30 +08:00
|
|
|
SYMFONY__ENV__REDIS_HOST=host.docker.internal
|
|
|
|
SYMFONY__ENV__REDIS_PORT=8790
|
|
|
|
SYMFONY__ENV__REDIS_PASSWORD=${placeholder."redis/wallabag"}
|
|
|
|
SYMFONY__ENV__SERVER_NAME=wallabag.chn.moe
|
2023-08-15 16:40:12 +08:00
|
|
|
SYMFONY__ENV__DOMAIN_NAME=https://wallabag.chn.moe
|
2023-08-15 16:26:46 +08:00
|
|
|
SYMFONY__ENV__TWOFACTOR_AUTH=false
|
2023-08-15 00:53:30 +08:00
|
|
|
'';
|
2023-08-15 17:24:08 +08:00
|
|
|
# SYMFONY__ENV__MAILER_DSN=smtp://bot%%40chn.moe@${placeholder."mail/bot-encoded"}:mail.chn.moe
|
|
|
|
# SYMFONY__ENV__FROM_EMAIL=bot@chn.moe
|
|
|
|
# SYMFONY__ENV__TWOFACTOR_SENDER=bot@chn.moe
|
2023-08-15 01:10:28 +08:00
|
|
|
secrets =
|
|
|
|
{
|
|
|
|
"redis/wallabag".owner = inputs.config.users.users.redis-wallabag.name;
|
|
|
|
"postgresql/wallabag" = {};
|
2023-08-15 17:24:08 +08:00
|
|
|
"mail/bot-encoded" = {};
|
2023-08-15 01:10:28 +08:00
|
|
|
};
|
2023-08-15 00:53:30 +08:00
|
|
|
};
|
|
|
|
services =
|
|
|
|
{
|
|
|
|
redis.servers.wallabag =
|
|
|
|
{
|
|
|
|
enable = true;
|
|
|
|
bind = null;
|
|
|
|
port = 8790;
|
|
|
|
requirePassFile = inputs.config.sops.secrets."redis/wallabag".path;
|
|
|
|
};
|
|
|
|
postgresql =
|
|
|
|
{
|
|
|
|
ensureDatabases = [ "wallabag" ];
|
2023-08-15 01:10:28 +08:00
|
|
|
ensureUsers =
|
|
|
|
[{
|
2023-08-15 00:53:30 +08:00
|
|
|
name = "wallabag";
|
|
|
|
ensurePermissions."DATABASE \"wallabag\"" = "ALL PRIVILEGES";
|
2023-08-15 01:10:28 +08:00
|
|
|
}];
|
2023-08-15 02:50:03 +08:00
|
|
|
# ALTER DATABASE db_name OWNER TO new_owner_name
|
|
|
|
# sudo docker exec -t wallabag /var/www/wallabag/bin/console wallabag:install --env=prod --no-interaction
|
2023-08-15 00:53:30 +08:00
|
|
|
};
|
|
|
|
};
|
|
|
|
nixos =
|
|
|
|
{
|
|
|
|
services =
|
|
|
|
{
|
2023-08-15 01:10:28 +08:00
|
|
|
nginx = { enable = true; httpProxy."wallabag.chn.moe".upstream = "http://127.0.0.1:4398"; };
|
2023-08-15 00:53:30 +08:00
|
|
|
postgresql.enable = true;
|
|
|
|
};
|
|
|
|
virtualization.docker.enable = true;
|
|
|
|
};
|
2023-08-15 15:20:15 +08:00
|
|
|
# users =
|
|
|
|
# {
|
|
|
|
# users.wallabag = { isSystemUser = true; group = "wallabag"; autoSubUidGidRange = true; };
|
|
|
|
# groups.wallabag = {};
|
|
|
|
# };
|
2023-08-15 00:53:30 +08:00
|
|
|
}
|
|
|
|
)
|
2023-08-16 19:51:55 +08:00
|
|
|
(
|
|
|
|
mkMerge
|
2023-08-16 20:22:27 +08:00
|
|
|
[
|
2023-08-16 19:51:55 +08:00
|
|
|
{
|
2023-08-16 20:22:27 +08:00
|
|
|
virtualisation.oci-containers.containers = listToAttrs (map
|
|
|
|
(container:
|
2023-08-16 19:51:55 +08:00
|
|
|
{
|
2023-08-16 20:22:27 +08:00
|
|
|
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 services.docker));
|
|
|
|
systemd.services = listToAttrs (concatLists (map
|
|
|
|
(container:
|
|
|
|
[
|
2023-08-16 19:51:55 +08:00
|
|
|
{
|
2023-08-16 20:22:27 +08:00
|
|
|
name = "docker-${container.value.user}-daemon";
|
|
|
|
value =
|
2023-08-16 19:51:55 +08:00
|
|
|
{
|
2023-08-16 20:22:27 +08:00
|
|
|
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; };
|
2023-08-16 19:51:55 +08:00
|
|
|
};
|
2023-08-16 20:22:27 +08:00
|
|
|
}
|
2023-08-16 19:51:55 +08:00
|
|
|
{
|
2023-08-16 20:22:27 +08:00
|
|
|
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 services.docker)));
|
|
|
|
}
|
|
|
|
(mkIf (services.docker != {})
|
|
|
|
{
|
|
|
|
systemd.tmpfiles.rules = [ "d /var/run/docker-rootless 0777" ];
|
|
|
|
nixos.virtualization.docker.enable = true;
|
2023-08-16 19:51:55 +08:00
|
|
|
})
|
2023-08-16 20:22:27 +08:00
|
|
|
]
|
2023-08-16 19:51:55 +08:00
|
|
|
)
|
2023-07-26 21:05:46 +08:00
|
|
|
];
|
2023-07-25 23:33:37 +08:00
|
|
|
}
|