nixfiles/services/shadowsocks-rust.nix

88 lines
3.1 KiB
Nix
Executable file

# Based on https://github.com/NixOS/nixpkgs/blob/nixos-23.05/nixos/modules/services/networking/shadowsocks.nix
{ lib, pkgs, ... }:
with lib;
{
# Local addresses to which the server binds.
localAddress ? "0.0.0.0"
, # Port which the server uses.
# If `client = true`, port of the remote server to connect to.
port ? 8388
, # Password for connecting clients
password ? null
, # Password file with a password for connecting clients
passwordFile ? null
, # Relay protocols (one of "tcp_only" "tcp_and_udp" "udp_only")
mode ? "tcp_and_udp"
, # use TCP fast-open
fastOpen ? true
, # Encryption method
encryptionMethod ? "chacha20-ietf-poly1305"
, # SIP003 plugin for shadowsocks
plugin ? null
, # Options to pass to the plugin if one was specified (e.g. "server;host=example.com")
pluginOpts ? ""
, # Whether to set up a Shadowsocks client instead of a server
client ? false
, # Address of the remote Shadowsocks server
server ? null
, # File containing address of the remote Shadowsocks server
serverFile ? null
, # Local port for the client to bind
localPort ? 8388
, # Additional configuration for shadowsocks that is not covered by the
# provided options. The provided attrset will be serialized to JSON config as-is
extraConfig ? { }
, # Name of the systemd service
serviceName ? "shadowsocks-rust"
, # Shadowsocks-rust package
package ? pkgs.shadowsocks-rust
}:
assert assertOneOf "mode" mode [ "tcp_only" "tcp_and_udp" "udp_only" ];
assert assertMsg (password == null || passwordFile == null) "Cannot use both password and passwordFile for shadowsocks-rust";
assert assertMsg (server == null || serverFile == null) "Cannot use both server and serverFile for shadowsocks-rust";
let
opts = {
server = localAddress;
server_port = port;
method = encryptionMethod;
mode = mode;
user = "nobody";
fast_open = fastOpen;
} // optionalAttrs (plugin != null) {
plugin = plugin;
plugin_opts = pluginOpts;
} // optionalAttrs (password != null) {
password = password;
} // optionalAttrs (client == true) {
server = server;
local_address = localAddress;
local_port = localPort;
} // extraConfig;
configFile = pkgs.writeText "shadowsocks.json" (builtins.toJSON opts);
in
{
systemd.services.${serviceName} = {
description = "${serviceName} Daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
path = [ package ] ++ optional (plugin != null) plugin ++ optional (passwordFile != null) pkgs.jq;
serviceConfig = {
PrivateTmp = true;
Restart = "on-failure";
};
script = ''
cp ${configFile} /tmp/shadowsocks.json
${optionalString (passwordFile != null) ''
cat /tmp/shadowsocks.json | jq --arg password "$(cat "${passwordFile}")" '. + { password: $password }' > /tmp/shadowsocks.json
''}
${optionalString (serverFile != null) ''
cat /tmp/shadowsocks.json | jq --arg server "$(cat "${serverFile}")" '. + { server: $server }' > /tmp/shadowsocks.json
''}
exec ${if client == true then "sslocal" else "ssserver"} -c /tmp/shadowsocks.json
'';
};
}