modules.services.nginx.transparentProxy: cleanup

This commit is contained in:
2025-07-06 17:48:05 +08:00
parent e0a113747b
commit 694cc41bf7

View File

@@ -1,111 +1,99 @@
inputs:
{
options.nixos.services.nginx = let inherit (inputs.lib) mkOption types; in
options.nixos.services.nginx.transparentProxy = let inherit (inputs.lib) mkOption types; in
{
transparentProxy =
# only disable in some rare cases
enable = mkOption { type = types.bool; default = true; };
externalIp = mkOption { type = types.listOf types.nonEmptyStr; default = [ "0.0.0.0" ]; };
# proxy to 127.0.0.1:${specified port}
map = mkOption
{
# only disable in some rare cases
enable = mkOption { type = types.bool; default = true; };
externalIp = mkOption { type = types.listOf types.nonEmptyStr; default = [ "0.0.0.0" ]; };
# proxy to 127.0.0.1:${specified port}
map = mkOption
{
type = types.attrsOf (types.oneOf
[
# proxy to 127.0.0.1:${specified port}
types.ints.unsigned
# proxy to specified ip:port
types.nonEmptyStr
]);
default = {};
};
type = types.attrsOf (types.oneOf
[
# proxy to 127.0.0.1:${specified port}
types.ints.unsigned
# proxy to specified ip:port
types.nonEmptyStr
]);
default = {};
};
};
config =
let
inherit (inputs.localLib) attrsToList;
inherit (inputs.config.nixos.services) nginx;
inherit (builtins) map listToAttrs concatStringsSep toString filter attrValues concatLists;
concatAttrs = list: listToAttrs (concatLists (map (attrs: attrsToList attrs) list));
in inputs.lib.mkIf nginx.enable (inputs.lib.mkMerge
[
(inputs.lib.mkIf nginx.transparentProxy.enable
config = let inherit (inputs.config.nixos.services) nginx; in
inputs.lib.mkIf (nginx.enable && nginx.transparentProxy.enable)
{
services.nginx.streamConfig =
''
log_format transparent_proxy '[$time_local] $remote_addr-$geoip2_data_country_code '
'"$ssl_preread_server_name"->$transparent_proxy_backend $bytes_sent $bytes_received';
map $ssl_preread_server_name $transparent_proxy_backend {
${builtins.concatStringsSep "\n " (inputs.lib.mapAttrsToList
(n: v: ''"${n}" ${if builtins.isInt v then "127.0.0.1:${builtins.toString v}" else v};'')
nginx.transparentProxy.map)}
default 127.0.0.1:${toString (with nginx.global; (httpsPort + httpsPortShift.http2))};
}
server {
${builtins.concatStringsSep "\n " (builtins.map (ip: "listen ${ip}:443;")
nginx.transparentProxy.externalIp)}
ssl_preread on;
proxy_bind $remote_addr transparent;
proxy_pass $transparent_proxy_backend;
proxy_connect_timeout 1s;
proxy_socket_keepalive on;
proxy_buffer_size 128k;
access_log syslog:server=unix:/dev/log transparent_proxy;
}
'';
# TODO: use existing options
systemd.services.nginx-proxy =
let
ip = "${inputs.pkgs.iproute2}/bin/ip";
start = inputs.pkgs.writeShellScript "nginx-proxy.start"
''
${ip} rule add fwmark 2/2 table 200
${ip} route add local 0.0.0.0/0 dev lo table 200
'';
stop = inputs.pkgs.writeShellScript "nginx-proxy.stop"
''
${ip} rule del fwmark 2/2 table 200
${ip} route del local 0.0.0.0/0 dev lo table 200
'';
in
{
description = "nginx transparent proxy";
after = [ "network.target" ];
serviceConfig =
{
Type = "oneshot";
RemainAfterExit = true;
ExecStart = start;
ExecStop = stop;
};
wants = [ "network.target" ];
wantedBy= [ "multi-user.target" ];
};
networking.nftables.tables.nginx =
{
services.nginx.streamConfig =
family = "inet";
content =
''
log_format transparent_proxy '[$time_local] $remote_addr-$geoip2_data_country_code '
'"$ssl_preread_server_name"->$transparent_proxy_backend $bytes_sent $bytes_received';
map $ssl_preread_server_name $transparent_proxy_backend {
${concatStringsSep "\n " (builtins.map
(x:
let upstrem = if builtins.isInt x.value then "127.0.0.1:${builtins.toString x.value}" else x.value;
in ''"${x.name}" ${upstrem};'')
(attrsToList nginx.transparentProxy.map))}
default 127.0.0.1:${toString (with nginx.global; (httpsPort + httpsPortShift.http2))};
chain output {
type route hook output priority mangle; policy accept;
# gid nginx
#
meta skgid ${builtins.toString inputs.config.users.groups.nginx.gid} fib saddr type != local \
ct state new counter ct mark set ct mark | 2 return
#
#
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
return
}
server {
${concatStringsSep "\n " (map (ip: "listen ${ip}:443;") nginx.transparentProxy.externalIp)}
ssl_preread on;
proxy_bind $remote_addr transparent;
proxy_pass $transparent_proxy_backend;
proxy_connect_timeout 1s;
proxy_socket_keepalive on;
proxy_buffer_size 128k;
access_log syslog:server=unix:/dev/log transparent_proxy;
# prerouting
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
return
}
'';
# TODO: use existing options
systemd.services.nginx-proxy =
let
ip = "${inputs.pkgs.iproute2}/bin/ip";
start = inputs.pkgs.writeShellScript "nginx-proxy.start"
''
${ip} rule add fwmark 2/2 table 200
${ip} route add local 0.0.0.0/0 dev lo table 200
'';
stop = inputs.pkgs.writeShellScript "nginx-proxy.stop"
''
${ip} rule del fwmark 2/2 table 200
${ip} route del local 0.0.0.0/0 dev lo table 200
'';
in
{
description = "nginx transparent proxy";
after = [ "network.target" ];
serviceConfig =
{
Type = "oneshot";
RemainAfterExit = true;
ExecStart = start;
ExecStop = stop;
};
wants = [ "network.target" ];
wantedBy= [ "multi-user.target" ];
};
networking.nftables.tables.nginx =
{
family = "inet";
content =
''
chain output {
type route hook output priority mangle; policy accept;
# gid nginx
#
meta skgid ${builtins.toString inputs.config.users.groups.nginx.gid} fib saddr type != local \
ct state new counter ct mark set ct mark | 2 return
#
#
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
return
}
# prerouting
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ct mark & 2 == 2 ct direction reply counter meta mark set meta mark | 2 return
return
}
'';
};
})
]);
};
};
}