From eaccf45596700b4e406c7fd70d098251aa61986c Mon Sep 17 00:00:00 2001 From: kp2pml30 Date: Tue, 17 Feb 2026 19:56:50 +0900 Subject: [PATCH] feat: move to own dns --- flake.lock | 8 +-- flake.nix | 2 +- nix/common.nix | 18 ++++-- nix/hardware/server.nix | 7 +++ nix/server/default.nix | 6 +- nix/server/dns.nix | 58 ++++++++++++++++--- nix/server/firewall.nix | 12 ++++ nix/server/ips.nix | 16 +++++ nix/server/nginx.nix | 22 +++++-- nix/server/ports.nix | 6 ++ nix/server/secrets.nix | 7 ++- nix/server/site.nix | 1 + nix/server/stream.nginx | 6 +- nix/server/xray-reality-client.json | 81 -------------------------- nix/server/xray-reality.json | 90 ----------------------------- 15 files changed, 138 insertions(+), 202 deletions(-) create mode 100644 nix/server/firewall.nix create mode 100644 nix/server/ips.nix delete mode 100644 nix/server/xray-reality-client.json delete mode 100644 nix/server/xray-reality.json diff --git a/flake.lock b/flake.lock index f53a159..ca114c7 100644 --- a/flake.lock +++ b/flake.lock @@ -68,17 +68,17 @@ "systems": "systems" }, "locked": { - "lastModified": 1770489230, - "narHash": "sha256-qFcJSENXS9GtBFLpFiVaY6WTmWqt6BarVHcT4uUSAKc=", + "lastModified": 1770820613, + "narHash": "sha256-I5lMXVML0491AqfSI8DUnw3mhIwCLIfQWwZwrdeRrZY=", "owner": "kp2pml30", "repo": "kp2pml30.github.io", - "rev": "c70b7cc290dc4ca341d791fe952ea5e5e2e36e1b", + "rev": "73cbd5858e7196c236029f86756119806d484612", "type": "github" }, "original": { "owner": "kp2pml30", "repo": "kp2pml30.github.io", - "rev": "c70b7cc290dc4ca341d791fe952ea5e5e2e36e1b", + "rev": "73cbd5858e7196c236029f86756119806d484612", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 4169978..09ea0b3 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ #}; kp2pml30-moe = { - url = "github:kp2pml30/kp2pml30.github.io/c70b7cc290dc4ca341d791fe952ea5e5e2e36e1b"; + url = "github:kp2pml30/kp2pml30.github.io/73cbd5858e7196c236029f86756119806d484612"; inputs.nixpkgs.follows = "nixpkgs"; }; }; diff --git a/nix/common.nix b/nix/common.nix index ad64fec..e633090 100644 --- a/nix/common.nix +++ b/nix/common.nix @@ -1,7 +1,18 @@ { pkgs +, lib , ... }: +let + ips = import ./server/ips.nix; + groupByAttr = attr: lib.foldlAttrs (acc: _: v: + acc // { ${v.${attr}} = (acc.${v.${attr}} or []) ++ [ v.full-address ]; } + ) {} ips.addresses; + groupToLines = lib.mapAttrsToList (ip: domains: "${ip} ${lib.concatStringsSep " " domains}"); +in { + networking.extraHosts = lib.concatStringsSep "\n" ( + groupToLines (groupByAttr "ip") ++ groupToLines (groupByAttr "ipv6") + ); system.stateVersion = "24.05"; users.mutableUsers = false; @@ -20,12 +31,7 @@ environment.TMPDIR = "/var/tmp"; }; - networking = { - firewall = { - enable = true; - allowedTCPPorts = [ 80 443 ]; - }; - }; + networking.firewall.enable = true; nix.settings.experimental-features = [ "nix-command" "flakes" ]; environment.systemPackages = with pkgs; [ diff --git a/nix/hardware/server.nix b/nix/hardware/server.nix index 9f9a79b..739a96a 100644 --- a/nix/hardware/server.nix +++ b/nix/hardware/server.nix @@ -47,10 +47,17 @@ prefixLength = 24; address = "146.103.126.11"; } ]; + interfaces.ens3.ipv6.addresses = [ { + prefixLength = 64; + address = "2a14:1e00:3:44d::1"; + } ]; defaultGateway = "146.103.126.1"; + defaultGateway6 = { address = "fe80::1"; interface = "ens3"; }; nameservers = [ "1.1.1.1" "8.8.8.8" + "2606:4700:4700::1111" + "2001:4860:4860::8888" ]; }; diff --git a/nix/server/default.nix b/nix/server/default.nix index 767eba1..c71d7cc 100644 --- a/nix/server/default.nix +++ b/nix/server/default.nix @@ -40,10 +40,14 @@ in { ./nix-cache.nix ./xray.nix ./secrets.nix + ./firewall.nix ]; config = { - security.pam.enableSSHAgentAuth = true; + users.groups.certreaders = {}; + users.users.nginx.extraGroups = [ "certreaders" ]; + + security.pam.sshAgentAuth.enable = true; users.users."${cfg.username}" = { isNormalUser = true; diff --git a/nix/server/dns.nix b/nix/server/dns.nix index 7f5fe8f..ea8ff1c 100644 --- a/nix/server/dns.nix +++ b/nix/server/dns.nix @@ -11,25 +11,65 @@ let cfg = config.kp2pml30.server; ports = config.kp2pml30.server.ports; + ips = import ./ips.nix; + + hostname = cfg.hostname; + + relName = fullAddr: + let stripped = lib.removeSuffix ".${hostname}" fullAddr; + in if stripped == fullAddr then "@" else stripped; + + domainEntries = lib.mapAttrsToList (_: v: { + name = relName v.full-address; + ip = v.ip; + ipv6 = v.ipv6; + }) ips.addresses; + + zoneRecords = lib.concatMapStringsSep "\n" (e: + "${e.name} IN A ${e.ip}\n" + + "${e.name} IN AAAA ${e.ipv6}\n" + + "${e.name} IN HTTPS 1 . alpn=h2,http/1.1 ipv4hint=${e.ip} ipv6hint=${e.ipv6}" + ) domainEntries; + + zoneFile = pkgs.writeText "${hostname}.zone" '' +$ORIGIN ${hostname}. +$TTL 300 +@ IN SOA dns.${hostname}. admin.${hostname}. ( 1 3600 600 604800 300 ) +@ IN NS dns.${hostname}. +@ IN NS dns2.${hostname}. +www IN CNAME ${hostname}. +${zoneRecords} +''; in lib.mkIf cfg.nginx { + users.users.coredns = { + isSystemUser = true; + group = "coredns"; + extraGroups = [ "certreaders" ]; + }; + users.groups.coredns = {}; + services.coredns.enable = true; services.coredns.config = '' - dns://.:53 { - forward . tls://1.1.1.1 { - tls - tls_servername cloudflare-dns.com - } - cache + ${hostname} { + file ${zoneFile} } - https://.:${toString ports.coredns-https} { - forward . dns://127.0.0.1:53 { - tls + dns://.:53 { + forward . tls://1.1.1.1 tls://1.0.0.1 { tls_servername cloudflare-dns.com policy random } cache } + + tls://.:853 { + tls /var/lib/acme/${hostname}/fullchain.pem /var/lib/acme/${hostname}/key.pem + forward . dns://127.0.0.1:53 + } + + https://.:${toString ports.coredns-https} { + forward . dns://127.0.0.1:53 + } ''; # networking.networkmanager.insertNameservers = [ "127.0.0.1" ]; } diff --git a/nix/server/firewall.nix b/nix/server/firewall.nix new file mode 100644 index 0000000..6253282 --- /dev/null +++ b/nix/server/firewall.nix @@ -0,0 +1,12 @@ +{ ... }: +let + dnsPort = 53; + httpPort = 80; + httpsPort = 443; + dnsOverTlsPort = 853; +in { + networking.firewall = { + allowedTCPPorts = [ dnsPort httpPort httpsPort dnsOverTlsPort ]; + allowedUDPPorts = [ dnsPort ]; + }; +} diff --git a/nix/server/ips.nix b/nix/server/ips.nix new file mode 100644 index 0000000..e086de3 --- /dev/null +++ b/nix/server/ips.nix @@ -0,0 +1,16 @@ +rec { + machines = { + vdsina = "146.103.126.11"; + vdsina-v6 = "2a14:1e00:3:44d::1"; + }; + addresses = { + forgejo = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "git.kp2pml30.moe"; }; + www = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "kp2pml30.moe"; }; + xray = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "x.kp2pml30.moe"; }; + dns = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "dns.kp2pml30.moe"; }; + dns2 = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "dns2.kp2pml30.moe"; }; + signal-proxy = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "pr.kp2pml30.moe"; }; + nix-cache = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "cache.nix.kp2pml30.moe"; }; + backend = { ip = machines.vdsina; ipv6 = machines.vdsina-v6; full-address = "backend.kp2pml30.moe"; }; + }; +} diff --git a/nix/server/nginx.nix b/nix/server/nginx.nix index 0d18f17..cc3ab34 100644 --- a/nix/server/nginx.nix +++ b/nix/server/nginx.nix @@ -6,6 +6,7 @@ let cfg = config.kp2pml30.server; ports = config.kp2pml30.server.ports; + ips = import ./ips.nix; acmeRoot = "/var/lib/acme/acme-challenge"; pref = "kp2"; in lib.mkIf cfg.nginx { @@ -15,9 +16,9 @@ in lib.mkIf cfg.nginx { defaults.email = "kp2pml30@gmail.com"; #defaults.server = "https://acme-staging-v02.api.letsencrypt.org/directory"; certs."${cfg.hostname}" = { - extraDomainNames = [ "pr.${cfg.hostname}" "www.${cfg.hostname}" "git.${cfg.hostname}" "backend.${cfg.hostname}" "dns.${cfg.hostname}" "cache.nix.${cfg.hostname}" "x.${cfg.hostname}" ]; + extraDomainNames = lib.mapAttrsToList (_: v: v.full-address) ips.addresses; webroot = acmeRoot; - group = "nginx"; + group = "certreaders"; }; }; @@ -34,6 +35,7 @@ in lib.mkIf cfg.nginx { listen = [ { addr = "0.0.0.0"; port = 80; } + { addr = "[::]"; port = 80; } ]; locations."/" = { @@ -47,6 +49,7 @@ in lib.mkIf cfg.nginx { listen = [ { addr = "0.0.0.0"; port = 80; } + { addr = "[::]"; port = 80; } ]; locations."/" = { @@ -60,6 +63,7 @@ in lib.mkIf cfg.nginx { listen = [ { addr = "0.0.0.0"; port = 80; } + { addr = "[::]"; port = 80; } ]; locations."/" = { @@ -73,6 +77,7 @@ in lib.mkIf cfg.nginx { listen = [ { addr = "0.0.0.0"; port = 80; } + { addr = "[::]"; port = 80; } ]; locations."/" = { @@ -98,7 +103,7 @@ in lib.mkIf cfg.nginx { proxy_send_timeout 60s; proxy_read_timeout 60s; - resolver 1.1.1.1; + resolver 127.0.0.1; ''; }; }; @@ -112,6 +117,7 @@ in lib.mkIf cfg.nginx { listen = [ { addr = "0.0.0.0"; port = 80; } + { addr = "[::]"; port = 80; } ]; locations."/" = { @@ -149,7 +155,7 @@ in lib.mkIf cfg.nginx { proxy_send_timeout 60s; proxy_read_timeout 60s; - resolver 1.1.1.1; + resolver 127.0.0.1; ''; }; }; @@ -182,7 +188,7 @@ in lib.mkIf cfg.nginx { proxy_send_timeout 60s; proxy_read_timeout 60s; - resolver 1.1.1.1; + resolver 127.0.0.1; ''; }; }; @@ -192,6 +198,7 @@ in lib.mkIf cfg.nginx { acmeRoot = acmeRoot; listen = [ { addr = "0.0.0.0"; port = 80; } + { addr = "[::]"; port = 80; } ]; locations."/" = { proxyPass = "http://${config.services.nix-serve.bindAddress}:${toString config.services.nix-serve.port}"; @@ -199,6 +206,9 @@ in lib.mkIf cfg.nginx { }; } else {}); - streamConfig = (builtins.readFile ./stream.nginx); + streamConfig = builtins.replaceStrings + ["@SIGNAL_PROXY_PORT@"] + ["${toString ports.signal-proxy-port}"] + (builtins.readFile ./stream.nginx); }; } diff --git a/nix/server/ports.nix b/nix/server/ports.nix index 903ac2f..da3eb56 100644 --- a/nix/server/ports.nix +++ b/nix/server/ports.nix @@ -41,5 +41,11 @@ default = 8012; description = "Xray websocket fallback port"; }; + + signal-proxy-port = lib.mkOption { + type = lib.types.int; + default = 8444; + description = "Signal proxy TLS termination port"; + }; }; } \ No newline at end of file diff --git a/nix/server/secrets.nix b/nix/server/secrets.nix index cf9ad4f..b075827 100644 --- a/nix/server/secrets.nix +++ b/nix/server/secrets.nix @@ -26,7 +26,12 @@ let ${pkgs.openssl}/bin/openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k "$KP2_DOTFILES_SECRET_KEY" -in "${./secrets.yaml}" | ${pkgs.yq}/bin/yq '.XRAY_UIDS[]' -r ''; - xray-config-base = builtins.toFile "xray.json" (builtins.readFile ./xray.json); + xray-config-base = builtins.toFile "xray.json" (builtins.toJSON ( + let base = builtins.fromJSON (builtins.readFile ./xray.json); + in base // { + inbounds = map (ib: ib // { port = config.kp2pml30.server.ports.xray-main; }) base.inbounds; + } + )); # Script to generate complete xray configuration generateXrayConfig = pkgs.writeShellScript "generate-xray-config" '' diff --git a/nix/server/site.nix b/nix/server/site.nix index a075874..762bea8 100644 --- a/nix/server/site.nix +++ b/nix/server/site.nix @@ -31,6 +31,7 @@ in lib.mkIf cfg.nginx { systemd.services.kp2pml30-moe-backend-service = { enable = true; + wants = [ "network-online.target" ]; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; diff --git a/nix/server/stream.nginx b/nix/server/stream.nginx index dcdcc95..c03a03c 100644 --- a/nix/server/stream.nginx +++ b/nix/server/stream.nginx @@ -12,7 +12,6 @@ map $ssl_preread_server_name $name { updates.signal.org updates; updates2.signal.org updates2; - www.microsoft.com xray-entrypoint; x.kp2pml30.moe xray-entrypoint; pr.kp2pml30.moe signal-proxy; @@ -86,11 +85,12 @@ upstream ssl-terminator { } upstream signal-proxy { - server 127.0.0.1:8444; + server 127.0.0.1:@SIGNAL_PROXY_PORT@; } server { listen 443; + listen [::]:443; ssl_preread on; proxy_pass $name; } @@ -106,7 +106,7 @@ server { } server { - listen 8444 ssl; + listen @SIGNAL_PROXY_PORT@ ssl; server_name pr.kp2pml30.moe; ssl_preread on; proxy_pass $name; diff --git a/nix/server/xray-reality-client.json b/nix/server/xray-reality-client.json deleted file mode 100644 index 4916a85..0000000 --- a/nix/server/xray-reality-client.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "log": { - "loglevel": "warning" - }, - "inbounds": [ - { - "port": 1080, - "listen": "127.0.0.1", - "protocol": "socks", - "settings": { - "udp": true - } - }, - { - "port": 1081, - "listen": "127.0.0.1", - "protocol": "http" - } - ], - "outbounds": [ - { - "tag": "proxy", - "protocol": "vless", - "settings": { - "vnext": [ - { - "address": "x.kp2pml30.moe", - "port": 443, - "users": [ - { - "id": "YOUR-UUID-HERE", - "encryption": "none", - "flow": "xtls-rprx-vision" - } - ] - } - ] - }, - "streamSettings": { - "network": "tcp", - "security": "reality", - "realitySettings": { - "show": false, - "fingerprint": "chrome", - "serverName": "www.microsoft.com", - "publicKey": "dRvlorHTupOukJ7aFZNPx-wXUMYJt3GQNrtSjMm9lAg", - "shortId": "deadbabe", - "spiderX": "/" - } - } - }, - { - "tag": "direct", - "protocol": "freedom" - }, - { - "tag": "block", - "protocol": "blackhole" - } - ], - "routing": { - "domainStrategy": "AsIs", - "rules": [ - { - "type": "field", - "domain": [ - "regexp:\\.ru$", - "geosite:category-ru", - "regexp:\\.рф$", - "regexp:(^|\\.)vk\\.com$" - ], - "outboundTag": "block" - }, - { - "type": "field", - "network": "tcp,udp", - "outboundTag": "proxy" - } - ] - } -} diff --git a/nix/server/xray-reality.json b/nix/server/xray-reality.json deleted file mode 100644 index 4787277..0000000 --- a/nix/server/xray-reality.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "log": { - "loglevel": "debug" - }, - "routing": { - "domainStrategy": "IPIfNonMatch", - "rules": [ - { - "type": "field", - "domain": [ - "regexp:\\.ru$", - "regexp:\\.рф$", - "domain:vk.com" - ], - "outboundTag": "block" - }, - { - "type": "field", - "ip": [ - "geoip:cn", - "geoip:ru" - ], - "outboundTag": "block" - }, - { - "type": "field", - "network": "tcp,udp", - "outboundTag": "direct" - } - ] - }, - "inbounds": [ - { - "listen": "127.0.0.1", - "port": 8010, - "protocol": "vless", - "settings": { - "clients": [ - { - "id": "YOUR-UUID-HERE", - "flow": "xtls-rprx-vision" - } - ], - "decryption": "none" - }, - "streamSettings": { - "network": "tcp", - "security": "reality", - "realitySettings": { - "show": true, - "dest": "www.microsoft.com:443", - "xver": 0, - "serverNames": [ - "www.microsoft.com" - ], - "privateKey": "", - "shortIds": [ - "deadbabe" - ], - "debug": true - } - }, - "sniffing": { - "enabled": true, - "destOverride": [ - "http", - "tls" - ] - } - } - ], - "outbounds": [ - { - "protocol": "freedom", - "tag": "direct" - }, - { - "protocol": "blackhole", - "tag": "block" - } - ], - "policy": { - "levels": { - "0": { - "handshake": 3, - "connIdle": 127 - } - } - } -}