diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
index d10ee8f8c203..ad2b74dfe81e 100644
--- a/maintainers/maintainer-list.nix
+++ b/maintainers/maintainer-list.nix
@@ -6121,6 +6121,16 @@
githubId = 307899;
name = "Gurkan Gur";
};
+ servalcatty = {
+ email = "servalcat@pm.me";
+ github = "servalcatty";
+ githubid = 51969817;
+ name = "Serval";
+ keys = [{
+ longkeyid = "rsa4096/0x4A2AAAA382F8294C";
+ fingerprint = "A317 37B3 693C 921B 480C C629 4A2A AAA3 82F8 294C";
+ }];
+ };
sfrijters = {
email = "sfrijters@gmail.com";
github = "sfrijters";
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 076e1654818a..8e373550bb30 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -722,6 +722,7 @@
./services/networking/tvheadend.nix
./services/networking/unbound.nix
./services/networking/unifi.nix
+ ./services/networking/v2ray.nix
./services/networking/vsftpd.nix
./services/networking/wakeonlan.nix
./services/networking/websockify.nix
diff --git a/nixos/modules/services/networking/v2ray.nix b/nixos/modules/services/networking/v2ray.nix
new file mode 100644
index 000000000000..a1774cdffbb9
--- /dev/null
+++ b/nixos/modules/services/networking/v2ray.nix
@@ -0,0 +1,81 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+{
+ options = {
+
+ services.v2ray = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Whether to run v2ray server.
+
+ Either configFile or config must be specified.
+ '';
+ };
+
+ configFile = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "/etc/v2ray/config.json";
+ description = ''
+ The absolute path to the configuration file.
+
+ Either configFile or config must be specified.
+
+ See .
+ '';
+ };
+
+ config = mkOption {
+ type = types.nullOr (types.attrsOf types.unspecified);
+ default = null;
+ example = {
+ inbounds = [{
+ port = 1080;
+ listen = "127.0.0.1";
+ protocol = "http";
+ }];
+ outbounds = [{
+ protocol = "freedom";
+ }];
+ };
+ description = ''
+ The configuration object.
+
+ Either `configFile` or `config` must be specified.
+
+ See .
+ '';
+ };
+ };
+
+ };
+
+ config = let
+ cfg = config.services.v2ray;
+ configFile = if cfg.configFile != null
+ then cfg.configFile
+ else (pkgs.writeText "v2ray.json" (builtins.toJSON cfg.config));
+
+ in mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = (cfg.configFile == null) != (cfg.config == null);
+ message = "Either but not both `configFile` and `config` should be specified for v2ray.";
+ }
+ ];
+
+ systemd.services.v2ray = {
+ description = "v2ray Daemon";
+ after = [ "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ path = [ pkgs.v2ray ];
+ script = ''
+ exec v2ray -config ${configFile}
+ '';
+ };
+ };
+}
diff --git a/pkgs/tools/networking/v2ray/default.nix b/pkgs/tools/networking/v2ray/default.nix
new file mode 100644
index 000000000000..78f17934a782
--- /dev/null
+++ b/pkgs/tools/networking/v2ray/default.nix
@@ -0,0 +1,36 @@
+{ callPackage, fetchFromGitHub, fetchurl
+, assetOverrides ? {}
+, ... } @ args:
+
+callPackage ./generic.nix (rec {
+ version = "4.21.3";
+
+ src = fetchFromGitHub {
+ owner = "v2ray";
+ repo = "v2ray-core";
+ rev = "v${version}";
+ sha256 = "0z45nrjnalrvpprq7g4zrjbrdkc3d3lhs4ci8hb8m69f92asiwbs";
+ };
+
+ assets = {
+ # MIT licensed
+ "geoip.dat" = let
+ geoipRev = "20190516.1";
+ geoipSha256 = "14h4rq7rlcl1397pwpylfgwpk3fiscpzqb04c4wd5lxkfvk5f02r";
+ in fetchurl {
+ url = "https://github.com/v2ray/geoip/releases/download/${geoipRev}/geoip.dat";
+ sha256 = geoipSha256;
+ };
+
+ # MIT licensed
+ "geosite.dat" = let
+ geositeRev = "20191121.1";
+ geositeSha256 = "0ijmvy43pvm69w38djf114j8swni7wfq5ry9wdpv9dj0rzb59m74";
+ in fetchurl {
+ url = "https://github.com/v2ray/domain-list-community/releases/download/${geositeRev}/dlc.dat";
+ sha256 = geositeSha256;
+ };
+
+ } // assetOverrides;
+
+} // args)
diff --git a/pkgs/tools/networking/v2ray/generic.nix b/pkgs/tools/networking/v2ray/generic.nix
new file mode 100644
index 000000000000..bf6e6cd55ae2
--- /dev/null
+++ b/pkgs/tools/networking/v2ray/generic.nix
@@ -0,0 +1,50 @@
+{ lib, linkFarm, buildGoModule, runCommand, makeWrapper
+
+# Version specific args
+, version, src, assets
+, ... }:
+
+let
+ assetsDrv = linkFarm "v2ray-assets" (lib.mapAttrsToList (name: path: {
+ inherit name path;
+ }) assets);
+
+ core = buildGoModule rec {
+ pname = "v2ray-core";
+ inherit version src;
+
+ modSha256 = "11gsncy3449a7y6w6pr7acqabyj2q2a1q52f8fcl5cdz1vjbmmxi";
+
+ buildPhase = ''
+ runHook preBuild
+
+ go build -o v2ray v2ray.com/core/main
+ go build -o v2ctl v2ray.com/core/infra/control/main
+
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ install -Dm755 v2ray v2ctl -t $out/bin
+ '';
+ };
+
+in runCommand "v2ray-${version}" {
+ inherit version;
+
+ buildInputs = [ assetsDrv core ];
+ nativeBuildInputs = [ makeWrapper ];
+
+ meta = {
+ homepage = "https://www.v2ray.com/en/index.html";
+ description = "A platform for building proxies to bypass network restrictions";
+ license = with lib.licenses; [ mit ];
+ maintainers = with lib.maintainers; [ servalcatty ];
+ };
+
+} ''
+ for file in ${core}/bin/*; do
+ makeWrapper "$file" "$out/bin/$(basename "$file")" \
+ --set-default V2RAY_LOCATION_ASSET ${assetsDrv}
+ done
+''
diff --git a/pkgs/tools/networking/v2ray/update.sh b/pkgs/tools/networking/v2ray/update.sh
new file mode 100755
index 000000000000..38ad77e98f86
--- /dev/null
+++ b/pkgs/tools/networking/v2ray/update.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i bash -p curl jq
+set -eo pipefail
+
+version_nix=$(dirname "$0")/default.nix
+deps_nix=$(dirname "$0")/deps.nix
+
+old_core_rev="v$(sed -En 's/.*\bversion = "(.*?)".*/\1/p' "$version_nix")"
+old_geoip_rev=$(sed -En 's/.*\bgeoipRev = "(.*?)".*/\1/p' "$version_nix")
+old_geosite_rev=$(sed -En 's/.*\bgeositeRev = "(.*?)".*/\1/p' "$version_nix")
+echo "Current version:" >&2
+echo "core: $old_core_rev, geoip: $old_geoip_rev, geosite: $old_geosite_rev" >&2
+
+function fetch_latest_rev {
+ curl "https://api.github.com/repos/v2ray/$1/releases" |
+ jq '.[0].tag_name' --raw-output
+}
+
+core_rev=$(fetch_latest_rev 'v2ray-core')
+geoip_rev=$(fetch_latest_rev 'geoip')
+geosite_rev=$(fetch_latest_rev 'domain-list-community')
+echo "Latest version:" >&2
+echo "core: $core_rev, geoip: $geoip_rev, geosite: $geosite_rev" >&2
+
+if [[ $core_rev != $old_core_rev ]]; then
+ echo "Prefetching core..." >&2
+ { read hash; read store_path; } < <(
+ nix-prefetch-url --unpack --print-path "https://github.com/v2ray/v2ray-core/archive/$core_rev.zip"
+ )
+
+ sed --in-place \
+ -e "s/\bversion = \".*\"/version = \"$(echo "$core_rev" | tail -c+2)\"/" \
+ -e "s/\bsha256 = \".*\"/sha256 = \"$hash\"/" \
+ "$version_nix"
+fi
+
+if [[ $geoip_rev != $old_geoip_rev ]]; then
+ echo "Prefetching geoip..." >&2
+ hash=$(nix-prefetch-url "https://github.com/v2ray/geoip/releases/download/$geoip_rev/geoip.dat")
+ sed --in-place \
+ -e "s/\bgeoipRev = \".*\"/geoipRev = \"$geoip_rev\"/" \
+ -e "s/\bgeoipSha256 = \".*\"/geoipSha256 = \"$hash\"/" \
+ "$version_nix"
+fi
+
+if [[ $geosite_rev != $old_geosite_rev ]]; then
+ echo "Prefetching geosite..." >&2
+ hash=$(nix-prefetch-url "https://github.com/v2ray/domain-list-community/releases/download/$geosite_rev/dlc.dat")
+ sed --in-place \
+ -e "s/\bgeositeRev = \".*\"/geositeRev = \"$geosite_rev\"/" \
+ -e "s/\bgeositeSha256 = \".*\"/geositeSha256 = \"$hash\"/" \
+ "$version_nix"
+fi
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 4e753d061edd..2927119412ce 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -6897,6 +6897,8 @@ in
uwsgi = callPackage ../servers/uwsgi { };
+ v2ray = callPackage ../tools/networking/v2ray { };
+
vacuum = callPackage ../applications/networking/instant-messengers/vacuum {};
vampire = callPackage ../applications/science/logic/vampire {};