Commit e2a586a
Changed files (22)
.secrets
cache
hyacine
kevin
modules
hosts
services
direct-dns
mihomo
.secrets/cache/hyacine/23b574ec5c5064908ea2bdb8c99bcce46094933cc0690a84e369a09027135ef6
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 diaafw ylUbkqPM7WrNZ8oZlNcwRw5HquVV8C38vpXzzFBOEEk
+3CrcjoTTvL1u58XAIYnhvzP1UqRWkmqBn9S/fuw6dqg
+-> J-grease
+3P4UdACi4XQdX98
+--- S5KEZjOwcn2GF5Ct5HtvCCWPG6kvMqjYdl1V1pfppj0
+��H�(�������J[��lu×�Cz3�w�&h@ȿw��W��E5�|\�i���(s:
����Ĺ9����
\ No newline at end of file
.secrets/cache/hyacine/c1f79e3dc3b16a58a93265681333e2188971d6add779082c0a536868ac1b471e
Binary file
.secrets/cache/hyacine/cfee81e34551a6f48db8023780a2ae1fd06fb0683e0ad303f06c8821c9878bee
@@ -0,0 +1,9 @@
+age-encryption.org/v1
+-> ssh-ed25519 diaafw 1CrplH6pGtg3e3rZZ/65eUrt4aAnfCsRNcbbB3J1CQo
+SWgoSLKCQxPwZv6Q6hsZYUvnAuC4U6hkFNc3tCnhl4I
+-> #PeT,-grease 6v/6P1 P ZLWS#qy jQjo'HfJ
+ciuZeNMWoExP4m6GX0zVcTvTRGluqKtNzo0rxkU0HSXzo/vkSCjzNJJ6/e4ZDlRc
+Rju5bJc
+--- u4efXM0qsu19E20Pzqw+dTva8V7vJ8uBczZbE5jGHcg
+��^%i��w�ʛ鎼��(g
+��������S�!k�L�����
\ No newline at end of file
.secrets/cache/kevin/6cfa3578e01638f1c8ce9729e6db68ab155162f46672ed972d27960870a131af
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> ssh-ed25519 WM7kiQ Wlc/u+8hS9OXIJSGPj8/ldBi7iqTOMn7CpbvGDxiwjE
+G5G0c7YQOKAPFxjYEFL00lp+A+3+misHNKCMcguvC1k
+-> zS-grease " tUc
+Jvh8UOJJBMfoiRn4oVCXHntxVS/T94L70O0GV/mvjxW4VQ
+--- AO+kEtuKF1x3lWaSzq+HA2kkKQy5M6FsDe2OvbPgbKg
+�zQo�����t�\��4Ȗ �P�.�.�p���g�ğ�r�>Y�kV/���0�`�p`
+���(`r%��
\ No newline at end of file
.secrets/cache/kevin/94ab301970e7a4c4159d081863efb003040031ec46b413e6219fa9223f17d7f4
Binary file
.secrets/cache/kevin/cbe6bb4ca091e1e324e95593330f59278156212abf2c74f4303daeecb4ae5a50
@@ -0,0 +1,9 @@
+age-encryption.org/v1
+-> ssh-ed25519 WM7kiQ UBEj2NuJzbisSKRbImnhZv7ihiDU1QvEzw05HiWCbRw
+Nq2Y8D3JQ5fnNCF+CFAegCTSkYmuIYA6wqz32mWwAb8
+-> y/E{D-grease jy2Wr~ v'/.9p cgi,<T5
+SiLj6u61soeHfHWPBCgFf2JV0080ap1Sw4ZLzWJhNJi6vWqZalepBGKAT5mFAodN
+HG88UOSc1S+7eJIh1iYXLlKg4u5VHL0zWSj2i6i9sdzuCGNJHw
+--- coGd/U1ekfCFGbmjyiPNfjlWwPaaQlKx9x1Akmk9/CI
+��f>\z����.�E}M���o
+�}�Ѯ�/�*�#��c/���
\ No newline at end of file
.secrets/cache/tribios/16a9fb3d720054c9fd42780aa0439bd5cc7ea034afcf8c5322884977a9cdb648
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> ssh-ed25519 1YGZAA 5x8Is7qlT8S10Q4E50Hp6iZOOakmS03RqM/XWEOoMRk
+u+ciBmMYyq+A4NRqG9gI3HS7MCC47iwArYP/U7/S2bM
+-> A&Yc&-grease BIB Y67B)?Z) j5 (N
+/pjZKloAWrq96VyapUr4hmArqqGrzo6egGQyzf8
+--- z5OFpysoNWbVI3om5DM997XW6CEwnaZeYxFWTC5GEpo
+d�e�*͂(Gx �'���>��=A]{��?-��Uq�#�
\ No newline at end of file
.secrets/cache/tribios/c1c305dbe1b886e2ae8b65b5d54f43a7f3692f83b8f6f0e5c48adcfff7882d15
Binary file
.secrets/cache/tribios/d5c9fd66af4de3dbda0e7b12f370c008b892cf4b6984f3ae18d866aeadd75251
Binary file
modules/hosts/hyacine/services/default.nix
@@ -5,6 +5,14 @@
domain = "derp-hyacine.trin.one";
port = 8010;
};
+
+ services.xray = {
+ realitySiteFileAged = ./xray-reality-site.age;
+ port = 7890;
+ uuidFileAged = ./xray-uuid.age;
+ privateKeyFileAged = ./xray-private-key.age;
+ pubKeyFileAged = ./xray-pub-key.age;
+ };
};
};
@@ -12,5 +20,8 @@
services.caddy
services.tailscale-derp
+
+ services.caddy.reality
+ services.xray
];
}
modules/hosts/hyacine/services/xray-private-key.age
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> piv-p256 xCEwtQ AlTB9Zft07Z5nVbPZ7Z6PJS0ZqzG86F0Pvm65THv1s9g
+IapezFo5boewoC8b8Z4pz19m4yFN6cctvszmWDwcpc0
+-> OA"-grease ,C
+HnUnUCUeJTv0tKXM
+--- WoYQ+3oOwrKQ9ic6CzXkdyOf/CgzWipeeyd95iGKREw
+����&Ø�������"�Qx�eݪ<�a�F���C%�8qK�%a� T����2�&\ta���?ݴ�I�?�U DJ�MA�
\ No newline at end of file
modules/hosts/hyacine/services/xray-pub-key.age
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> piv-p256 xCEwtQ Ak/a7dzv2fbDmrywFPMNCWIgNy7MdA2C9KRFLbfICKBU
+cwxGJ0HR477HNVilPSVVK+nFqywPiiH9j6zDtykt+HM
+-> $R.-grease
+4XD3FyTa2LE8Bg
+--- r0zvDBbbC5cH8bh0S/qLuGYRoHSiZWUuBBoh/Vg9GOU
+�dXJ*�
4&�#guF�K��}���(zb��u�8�FϤ�V7�ܱ!f��k?�4��D���V6�Ǒ��ra�=�lWbFo�
\ No newline at end of file
modules/hosts/hyacine/services/xray-reality-site.age
@@ -0,0 +1,7 @@
+age-encryption.org/v1
+-> piv-p256 xCEwtQ AveEZ9Rk1s218t8QXZUJtgJO3dt89Pox5ZmwnINjO2kJ
+Bfx1zFy5GST7j+Q+N7T8QxcD8KXwCbEsqZb+HR+z2kA
+-> oL-grease
+pQse5EsijGKlZ+lxEABvbAonr5TIR3H+t5VSD6VkplsxGO0MKjdTAAL/cSljYw
+--- ioBb1bIlLetD2f03S0FoVC0GWBW9WlIIfLsvyGkIOsY
+�q�($������\���KΆ�$�8]��tp����h�"CՅ
\ No newline at end of file
modules/hosts/hyacine/services/xray-uuid.age
@@ -0,0 +1,8 @@
+age-encryption.org/v1
+-> piv-p256 xCEwtQ AvAC/bDGO+TuTyc7UtoC0D3eM1/TIC4+a/5DVQITd+pK
+oVDLCW6kj/7DljYWLPXQqHhdQDlSa1nw3CZVUViWe2k
+-> qBeVEk:5-grease m+^goT
+KxxxIX6dV0J9IALWHsgUd7itTxWjCt85bBEidB1PmQYHXAjPGGLnzF5sO1168dnR
+fK6EVv3ZBXse5RWzRROwDjTSJfaDL0tBmNWf73m9VMe1qPXpVw
+--- PgQ5H0O3UUrHxFc0Is9QNDKCKG54wmwP6kASpLpTZ2o
+]m)����C��4�x�TCb'�8yo��)o��b�ؠ��2������E��&�n��g]2�YJ��mJu)q
\ No newline at end of file
modules/services/caddy/default.nix
@@ -21,8 +21,9 @@
package = pkgs.caddy.withPlugins {
plugins = [
"github.com/caddy-dns/cloudflare@v0.2.4"
+ "github.com/mholt/caddy-l4@v0.1.2"
];
- hash = "sha256-7GoH8YLCoPmPExQxoga2FHB58zQDoZVf1BBwkVi0SsQ=";
+ hash = "sha256-6HJkIfqacmsEaubClOVjzPM+7Jy5Z7xHVORzf6+5OxU=";
};
globalConfig = ''
modules/services/caddy/quirks.nix
@@ -16,7 +16,7 @@ in {
path = "/foo/bar" # Path to reverse proxy to
stripPath = false; # Whether to strip path prefix ("/foo/bar")
upstream = "/"; Path to reverse proxy from
- prefer = "direct"; # Connection policy override: null (host default), "cdn", "direct" or "tailscale"
+ prefer = "direct"; # Connection policy override: null (host default), "direct" or "tailscale"
}
'';
modules/services/caddy/reality.nix
@@ -0,0 +1,52 @@
+{
+ den.aspects.services.caddy.reality = {
+ nixos = {
+ host,
+ config,
+ ...
+ }: let
+ xrayCfg = host.settings.services.xray;
+ in {
+ boot.kernel.sysctl = {
+ "net.ipv4.tcp_congestion_control" = "bbr";
+ };
+
+ vaultix.secrets.reality-site.file = xrayCfg.realitySiteFileAged;
+
+ vaultix.templates.caddy-reality = {
+ content = ''
+ :${toString config.services.caddy.httpsPort} {
+ @reality tls sni ${config.vaultix.placeholder.reality-site}
+ route @reality {
+ proxy {
+ upstream 127.0.0.1:${toString xrayCfg.port}
+ }
+ }
+ route {
+ proxy {
+ upstream 127.0.0.1:${toString config.services.caddy.httpsPort}
+ }
+ }
+ }
+ '';
+ owner = config.services.caddy.user;
+ group = config.services.caddy.group;
+ mode = "0400";
+ };
+
+ services.caddy.globalConfig = ''
+ default_bind 127.0.0.1
+ layer4 {
+ :${toString config.services.caddy.httpPort} {
+ route {
+ proxy {
+ upstream 127.0.0.1:${toString config.services.caddy.httpPort}
+ }
+ }
+ }
+ import ${config.vaultix.templates.caddy-reality.path}
+ }
+ '';
+ };
+ };
+}
modules/services/direct-dns/_lib.nix
@@ -26,7 +26,7 @@
mode =
if prefer != null
then prefer
- else host.settings.services.direct-dns.mode or "cdn";
+ else host.settings.services.direct-dns.mode or null;
v4 =
if mode == "direct"
then fromClearOrSecret host.address.ipv4
modules/services/direct-dns/default.nix
@@ -2,14 +2,14 @@
den.aspects.services.direct-dns = {
settings.host = {
mode = lib.mkOption {
- type = lib.types.enum ["cdn" "direct" "tailscale"];
- default = "cdn";
+ type = lib.types.nullOr (lib.types.enum ["direct" "tailscale"]);
+ default = null;
description = ''
Default connection policy for reverse proxy domains served by this host.
- - `cdn`: resolve through public DNS (unchanged).
- - `direct`: resolve to the host's public IP.
- - `tailscale`: resolve to the host's tailscale IP.
+ - `null`: resolve through public DNS (unchanged).
+ - `"direct"`: resolve to the host's public IP.
+ - `"tailscale"`: resolve to the host's tailscale IP.
Individual reverse proxy entries can override this with `prefer`.
'';
modules/services/mihomo/proxies.nix
@@ -1,6 +1,9 @@
-{
+{den, ...}: {
den.aspects.services.mihomo.proxies = {
- nixos = {config, ...}: {
+ nixos = {config, ...}: let
+ allHosts = builtins.concatMap builtins.attrValues (builtins.attrValues den.hosts);
+ hyacine = builtins.head (builtins.filter (h: h.name == "hyacine") allHosts);
+ in {
services.mihomo = {
config = {
proxy-providers = let
@@ -30,6 +33,23 @@
};
};
proxies = [
+ {
+ name = "[Self]HK-Hyacine";
+ type = "vless";
+ server._secret = config.vaultix.secrets.${hyacine.address.ipv4.secret.name}.path;
+ port = 443;
+ uuid._secret = config.vaultix.secrets.hyacine-xray-uuid.path;
+ network = "tcp";
+ udp = true;
+ tls = true;
+ flow = "xtls-rprx-vision";
+ servername._secret = config.vaultix.secrets.hyacine-xray-reality-site.path;
+ client-fingerprint = "chrome";
+ reality-opts = {
+ public-key._secret = config.vaultix.secrets.hyacine-xray-pub-key.path;
+ short-id = "";
+ };
+ }
];
};
};
@@ -45,6 +65,22 @@
owner = "mihomo";
group = "mihomo";
};
+
+ hyacine-xray-uuid = {
+ file = hyacine.settings.services.xray.uuidFileAged;
+ owner = "mihomo";
+ group = "mihomo";
+ };
+ hyacine-xray-pub-key = {
+ file = hyacine.settings.services.xray.pubKeyFileAged;
+ owner = "mihomo";
+ group = "mihomo";
+ };
+ hyacine-xray-reality-site = {
+ file = hyacine.settings.services.xray.realitySiteFileAged;
+ owner = "mihomo";
+ group = "mihomo";
+ };
};
};
};
modules/services/xray/_module.nix
@@ -0,0 +1,114 @@
+{
+ lib,
+ pkgs,
+ config,
+ ...
+}: let
+ utils = pkgs.callPackage "${pkgs.path}/nixos/lib/utils.nix" {};
+
+ cfg = config.services.xray;
+
+ configFormat = pkgs.formats.json {};
+
+ runtimeConfig = "/run/xray/config.json";
+in {
+ disabledModules = ["services/networking/xray.nix"];
+
+ options.services.xray = {
+ enable = lib.mkOption {
+ type = lib.types.bool;
+ default = false;
+ description = ''
+ Whether to run xray server.
+
+ Either `settingsFile` or `settings` must be specified.
+ '';
+ };
+
+ package = lib.mkPackageOption pkgs "xray" {};
+
+ settingsFile = lib.mkOption {
+ type = lib.types.nullOr lib.types.path;
+ default = null;
+ example = "/etc/xray/config.json";
+ description = ''
+ The absolute path to the configuration file.
+
+ Either `settingsFile` or `settings` must be specified.
+
+ See <https://www.v2fly.org/en_US/config/overview.html>.
+ '';
+ };
+
+ settings = lib.mkOption {
+ type = lib.types.nullOr (lib.types.submodule {
+ freeformType = configFormat.type;
+ });
+ default = null;
+ example = {
+ inbounds = [
+ {
+ port = 1080;
+ listen = "127.0.0.1";
+ protocol = "http";
+ }
+ ];
+ outbounds = [
+ {
+ protocol = "freedom";
+ }
+ ];
+ };
+ description = ''
+ The configuration object.
+
+ Either `settingsFile` or `settings` must be specified.
+
+ See <https://www.v2fly.org/en_US/config/overview.html>.
+
+ Options containing secret data should be set to an attribute set
+ containing the attribute `_secret` - a string pointing to a file
+ containing the value the option should be set to.
+
+ Set `quote = true` (default behavior) to quote the content of the
+ secret file as a string, or set `quote = false` to parse the content
+ of the secret file to JSON.
+ '';
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = (cfg.settingsFile == null) != (cfg.settings == null);
+ message = "Either but not both `settingsFile` and `settings` should be specified for xray.";
+ }
+ ];
+
+ systemd.services.xray = {
+ description = "xray Daemon";
+ after = ["network.target"];
+ wantedBy = ["multi-user.target"];
+ serviceConfig = {
+ ExecStart = "${lib.getExe cfg.package} run -config ${runtimeConfig}";
+
+ ExecStartPre = "+${pkgs.writeShellScript "xray-pre-start" ''
+ ${lib.optionalString (cfg.settings != null) (utils.genJqSecretsReplacementSnippet cfg.settings runtimeConfig)}
+ ${lib.optionalString (cfg.settings != null) "chown --reference=/run/xray ${runtimeConfig}"}
+ ${lib.getExe cfg.package} -test -config ${
+ if cfg.settings != null
+ then runtimeConfig
+ else cfg.settingsFile
+ }
+ ''}";
+
+ DynamicUser = true;
+ RuntimeDirectory = "xray";
+ RuntimeDirectoryMode = "0700";
+ CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
+ AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
+ NoNewPrivileges = true;
+ };
+ };
+ };
+}
modules/services/xray/default.nix
@@ -0,0 +1,116 @@
+{lib, ...}: {
+ den.aspects.services.xray = {
+ settings.host = {
+ realitySiteFileAged = lib.mkOption {
+ type = lib.types.path;
+ };
+ port = lib.mkOption {
+ type = lib.types.port;
+ default = 7890;
+ };
+ uuidFileAged = lib.mkOption {
+ type = lib.types.path;
+ };
+ privateKeyFileAged = lib.mkOption {
+ type = lib.types.path;
+ };
+ pubKeyFileAged = lib.mkOption {
+ type = lib.types.path;
+ };
+ };
+
+ nixos = {
+ host,
+ config,
+ ...
+ }: let
+ cfg = host.settings.services.xray;
+ in {
+ imports = [./_module.nix];
+
+ vaultix.secrets = {
+ xray-uuid.file = cfg.uuidFileAged;
+ xray-private-key.file = cfg.privateKeyFileAged;
+ xray-reality-site.file = cfg.realitySiteFileAged;
+ };
+
+ vaultix.templates.xray-reality-target = {
+ content = "${config.vaultix.placeholder.xray-reality-site}:443";
+ owner = "root";
+ group = "root";
+ mode = "0400";
+ };
+
+ services.xray = {
+ enable = true;
+ settings = {
+ log.loglevel = "warning";
+ routing = {
+ rules = [
+ {
+ type = "field";
+ protocol = ["bittorrent"];
+ outboundTag = "block";
+ }
+ {
+ type = "field";
+ ip = ["geoip:private"];
+ outboundTag = "block";
+ }
+ ];
+ };
+ inbounds = [
+ {
+ listen = "127.0.0.1";
+ port = cfg.port;
+ protocol = "vless";
+ sniffing = {
+ enabled = true;
+ destOverride = ["http" "tls" "quic"];
+ };
+ settings = {
+ clients = [
+ {
+ id = {
+ _secret = config.vaultix.secrets.xray-uuid.path;
+ };
+ flow = "xtls-rprx-vision";
+ }
+ ];
+ decryption = "none";
+ };
+ streamSettings = {
+ network = "raw";
+ security = "reality";
+ realitySettings = {
+ target = {
+ _secret = config.vaultix.templates.xray-reality-target.path;
+ };
+ serverNames = [
+ {
+ _secret = config.vaultix.secrets.xray-reality-site.path;
+ }
+ ];
+ privateKey = {
+ _secret = config.vaultix.secrets.xray-private-key.path;
+ };
+ shortIds = [""];
+ };
+ };
+ }
+ ];
+ outbounds = [
+ {
+ tag = "direct";
+ protocol = "freedom";
+ }
+ {
+ tag = "block";
+ protocol = "blackhole";
+ }
+ ];
+ };
+ };
+ };
+ };
+}