1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8with lib;
9
10let
11 json = pkgs.formats.json { };
12in
13{
14 options = {
15
16 services.v2ray = {
17 enable = mkOption {
18 type = types.bool;
19 default = false;
20 description = ''
21 Whether to run v2ray server.
22
23 Either `configFile` or `config` must be specified.
24 '';
25 };
26
27 package = mkPackageOption pkgs "v2ray" { };
28
29 configFile = mkOption {
30 type = types.nullOr types.str;
31 default = null;
32 example = "/etc/v2ray/config.json";
33 description = ''
34 The absolute path to the configuration file.
35
36 Either `configFile` or `config` must be specified.
37
38 See <https://www.v2fly.org/en_US/v5/config/overview.html>.
39 '';
40 };
41
42 config = mkOption {
43 type = types.nullOr json.type;
44 default = null;
45 example = {
46 inbounds = [
47 {
48 port = 1080;
49 listen = "127.0.0.1";
50 protocol = "http";
51 }
52 ];
53 outbounds = [
54 {
55 protocol = "freedom";
56 }
57 ];
58 };
59 description = ''
60 The configuration object.
61
62 Either `configFile` or `config` must be specified.
63
64 See <https://www.v2fly.org/en_US/v5/config/overview.html>.
65 '';
66 };
67 };
68
69 };
70
71 config =
72 let
73 cfg = config.services.v2ray;
74 configFile =
75 if cfg.configFile != null then
76 cfg.configFile
77 else
78 pkgs.writeTextFile {
79 name = "v2ray.json";
80 text = builtins.toJSON cfg.config;
81 checkPhase = ''
82 ${cfg.package}/bin/v2ray test -c $out
83 '';
84 };
85
86 in
87 mkIf cfg.enable {
88 assertions = [
89 {
90 assertion = (cfg.configFile == null) != (cfg.config == null);
91 message = "Either but not both `configFile` and `config` should be specified for v2ray.";
92 }
93 ];
94
95 environment.etc."v2ray/config.json".source = configFile;
96
97 systemd.packages = [ cfg.package ];
98
99 systemd.services.v2ray = {
100 restartTriggers = [ config.environment.etc."v2ray/config.json".source ];
101
102 # Workaround: https://github.com/NixOS/nixpkgs/issues/81138
103 wantedBy = [ "multi-user.target" ];
104 };
105 };
106}