diff --git a/.gitignore b/.gitignore index c4a847d..812980f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /result +/.env diff --git a/flake.lock b/flake.lock index 2a3297a..f5cc9bc 100644 --- a/flake.lock +++ b/flake.lock @@ -44,16 +44,16 @@ ] }, "locked": { - "lastModified": 1744117652, - "narHash": "sha256-t7dFCDl4vIOOUMhEZnJF15aAzkpaup9x4ZRGToDFYWI=", + "lastModified": 1758463745, + "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", "owner": "nix-community", "repo": "home-manager", - "rev": "b4e98224ad1336751a2ac7493967a4c9f6d9cb3f", + "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-24.11", + "ref": "release-25.05", "repo": "home-manager", "type": "github" } @@ -158,16 +158,16 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1744309437, - "narHash": "sha256-QZnNHM823am8apCqKSPdtnzPGTy2ZB4zIXOVoBp5+W0=", + "lastModified": 1761999846, + "narHash": "sha256-IYlYnp4O4dzEpL77BD/lj5NnJy2J8qbHkNSFiPBCbqo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f9ebe33a928b5d529c895202263a5ce46bdf12f7", + "rev": "3de8f8d73e35724bf9abef41f1bdbedda1e14a31", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-24.11", + "ref": "nixos-25.05", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 75f9208..d0929d6 100644 --- a/flake.nix +++ b/flake.nix @@ -1,12 +1,12 @@ { inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; nixos-wsl = { url = "github:nix-community/NixOS-WSL/main"; inputs.nixpkgs.follows = "nixpkgs"; }; home-manager = { - url = "github:nix-community/home-manager/release-24.11"; + url = "github:nix-community/home-manager/release-25.05"; inputs.nixpkgs.follows = "nixpkgs"; }; nixos-generators = { @@ -44,6 +44,8 @@ hostname = "kp2pml30.moe"; nginx = true; forgejo = true; + nix-cache = true; + xray = true; }; } @@ -66,7 +68,7 @@ networking.hostName = "kp2pml30-personal-pc"; networking.hostId = "e31a5cc2"; - time.timeZone = "Asia/Yerevan"; + time.timeZone = "Asia/Tokyo"; } ./nix/hardware/mini.nix diff --git a/nix/hardware/mini.nix b/nix/hardware/mini.nix index 4c58a19..e8954bc 100644 --- a/nix/hardware/mini.nix +++ b/nix/hardware/mini.nix @@ -1,4 +1,3 @@ - { pkgs , inputs , lib @@ -6,7 +5,10 @@ , ... }: { - imports = [ ./common.nix ]; + imports = [ + ./common.nix + # ./nvidia.nix + ]; fileSystems."/" = { device = "/dev/disk/by-uuid/1ec7bbd6-cb83-427a-a901-d5fb7a4ef3ba"; @@ -19,15 +21,15 @@ options = [ "fmask=0077" "dmask=0077" ]; }; - fileSystems."/mnt/d" = { - device = "/dev/sda1"; - fsType = "exfat"; - options = [ - "users" - "exec" - "nofail" - ]; - }; +# fileSystems."/mnt/d" = { +# device = "/dev/sda1"; +# fsType = "exfat"; +# options = [ +# "users" +# "exec" +# "nofail" +# ]; +# }; swapDevices = [ { device = "/dev/disk/by-uuid/c68daa9f-f165-4e23-8710-2aab0ad8d282"; } ]; diff --git a/nix/hardware/nvidia.nix b/nix/hardware/nvidia.nix new file mode 100644 index 0000000..bed6b44 --- /dev/null +++ b/nix/hardware/nvidia.nix @@ -0,0 +1,16 @@ +{ pkgs +, inputs +, lib +, config +, ... +}: +{ + services.xserver.videoDrivers = ["nvidia"]; + + hardware.nvidia = { + package = config.boot.kernelPackages.nvidiaPackages.production; + modesetting.enable = true; + open = false; + nvidiaSettings = true; + }; +} diff --git a/nix/personal/default.nix b/nix/personal/default.nix index 8ba9323..0d9afbe 100644 --- a/nix/personal/default.nix +++ b/nix/personal/default.nix @@ -54,6 +54,7 @@ in { "C.UTF-8/UTF-8" "en_US.UTF-8/UTF-8" "ru_RU.UTF-8/UTF-8" + "ja_JP.UTF-8/UTF-8" ]; programs = { @@ -71,6 +72,7 @@ in { nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (pkgs.lib.getName pkg) [ + "anytype-heart" "vscode" "steam" "steam-run" @@ -80,7 +82,7 @@ in { "nvidia-settings" "nvidia-persistenced" "opera" - "discord-ptb" + "discord" "slack" "anytype" ]; diff --git a/nix/personal/graphical/default.nix b/nix/personal/graphical/default.nix index 218f684..cf24440 100644 --- a/nix/personal/graphical/default.nix +++ b/nix/personal/graphical/default.nix @@ -20,11 +20,16 @@ in { environment.systemPackages = [ pkgs.anytype ]; + fonts.enableDefaultFonts = true; fonts.packages = with pkgs; [ + noto-fonts + noto-fonts-cjk-sans + noto-fonts-cjk-sans + fira-code fira-code-nerdfont fira-code-symbols - (nerdfonts.override { fonts = [ "FiraCode" ]; }) + nerd-fonts.fira-code ]; } diff --git a/nix/personal/graphical/messengers.nix b/nix/personal/graphical/messengers.nix index a9ab1ce..e1a2498 100644 --- a/nix/personal/graphical/messengers.nix +++ b/nix/personal/graphical/messengers.nix @@ -7,11 +7,15 @@ }: let cfg = config.kp2pml30; - signalSuffix = if system == "x86_64-linux" then "amd64" else "arm64"; + signal-pkgs = import (builtins.fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/71cbb752aa36854eb4a7deb3685b9789256d643c.tar.gz"; + sha256 = "10dnjv2c28bjgplyj6nbk2q9lng6f95jf75i5yh541zngrr8b2qg"; + }) { + system = pkgs.system; + }; in lib.mkIf cfg.messengers.personal { users.users.${cfg.username}.packages = with pkgs; [ - discord-ptb + discord telegram-desktop - pkgs.signal-desktop - ]; + ] ++ [signal-pkgs.signal-desktop]; } diff --git a/nix/personal/graphical/opera.nix b/nix/personal/graphical/opera.nix index 66d4807..5c3caa9 100644 --- a/nix/personal/graphical/opera.nix +++ b/nix/personal/graphical/opera.nix @@ -6,10 +6,37 @@ }: let cfg = config.kp2pml30; + version = "123.0.5669.23"; + legacy-nixpkgs = import (builtins.fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/refs/tags/24.11.tar.gz"; + sha256 = "1gx0hihb7kcddv5h0k7dysp2xhf1ny0aalxhjbpj2lmvj7h9g80a"; + }) { + system = pkgs.system; + config.allowUnfreePredicate = pkg: + builtins.elem (pkgs.lib.getName pkg) [ + "vscode" + "steam" + "steam-run" + "steam-original" + "steam-unwrapped" + "nvidia-x11" + "nvidia-settings" + "nvidia-persistenced" + "opera" + "discord" + "slack" + "anytype" + ]; + }; in lib.mkIf cfg.opera { home-manager.users.${cfg.username}.home = { - packages = with pkgs; [ - (opera.override { proprietaryCodecs = true; }) + packages = with legacy-nixpkgs; [ + ((opera.override { proprietaryCodecs = true; }).overrideAttrs (finalAttrs: previousAttrs: { + src = fetchurl { + url = "https://get.geo.opera.com/pub/opera/desktop/${version}/linux/opera-stable_${version}_amd64.deb"; + hash = "sha256-j2kHdg8d60S9j3bLychjmH/cRAXHGIjOgGKqmNIhnHU="; + }; + })) ]; }; } diff --git a/nix/personal/graphical/vscode.nix b/nix/personal/graphical/vscode.nix index 7704879..5f28a48 100644 --- a/nix/personal/graphical/vscode.nix +++ b/nix/personal/graphical/vscode.nix @@ -10,30 +10,36 @@ in lib.mkIf cfg.vscode { home-manager.users.${cfg.username} = { programs.vscode = { enable = true; - package = pkgs.vscode; + package = (pkgs.vscode.overrideAttrs (oldAttrs: rec { + src = (builtins.fetchTarball { + url = "https://update.code.visualstudio.com/1.104.1/linux-x64/stable"; + sha256 = "sha256:109mdk1v323dyhzrq0444gjjhfpjxbllkqkhsapfj44ypjzdjcy8"; + }); + version = "1.102.2"; + })); mutableExtensionsDir = false; userSettings = lib.importJSON("${rootPath}/vscode/settings.json"); - extensions = with pkgs; [ - vscode-extensions.eamodio.gitlens - vscode-extensions.editorconfig.editorconfig +# extensions = with pkgs; [ +# vscode-extensions.eamodio.gitlens +# vscode-extensions.editorconfig.editorconfig +# +# vscode-extensions.bierner.markdown-mermaid - vscode-extensions.bierner.markdown-mermaid +# vscode-extensions.tamasfe.even-better-toml - vscode-extensions.tamasfe.even-better-toml - - vscode-extensions.streetsidesoftware.code-spell-checker - (pkgs.vscode-utils.buildVscodeMarketplaceExtension { - mktplcRef = { - name = "code-spell-checker-russian"; - publisher = "streetsidesoftware"; - version = "0.2.2"; - sha256 = "a3b00c76a4aafecb962d6c292a3b9240a27d84b17de2119bb8007d0ad90ab443"; - }; - meta = { - license = lib.licenses.mit; - }; - }) - ]; +# vscode-extensions.streetsidesoftware.code-spell-checker +# (pkgs.vscode-utils.buildVscodeMarketplaceExtension { +# mktplcRef = { +# name = "code-spell-checker-russian"; +# publisher = "streetsidesoftware"; +# version = "0.2.2"; +# sha256 = "a3b00c76a4aafecb962d6c292a3b9240a27d84b17de2119bb8007d0ad90ab443"; +# }; +# meta = { +# license = lib.licenses.mit; +# }; +# }) +# ]; }; }; } diff --git a/nix/personal/neovim.nix b/nix/personal/neovim.nix index 59839f3..027c1e0 100644 --- a/nix/personal/neovim.nix +++ b/nix/personal/neovim.nix @@ -27,7 +27,9 @@ in nerdtree tokyonight-nvim barbar-nvim - feline-nvim + ((fromGitHub "3587f57480b88e8009df7b36dc84e9c7ff8f2c49" "famiu/feline.nvim").overrideAttrs (old: { + doCheck = false; + })) (fromGitHub "d63c811337b2f75de52f16efee176695f31e7fbc" "timakro/vim-yadi") (fromGitHub "aafa5c187a15701a7299a392b907ec15d9a7075f" "nvim-tree/nvim-web-devicons") ]; diff --git a/nix/personal/tui.nix b/nix/personal/tui.nix index 64f0b9a..2dc48d9 100644 --- a/nix/personal/tui.nix +++ b/nix/personal/tui.nix @@ -14,8 +14,9 @@ in { htop.enable = true; }; - environment.systemPackages = with pkgs; [ + environment.systemPackages = with pkgs; [ ncdu + timewarrior ]; }; diff --git a/nix/server/default.nix b/nix/server/default.nix index a3eadd9..767eba1 100644 --- a/nix/server/default.nix +++ b/nix/server/default.nix @@ -20,17 +20,26 @@ in { forgejo = lib.mkEnableOption ""; + dns = lib.mkEnableOption ""; + nix-cache = lib.mkEnableOption ""; + xray = lib.mkEnableOption ""; + sitePath = lib.mkOption { type = lib.types.str; }; }; imports = [ + ./ports.nix ./ssh.nix ./nginx.nix ./boot.nix ./site.nix ./forgejo.nix + ./dns.nix + ./nix-cache.nix + ./xray.nix + ./secrets.nix ]; config = { diff --git a/nix/server/dns.nix b/nix/server/dns.nix new file mode 100644 index 0000000..7f5fe8f --- /dev/null +++ b/nix/server/dns.nix @@ -0,0 +1,35 @@ + +{ config +, pkgs +, lib +, self +, nixpkgs +, kp2pml30-moe +, system +, ... +}@args: +let + cfg = config.kp2pml30.server; + ports = config.kp2pml30.server.ports; +in lib.mkIf cfg.nginx { + services.coredns.enable = true; + services.coredns.config = '' + dns://.:53 { + forward . tls://1.1.1.1 { + tls + tls_servername cloudflare-dns.com + } + cache + } + + https://.:${toString ports.coredns-https} { + forward . dns://127.0.0.1:53 { + tls + tls_servername cloudflare-dns.com + policy random + } + cache + } + ''; + # networking.networkmanager.insertNameservers = [ "127.0.0.1" ]; +} diff --git a/nix/server/forgejo.nix b/nix/server/forgejo.nix index c8e68e5..08e2583 100644 --- a/nix/server/forgejo.nix +++ b/nix/server/forgejo.nix @@ -5,6 +5,7 @@ }: let cfg = config.kp2pml30.server; + ports = config.kp2pml30.server.ports; in lib.mkIf cfg.forgejo { services.forgejo = { enable = true; @@ -14,7 +15,7 @@ in lib.mkIf cfg.forgejo { server = { DOMAIN = "git.${cfg.hostname}"; ROOT_URL = "https://git.${cfg.hostname}/"; - HTTP_PORT = 8002; + HTTP_PORT = ports.forgejo; }; service.DISABLE_REGISTRATION = true; }; diff --git a/nix/server/modify-secrets.sh b/nix/server/modify-secrets.sh new file mode 100755 index 0000000..e82f3d7 --- /dev/null +++ b/nix/server/modify-secrets.sh @@ -0,0 +1,26 @@ +#!/bin/sh +set -e + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +if ! command -v nvim +then + echo "no nvim" + exit 1 +fi + +if ! command -v base64 +then + echo "no base64" + exit 1 +fi + +if ! command -v openssl +then + echo "no openssl" + exit 1 +fi + +env $(cat /var/lib/secrets/.env | xargs) nvim --clean -n \ + -u "$SCRIPT_DIR/modify-secrets.vim" \ + "$SCRIPT_DIR/secrets.yaml" diff --git a/nix/server/modify-secrets.vim b/nix/server/modify-secrets.vim new file mode 100644 index 0000000..41f8fff --- /dev/null +++ b/nix/server/modify-secrets.vim @@ -0,0 +1,43 @@ +set nobackup nowritebackup noundofile noswapfile viminfo= history=0 noshelltemp secure + +function! s:OpenSSLReadPre() +endfunction + +function! s:OpenSSLReadPost() + silent! execute "0,$!openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -d -k '" . $KP2_DOTFILES_SECRET_KEY . "'" + if v:shell_error + silent! 0,$y + silent! undo + echo "Note that your version of openssl may not have the given cipher engine built-in" + echo "even though the engine may be documented in the openssl man pages." + echo "ERROR FROM OPENSSL:" + echo @" + echo "COULD NOT DECRYPT" + return + endif + redraw! +endfunction + +function! s:OpenSSLWritePre() + silent! execute "0,$!openssl enc -aes-256-cbc -pbkdf2 -iter 1000000 -base64 -k '" . $KP2_DOTFILES_SECRET_KEY . "'" + if v:shell_error + silent! 0,$y + silent! undo + echo "Note that your version of openssl may not have the given cipher engine built in" + echo "even though the engine may be documented in the openssl man pages." + echo "ERROR FROM OPENSSL:" + echo @" + echo "COULD NOT ENCRYPT" + return + endif +endfunction + +function! s:OpenSSLWritePost() + "silent! undo + "redraw! +endfunction + +autocmd BufReadPre,FileReadPre * call s:OpenSSLReadPre() +autocmd BufReadPost,FileReadPost * call s:OpenSSLReadPost() +autocmd BufWritePre,FileWritePre * call s:OpenSSLWritePre() +autocmd BufWritePost,FileWritePost * call s:OpenSSLWritePost() diff --git a/nix/server/nginx.nix b/nix/server/nginx.nix index b2ffa75..0d18f17 100644 --- a/nix/server/nginx.nix +++ b/nix/server/nginx.nix @@ -5,6 +5,7 @@ }: let cfg = config.kp2pml30.server; + ports = config.kp2pml30.server.ports; acmeRoot = "/var/lib/acme/acme-challenge"; pref = "kp2"; in lib.mkIf cfg.nginx { @@ -14,7 +15,7 @@ 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}" ]; + extraDomainNames = [ "pr.${cfg.hostname}" "www.${cfg.hostname}" "git.${cfg.hostname}" "backend.${cfg.hostname}" "dns.${cfg.hostname}" "cache.nix.${cfg.hostname}" "x.${cfg.hostname}" ]; webroot = acmeRoot; group = "nginx"; }; @@ -23,47 +24,180 @@ in lib.mkIf cfg.nginx { services.nginx = { enable = true; - virtualHosts."git.${cfg.hostname}" = { - enableACME = true; - acmeRoot = acmeRoot; + logError = "stderr debug"; - listen = [ - { addr = "0.0.0.0"; port = 80; } - ]; - locations."/" = { - proxyPass = "http://127.0.0.1:8002"; + virtualHosts = { + "git.${cfg.hostname}" = { + enableACME = true; + acmeRoot = acmeRoot; + + listen = [ + { addr = "0.0.0.0"; port = 80; } + ]; + + locations."/" = { + proxyPass = "http://127.0.0.1:${toString ports.forgejo}"; + }; }; - }; - virtualHosts."backend.${cfg.hostname}" = { - enableACME = true; - acmeRoot = acmeRoot; + "backend.${cfg.hostname}" = { + enableACME = true; + acmeRoot = acmeRoot; - listen = [ - { addr = "0.0.0.0"; port = 80; } - ]; + listen = [ + { addr = "0.0.0.0"; port = 80; } + ]; - locations."/" = { - proxyPass = "http://127.0.0.1:8001"; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString ports.backend}"; + }; }; - }; - virtualHosts."${cfg.hostname}" = { - # addSSL = true; - # forceSSL = true; - enableACME = true; - acmeRoot = acmeRoot; + "dns.${cfg.hostname}" = { + enableACME = true; + acmeRoot = acmeRoot; - listen = [ - { addr = "0.0.0.0"; port = 80; } - ]; + listen = [ + { addr = "0.0.0.0"; port = 80; } + ]; - locations."/" = { - root = cfg.sitePath; - tryFiles = "$uri $uri/ /index.html"; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString ports.coredns-https}"; + }; }; - }; + + "x.${cfg.hostname}" = { + enableACME = true; + acmeRoot = acmeRoot; + + listen = [ + { addr = "0.0.0.0"; port = 80; } + ]; + + locations."/" = { + proxyPass = "https://www.lovelive-anime.jp"; + extraConfig = '' + sub_filter $proxy_host $host; + sub_filter_once off; + + proxy_set_header Host $proxy_host; + proxy_http_version 1.1; + proxy_cache_bypass $http_upgrade; + proxy_ssl_server_name on; + + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Real-IP $proxy_protocol_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + resolver 1.1.1.1; + ''; + }; + }; + + + "${cfg.hostname}" = { + # addSSL = true; + # forceSSL = true; + enableACME = true; + acmeRoot = acmeRoot; + + listen = [ + { addr = "0.0.0.0"; port = 80; } + ]; + + locations."/" = { + root = cfg.sitePath; + tryFiles = "$uri $uri/ /index.html"; + }; + }; + } // (if cfg.xray then { + # Xray fallback proxy servers + "127.0.0.1:${toString ports.xray-fallback}" = { + listen = [ + { addr = "127.0.0.1"; port = ports.xray-fallback; proxyProtocol = true; } + ]; + + locations."/" = { + proxyPass = "https://www.lovelive-anime.jp"; + extraConfig = '' + sub_filter $proxy_host $host; + sub_filter_once off; + + proxy_set_header Host $proxy_host; + proxy_http_version 1.1; + proxy_cache_bypass $http_upgrade; + proxy_ssl_server_name on; + + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Real-IP $proxy_protocol_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + resolver 1.1.1.1; + ''; + }; + }; + + "127.0.0.1:${toString ports.xray-websocket}" = { + listen = [ + { addr = "127.0.0.1"; port = ports.xray-websocket; proxyProtocol = true; } + ]; + + locations."/" = { + proxyPass = "https://www.lovelive-anime.jp"; + extraConfig = '' + sub_filter $proxy_host $host; + sub_filter_once off; + + proxy_set_header Host $proxy_host; + proxy_http_version 1.1; + proxy_cache_bypass $http_upgrade; + proxy_ssl_server_name on; + + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header X-Real-IP $proxy_protocol_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port $server_port; + + proxy_connect_timeout 60s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + + resolver 1.1.1.1; + ''; + }; + }; + } else {}) // (if cfg.nix-cache then { + "cache.nix.${cfg.hostname}" = { + enableACME = true; + acmeRoot = acmeRoot; + listen = [ + { addr = "0.0.0.0"; port = 80; } + ]; + locations."/" = { + proxyPass = "http://${config.services.nix-serve.bindAddress}:${toString config.services.nix-serve.port}"; + }; + }; + } else {}); streamConfig = (builtins.readFile ./stream.nginx); }; diff --git a/nix/server/nix-cache.nix b/nix/server/nix-cache.nix new file mode 100644 index 0000000..14beb5a --- /dev/null +++ b/nix/server/nix-cache.nix @@ -0,0 +1,18 @@ + +{ config +, pkgs +, lib +, self +, nixpkgs +, kp2pml30-moe +, system +, ... +}@args: +let + cfg = config.kp2pml30.server; +in lib.mkIf cfg.nix-cache { + services.nix-serve = { + enable = true; + secretKeyFile = "/var/cache-priv-key.pem"; + }; +} diff --git a/nix/server/ports.nix b/nix/server/ports.nix new file mode 100644 index 0000000..903ac2f --- /dev/null +++ b/nix/server/ports.nix @@ -0,0 +1,45 @@ +{ lib, ... }: +{ + # Server Port Usage Configuration + # This file documents and centralizes all port assignments + + options.kp2pml30.server.ports = { + # Application Services + backend = lib.mkOption { + type = lib.types.int; + default = 8001; + description = "Backend service port (kp2pml30-moe-backend)"; + }; + + forgejo = lib.mkOption { + type = lib.types.int; + default = 8002; + description = "Forgejo Git service port"; + }; + + coredns-https = lib.mkOption { + type = lib.types.int; + default = 8003; + description = "CoreDNS HTTPS interface port"; + }; + + # Available ports for new services + xray-main = lib.mkOption { + type = lib.types.int; + default = 8010; + description = "Xray VLESS inbound port"; + }; + + xray-fallback = lib.mkOption { + type = lib.types.int; + default = 8011; + description = "Xray fallback proxy port"; + }; + + xray-websocket = lib.mkOption { + type = lib.types.int; + default = 8012; + description = "Xray websocket fallback port"; + }; + }; +} \ No newline at end of file diff --git a/nix/server/secrets.nix b/nix/server/secrets.nix new file mode 100644 index 0000000..cf9ad4f --- /dev/null +++ b/nix/server/secrets.nix @@ -0,0 +1,97 @@ +{ config +, pkgs +, lib +, ... +}: +let + cfg = config.kp2pml30.server; + + # Script to decrypt secrets.yaml and extract XRAY_UIDS + decryptSecrets = pkgs.writeShellScript "decrypt-secrets" '' + set -euo pipefail + + source /var/lib/secrets/.env + + if [ -z "''${KP2_DOTFILES_SECRET_KEY:-}" ]; then + echo "Error: KP2_DOTFILES_SECRET_KEY environment variable not set" >&2 + exit 1 + fi + + if [ ! -f "${./secrets.yaml}" ]; then + echo "Error: secrets.yaml not found" >&2 + exit 1 + fi + + # Decrypt and parse XRAY_UIDS + ${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); + + # Script to generate complete xray configuration + generateXrayConfig = pkgs.writeShellScript "generate-xray-config" '' + set -euo pipefail + + ALL_IDS="[" + + first=true + while IFS= read -r uuid; do + if [ "$first" = true ]; then + first=false + else + ALL_IDS="$ALL_IDS," + fi + ALL_IDS="$ALL_IDS{\"id\":\"$uuid\",\"flow\": \"xtls-rprx-vision\"}" + done < <(${decryptSecrets}) + + ALL_IDS="$ALL_IDS]" + + cat "${xray-config-base}" | \ + jq --argjson val "$ALL_IDS" '.inbounds.[0].settings.clients = $val' + ''; + +in { + options.kp2pml30.server.secretsDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/secrets"; + description = "Directory for secrets management"; + }; + + config = lib.mkIf cfg.xray { + # Ensure xray user and group exist + users.users.xray = { + isSystemUser = true; + group = "xray"; + }; + + users.groups.xray = {}; + + # Create a systemd service to decrypt and prepare xray clients config + systemd.services.xray-secrets = { + description = "Decrypt Xray client configuration"; + wantedBy = [ "xray.service" ]; + before = [ "xray.service" ]; + + serviceConfig = { + Type = "oneshot"; + User = "root"; + EnvironmentFile = "${cfg.secretsDir}/.env"; + }; + + script = '' + mkdir -p /run/secrets + ${generateXrayConfig} > /run/secrets/xray-config.json + chown xray:xray /run/secrets/xray-config.json + chmod 440 /run/secrets/xray-config.json + ''; + + path = [ pkgs.jq ]; + }; + + # Ensure secrets directory exists + systemd.tmpfiles.rules = [ + "d ${cfg.secretsDir} 0750 root root -" + "d /run/secrets 0755 root root -" + ]; + }; +} diff --git a/nix/server/secrets.yaml b/nix/server/secrets.yaml new file mode 100644 index 0000000..de129d6 --- /dev/null +++ b/nix/server/secrets.yaml @@ -0,0 +1,4 @@ +U2FsdGVkX18N4BW9sin9kPVNkpbtVNoDqBAm+080vcYSS7qySHVOCfe94a7S8mh4 +G5tbvoRrOFxJ+RW/WYNMsEZ7wgsJM8b9AiKPaT30BMHXriTdtai80i6xKqv9zdCb +moGUlBSgMtqEhvAnvpYBxHQ+NtDhxw7K9UjaO7eodNp+l9PR6z+IeL29rC2DMxQc +jXAjbfPa3aeSikXF0g118HbUwVJQwlXq99n/fjkJ8XOhBo/S4tWbt0U8O97VKlA6 diff --git a/nix/server/site.nix b/nix/server/site.nix index 243074d..a075874 100644 --- a/nix/server/site.nix +++ b/nix/server/site.nix @@ -9,6 +9,7 @@ }@args: let cfg = config.kp2pml30.server; + ports = config.kp2pml30.server.ports; backend = kp2pml30-moe.packages.${system}.kp2pml30-moe-backend; frontend = kp2pml30-moe.packages.${system}.kp2pml30-moe-frontend; in lib.mkIf cfg.nginx { @@ -45,7 +46,7 @@ in lib.mkIf cfg.nginx { Restart = "on-failure"; RestartSec = "3"; - ExecStart = ''${pkgs.bash}/bin/bash -c "source /home/kp2pml30-moe-backend/env.sh && touch /home/kp2pml30-moe-backend/db.json && ${backend}/bin/kp2pml30-moe-backend --port 8001 --moderated-path /home/kp2pml30-moe-backend/chatbox-db.json"''; + ExecStart = ''${pkgs.bash}/bin/bash -c "source /home/kp2pml30-moe-backend/env.sh && touch /home/kp2pml30-moe-backend/db.json && ${backend}/bin/kp2pml30-moe-backend --port ${toString ports.backend} --moderated-path /home/kp2pml30-moe-backend/chatbox-db.json"''; }; }; } diff --git a/nix/server/stream.nginx b/nix/server/stream.nginx index 3075273..dcdcc95 100644 --- a/nix/server/stream.nginx +++ b/nix/server/stream.nginx @@ -12,8 +12,15 @@ map $ssl_preread_server_name $name { updates.signal.org updates; updates2.signal.org updates2; - kp2pml30.moe self; - git.kp2pml30.moe self; + www.microsoft.com xray-entrypoint; + x.kp2pml30.moe xray-entrypoint; + pr.kp2pml30.moe signal-proxy; + + kp2pml30.moe ssl-terminator; + dns.kp2pml30.moe ssl-terminator; + git.kp2pml30.moe ssl-terminator; + cache.nix.kp2pml30.moe ssl-terminator; + backend.kp2pml30.moe ssl-terminator; default deny; } @@ -62,6 +69,10 @@ upstream updates2 { server updates2.signal.org:443; } +upstream xray-entrypoint { + server 127.0.0.1:8010; +} + upstream deny { server 127.0.0.1:9; } @@ -70,23 +81,45 @@ upstream self { server 127.0.0.1:80; } -server { - listen 443 ssl; - server_name pr.kp2pml30.moe; - proxy_pass $name; - ssl_preread on; +upstream ssl-terminator { + server 127.0.0.1:8443; +} - ssl_certificate /var/lib/acme/kp2pml30.moe/fullchain.pem; - ssl_certificate_key /var/lib/acme/kp2pml30.moe/key.pem; - ssl_trusted_certificate /var/lib/acme/kp2pml30.moe/chain.pem; +upstream signal-proxy { + server 127.0.0.1:8444; } server { - listen 443 ssl; - server_name kp2pml30.moe git.kp2pml30.moe backend.kp2pml30.moe; + listen 443; + ssl_preread on; + proxy_pass $name; +} + +server { + listen 8443 ssl; + server_name kp2pml30.moe git.kp2pml30.moe cache.nix.kp2pml30.moe backend.kp2pml30.moe dns.kp2pml30.moe; proxy_pass self; ssl_certificate /var/lib/acme/kp2pml30.moe/fullchain.pem; ssl_certificate_key /var/lib/acme/kp2pml30.moe/key.pem; ssl_trusted_certificate /var/lib/acme/kp2pml30.moe/chain.pem; } + +server { + listen 8444 ssl; + server_name pr.kp2pml30.moe; + ssl_preread on; + proxy_pass $name; + + ssl_certificate /var/lib/acme/kp2pml30.moe/fullchain.pem; + ssl_certificate_key /var/lib/acme/kp2pml30.moe/key.pem; + ssl_trusted_certificate /var/lib/acme/kp2pml30.moe/chain.pem; +} + +log_format proxy_log '$remote_addr [$time_local] ' + '$protocol $status $bytes_sent $bytes_received ' + '$session_time "$upstream_addr" ' + '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"' + 'Proxy: "$ssl_preread_server_name" $name"'; + +access_log /var/log/nginx/aboba-access.log proxy_log buffer=1k flush=1m; diff --git a/nix/server/xray-client.json b/nix/server/xray-client.json new file mode 100644 index 0000000..a2989e0 --- /dev/null +++ b/nix/server/xray-client.json @@ -0,0 +1,103 @@ +{ + "log": { + "loglevel": "warning" + }, + "routing": { + "domainStrategy": "IPIfNonMatch", + "rules": [ + { + "type": "field", + "domain": [ + "regexp:\\.ru$", + "regexp:\\.рф$", + "domain:vk.com" + ], + "outboundTag": "direct" + }, + { + "type": "field", + "domain": [ + "geosite:cn", + "geosite:private" + ], + "outboundTag": "direct" + }, + { + "type": "field", + "ip": [ + "geoip:cn", + "geoip:ru", + "geoip:private" + ], + "outboundTag": "direct" + } + ] + }, + "inbounds": [ + { + "listen": "127.0.0.1", + "port": 10808, + "protocol": "socks", + "settings": { + "udp": true + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ] + } + }, + { + "listen": "127.0.0.1", + "port": 10809, + "protocol": "http", + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ] + } + } + ], + "outbounds": [ + { + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "x.kp2pml30.moe", + "port": 443, + "users": [ + { + "id": "", + "encryption": "none", + "flow": "xtls-rprx-vision" + } + ] + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "tls", + "tlsSettings": { + "serverName": "", + "allowInsecure": false, + "fingerprint": "chrome" + } + }, + "tag": "proxy" + }, + { + "protocol": "freedom", + "tag": "direct" + }, + { + "protocol": "blackhole", + "tag": "block" + } + ] +} diff --git a/nix/server/xray-reality-client.json b/nix/server/xray-reality-client.json new file mode 100644 index 0000000..4916a85 --- /dev/null +++ b/nix/server/xray-reality-client.json @@ -0,0 +1,81 @@ +{ + "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 new file mode 100644 index 0000000..4787277 --- /dev/null +++ b/nix/server/xray-reality.json @@ -0,0 +1,90 @@ +{ + "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 + } + } + } +} diff --git a/nix/server/xray.json b/nix/server/xray.json new file mode 100644 index 0000000..24fe990 --- /dev/null +++ b/nix/server/xray.json @@ -0,0 +1,86 @@ +{ + "log": { + "loglevel": "warning" + }, + "routing": { + "domainStrategy": "IPIfNonMatch", + "rules": [ + { + "type": "field", + "domain": [ + "regexp:\\.ru$", + "regexp:\\.рф$", + "domain:vk.com" + ], + "outboundTag": "block" + }, + { + "type": "field", + "ip": [ + "geoip:cn", + "geoip:ru" + ], + "outboundTag": "block" + } + ] + }, + "inbounds": [ + { + "listen": "127.0.0.1", + "port": 8010, + "protocol": "vless", + "settings": { + "clients": [ + ], + "decryption": "none", + "fallbacks": [ + { + "dest": "8011", + "xver": 1 + } + ] + }, + "streamSettings": { + "network": "tcp", + "security": "tls", + "tlsSettings": { + "rejectUnknownSni": true, + "minVersion": "1.2", + "alpn": ["http/1.1"], + "certificates": [ + { + "ocspStapling": 3600, + "certificateFile": "/var/lib/acme/kp2pml30.moe/fullchain.pem", + "keyFile": "/var/lib/acme/kp2pml30.moe/key.pem" + } + ] + } + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls" + ] + } + } + ], + "outbounds": [ + { + "protocol": "freedom", + "tag": "direct" + }, + { + "protocol": "blackhole", + "tag": "block" + } + ], + "policy": { + "levels": { + "0": { + "handshake": 3, + "connIdle": 127 + } + } + } +} diff --git a/nix/server/xray.nix b/nix/server/xray.nix new file mode 100644 index 0000000..49fcf35 --- /dev/null +++ b/nix/server/xray.nix @@ -0,0 +1,21 @@ +{ config +, pkgs +, lib +, ... +}: +let + cfg = config.kp2pml30.server; + ports = config.kp2pml30.server.ports; +in lib.mkIf cfg.xray { + services.xray = { + enable = true; + settingsFile = "/run/secrets/xray-config.json"; + }; + + # Ensure xray can read the certificates + users.users.xray.extraGroups = [ "nginx" ]; + + # Ensure the xray service starts after ACME certificates are available + systemd.services.xray.after = [ "acme-${cfg.hostname}.service" ]; + systemd.services.xray.wants = [ "acme-${cfg.hostname}.service" ]; +} \ No newline at end of file