diff --git a/home/config/nvim/lua/config/options.lua b/home/config/nvim/lua/config/options.lua index 4c677b5..fa3db68 100644 --- a/home/config/nvim/lua/config/options.lua +++ b/home/config/nvim/lua/config/options.lua @@ -31,3 +31,22 @@ vim.g.mkdp_combine_preview = 1 vim.g.mkdp_echo_preview_url = 1 vim.g.mkdp_open_to_the_world = 1 vim.g.mkdp_port = "20088" + +-- Use osc52 as clipboard provider +local function paste() + return { vim.fn.split(vim.fn.getreg(""), "\n"), vim.fn.getregtype("") } +end +vim.g.clipboard = { + name = "OSC 52", + copy = { + ["+"] = require("vim.ui.clipboard.osc52").copy("+"), + ["*"] = require("vim.ui.clipboard.osc52").copy("*"), + }, + paste = { + ["+"] = paste, + ["*"] = paste, + }, +} +-- To ALWAYS use the clipboard for ALL operations +-- (instead of interacting with the "+" and/or "*" registers explicitly): +vim.opt.clipboard = "unnamedplus" diff --git a/home/user/environment.nix b/home/user/environment.nix index afb9aa1..795bd8c 100644 --- a/home/user/environment.nix +++ b/home/user/environment.nix @@ -33,5 +33,7 @@ GTK_CSD = "0"; GTK_USE_PORTAL = "1"; GTK_IM_MODULE = ""; + + MAIL = "~/Mailbox"; }; } diff --git a/home/user/tmux.nix b/home/user/tmux.nix index e9fa31c..7a6bc26 100644 --- a/home/user/tmux.nix +++ b/home/user/tmux.nix @@ -31,9 +31,18 @@ let tmux switch-client -t $selected_name ''; + + ryank = pkgs.writeShellScriptBin "ryank" '' + # copy via OSC 52 + buf=$( cat "$@" ) + len=$( printf %s "$buf" | wc -c ) max=74994 + test $len -gt $max && echo "$0: input is $(( len - max )) bytes too long" >&2 + printf "\033]52;c;$( printf %s "$buf" | head -c $max | base64 | tr -d '\r\n' )\a" + ''; in { home.packages = [ tmuxSessionizer + ryank ]; } diff --git a/system/dev/dn-server/default.nix b/system/dev/dn-server/default.nix index 77b9209..6a7ed0c 100644 --- a/system/dev/dn-server/default.nix +++ b/system/dev/dn-server/default.nix @@ -29,6 +29,10 @@ dataBackupPath = "/mnt/backup_dn"; dbBackupPath = "/mnt/backup_dn"; }) + (import ../../modules/vaultwarden.nix { + domain = "https://bitwarden.net.dn"; + }) + (import ../../modules/openldap.nix { }) ]; environment.systemPackages = with pkgs; [ diff --git a/system/dev/dn-server/mail-server.nix b/system/dev/dn-server/mail-server.nix index 2ee0860..9fb4741 100644 --- a/system/dev/dn-server/mail-server.nix +++ b/system/dev/dn-server/mail-server.nix @@ -1,5 +1,6 @@ { config, + pkgs, settings, ... }: @@ -16,7 +17,10 @@ let # fqdn = "dn-server.daccc.info"; in { - networking.firewall.allowedTCPPorts = [ 25 ]; + networking.firewall.allowedTCPPorts = [ + 25 + 587 + ]; services.postfix = { enable = true; @@ -29,9 +33,17 @@ in fqdn ]; + config = { + home_mailbox = "Mailbox"; + }; + postmasterAlias = "root"; rootAlias = settings.personal.username; + config = { + alias_maps = [ "ldap:${config.sops.secrets."postfix/openldap".path}" ]; + }; + extraAliases = '' mailer-daemon: postmaster nobody: root @@ -44,6 +56,7 @@ in abuse: root noc: root security: root + vaultwarden: root ''; }; } diff --git a/system/dev/dn-server/nginx.nix b/system/dev/dn-server/nginx.nix index e498b2c..2489125 100644 --- a/system/dev/dn-server/nginx.nix +++ b/system/dev/dn-server/nginx.nix @@ -1,16 +1,76 @@ { config, - lib, pkgs, ... }: let - acmeWebRoot = "/var/www/${config.services.nextcloud.hostName}/html/"; + mkProxyHost = ( + { + domain, + proxyPass, + ssl ? false, + }: + ( + if ssl then + { + forceSSL = true; + sslCertificate = "/etc/letsencrypt/live/${domain}/fullchain.pem"; + sslCertificateKey = "/etc/letsencrypt/live/${domain}/privkey.pem"; - certScript = pkgs.writeShellScriptBin "certbot-nextcloud" '' + listen = [ + { + addr = "0.0.0.0"; + port = 443; + ssl = true; + } + ]; + } + else + { + listen = [ + { + addr = "0.0.0.0"; + port = 80; + } + ]; + } + ) + // { + locations."/" = { + proxyPass = proxyPass; + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + ''; + }; + + locations."^~ /.well-known/acme-challenge/" = { + root = "/var/www/${domain}/html"; + extraConfig = '' + default_type "text/plain"; + ''; + }; + + extraConfig = '' + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384'; + ssl_prefer_server_ciphers on; + ''; + } + ); + + certScript = pkgs.writeShellScriptBin "genCert" '' + acmeWebRoot="/var/www/$1/html/"; + if [ ! -d "$acmeWebRoot" ]; then + mkdir -p "$acmeWebRoot" + fi + + REQUESTS_CA_BUNDLE=${../../../system/extra/ca.crt} \ ${pkgs.certbot}/bin/certbot certonly --webroot \ - --webroot-path ${acmeWebRoot} -v \ - -d ${config.services.nextcloud.hostName} \ + --webroot-path $acmeWebRoot -v \ + -d "$1" \ --server https://ca.net.dn:8443/acme/acme/directory \ -m admin@mail.net.dn @@ -21,17 +81,24 @@ let hostname = "pre-nextcloud.net.dn"; ip = "10.0.0.130"; }; + + vaultwarden = { + domain = "bitwarden.net.dn"; + }; in { + environment.systemPackages = [ + certScript + ]; + services.nginx = { enable = true; enableReload = true; virtualHosts = { # Nextcloud - Server - ${config.services.nextcloud.hostName} = { - listen = lib.mkForce [ + listen = [ { addr = "0.0.0.0"; port = 443; @@ -61,46 +128,16 @@ in ''; }; - ${pre7780.hostname} = { - listen = [ - { - addr = "0.0.0.0"; - port = 443; - ssl = true; - } - { - addr = "0.0.0.0"; - port = 80; - } - ]; - - locations."/" = { - proxyPass = "http://${pre7780.ip}/"; - extraConfig = '' - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - ''; - }; - - locations."^~ /.well-known/acme-challenge/" = { - root = "/var/www/${pre7780.hostname}/html"; - extraConfig = '' - default_type "text/plain"; - ''; - }; - - forceSSL = true; - sslCertificate = "/etc/letsencrypt/live/${pre7780.hostname}/fullchain.pem"; - sslCertificateKey = "/etc/letsencrypt/live/${pre7780.hostname}/privkey.pem"; - - extraConfig = '' - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384'; - ssl_prefer_server_ciphers on; - ''; + ${pre7780.hostname} = mkProxyHost { + domain = pre7780.hostname; + proxyPass = "http://${pre7780.ip}"; + ssl = true; + }; + ${vaultwarden.domain} = mkProxyHost { + domain = vaultwarden.domain; + proxyPass = "http://127.0.0.1:${builtins.toString config.services.vaultwarden.config.ROCKET_PORT}"; + ssl = true; }; }; }; diff --git a/system/dev/dn-server/secret.yaml b/system/dev/dn-server/secret.yaml index 5e4bfac..f6ae217 100644 --- a/system/dev/dn-server/secret.yaml +++ b/system/dev/dn-server/secret.yaml @@ -4,6 +4,13 @@ nextcloud: adminPassword: ENC[AES256_GCM,data:O2rK18+riVrvloqqLsMUXw==,iv:OosiF0g4l1mrgndbwUOvO2YUqxWVk1hvAZY0rHU9GPE=,tag:yh1ccDmthARLND0NwpLTCA==,type:str] step_ca: password: ENC[AES256_GCM,data:3EWxpk/ktZHJreqnR9ln5pfdPjgigoCC4lyoRWugHas=,iv:q9cWW8xTxYQnRYohBxnPIsbVSpvkZYVpYLRVeZgmsRM=,tag:UHZagnLvorZUrPq43YU+Gw==,type:str] +vaultwarden: ENC[AES256_GCM,data:PSKtHBIxw0/z/rmtF83Yg3btHksbVVyWZ80nP0wl4zAHRpFXypvpchZu9/edX7RgREd+9okm21WyjNWRUDoGVTOJYOCFHZCvOUx4KzIL2c/i7jUjXwtvAEmikhL1qlunVrCPhDu0knQ5nvsqpgWyxgcZl52yxuskMSIRAOsMpCRePVwJerWW5tuQ5zteYeOR0GHR8Q0iwBm98YGlCbKvz/37jAjMQVxY5W9DE1Tu1XVyEPBeAVvEwZknFNIZg1ukB+kW9Z/sBwLEVbAGsiBSGjonP6KEsgKmtaIkbBPzpfA3CQ==,iv:X8x3ooFDkFIT2OuHICcP2J1zX8T6xZW8j71ZuaByx6Q=,tag:mfnDFf9riivZ3EBup1l6lw==,type:str] +openldap: + adminPassword: ENC[AES256_GCM,data:dSaynM6RBrhZLOwcN2djaA==,iv:t2xJuRO2irEFgcnNcZS25qCfXiZXHaoqcCZYcR041aY=,tag:K5DiJRp+AumtKafAOR49/w==,type:str] +postfix: + openldap: ENC[AES256_GCM,data:8woTLrSJ5qqZU7jizOIK9VGlaPaBuyhq6FOs6LwiE9WHYJzWCAw3D+449SmCVeEE2t+EZWmfRPaOQBceSeIfUY6WZ5vso1E29CWPq8Tk7AuHT2i/K82EhpapXst61IAgSa/y39MchA7LqwaiTzL3A2CJVM1k5Ay5iHUUDfXvLbUsVmn1NlNfOv2QPPd5g+2yR2oGGx5HTbTPQNfoiU77KtvtFmlrubAs413I3DGdhM4uiOS+FI9WgZ4Ia22BucaOLHp2odfWnEMbP+ZIyJFdu3CBcs1lbTnLLVI=,iv:RvPm2+WsTIPFWLlYzv/OyKKDy/fWhtEfut98mBoM/1A=,tag:wkkWK88D0jKfaudN+KpN0Q==,type:str] +dovecot: + openldap: ENC[AES256_GCM,data:G7jdoSqL2SYDv2alh7q65BaA8Ap898azUPf2KKWd5wbr9pRVsRhFxQxHdZDuTOHDhWcfaa+eqMgc5k9gGLBYIO9EWVyEZ01/QfG4GIHSDjubzZxCElwhJrtsFn1A+Ihv7T1IIGKBCdmQGhUwfBMtwYlIuj8PYZaty4+c/dxIOCfDr5HyM1C6qQ4RCJTDEh6B+Hpx8NlFO0+fRFC9+9tQYX0rjI7JZRSfbg7F23nEdkBATr/xlwQXj8dvXYMLZhUKaswFnRs5TrG97AVQ9t3rMguRHutCAqEROhml2lJvV3Vxb/yMmTrom8qSrbkuw00YfdlDCmUo5/E4Vu9DYL0kv0EnASyQ4vQbmVXz0clYEzEXBLWZIEu4QHGJ7jQWgsKFv+WSTvuunVQyNuij3SFWZLR/zdfJELxU,iv:bsGMMdDo1Mj4GxRbWuRmbH/WrLt25jK3we8JDYQRsLw=,tag:EugvDijjQnYcms70nZq5FQ==,type:str] sops: kms: [] gcp_kms: [] @@ -19,8 +26,8 @@ sops: Qm0wbmNGZDZwZlNTOVl0WVh5RXNxK2cK1Fwbgl5kKAFyrIIhBP+X4ZKFS4Xl39QY 11qkglNgro/JBFJ/W7Hj5wtEd8QToiJM1RW0lQaI25sneQ2v6L5pDA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-04-22T06:01:27Z" - mac: ENC[AES256_GCM,data:HQHGQRuRR93Lwny8Bbv3Po2xSNvKgrLJhXC7txwwwO0Qh4Q3HjngpJqTQZg8KXe6PyNj8iPSnqW3Bt1jjOv9vjPPQVhRiUFy5pMBd/aK7mkBhTbvN4CMj5y1egU6TBMceRvlU5rhtPSsiIzq1egA/YOsfyeAXkLBghDRZmabq8s=,iv:IAvO0Kewx9D7NxWQ5K9heQtdksK7xfvl0eQCU1n0bmU=,tag:KPNbBeqXTeei+CXyL1NaOw==,type:str] + lastmodified: "2025-05-04T13:11:13Z" + mac: ENC[AES256_GCM,data:+V5vP4XbeXQP49gyisV4uQJjUybtK792DaFEWBHzLlKn2HiRj+qqSVR5XQrQMQQ5mKMhzsZXGq7QjjXtzKqgLCz5snItU63HzxQ6OxarNeg5pctk7i8ueNST4JpMxZODKGJncz2Ysq8OGrjZ6Nf4QVjO0XhFxZP6MbZxZL7wbuY=,iv:7jKt3uAY/ks8m/uzpos6XvldkpQjkgCHcLn+oRiY3mk=,tag:d6V+waMu4m2wi/H/J3bMXg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4 diff --git a/system/dev/dn-server/services.nix b/system/dev/dn-server/services.nix index eef364a..00fe82c 100644 --- a/system/dev/dn-server/services.nix +++ b/system/dev/dn-server/services.nix @@ -382,10 +382,11 @@ in IN NS dns.${origin} @ IN A ${serverIP} IN AAAA fe80::3319:e2bb:fc15:c9df - IN MX 10 mail.${origin} + @ IN MX 10 mail.${origin} IN TXT "v=spf1 mx" dns IN A ${serverIP} nextcloud IN A ${serverIP} + bitwarden IN A ${serverIP} pre-nextcloud IN A ${serverIP} ca IN A ${serverIP} ${hostname} IN A ${serverIP} @@ -406,7 +407,6 @@ in file = let serverIP = getSubAddress personal.ip; - mailIP = getSubAddress personal.ip; hostname = config.networking.hostName; in pkgs.writeText "${getReverseFilename personal.ip}" '' @@ -420,11 +420,12 @@ in IN NS dns.${personal.domain}. ${serverIP} IN PTR dns.${personal.domain}. + ${serverIP} IN PTR mail.${personal.domain}. ${serverIP} IN PTR ${hostname}.${personal.domain}. ${serverIP} IN PTR nextcloud.${personal.domain}. + ${serverIP} IN PTR bitwarden.${personal.domain}. ${serverIP} IN PTR pre-nextcloud.${personal.domain}. ${serverIP} IN PTR ca.${personal.domain}. - ${mailIP} IN PTR mail.${personal.domain}. ${dnsReversedRecords} ''; diff --git a/system/dev/dn-server/sops-conf.nix b/system/dev/dn-server/sops-conf.nix index 1601f3c..6727982 100644 --- a/system/dev/dn-server/sops-conf.nix +++ b/system/dev/dn-server/sops-conf.nix @@ -1,9 +1,16 @@ +{ config, ... }: { sops = { secrets = { "wireguard/privateKey" = { }; "nextcloud/adminPassword" = { }; "step_ca/password" = { }; + vaultwarden = { }; + "postfix/openldap" = { }; + "openldap/adminPassword" = { + owner = config.users.users.openldap.name; + group = config.users.users.openldap.group; + }; }; }; } diff --git a/system/modules/certbot.nix b/system/modules/certbot.nix index 4a88cfd..3a777f8 100644 --- a/system/modules/certbot.nix +++ b/system/modules/certbot.nix @@ -25,13 +25,14 @@ ExecStart = ''${pkgs.certbot}/bin/certbot renew''; ExecStartPost = "${pkgs.busybox}/bin/chown nginx:nginx -R /etc/letsencrypt"; }; - unitConfig = { - OnSuccess = "nginx-reload-after-certbot.service"; - }; }; systemd.services."nginx-reload-after-certbot" = { + after = [ "certbot-renew.service" ]; + requires = [ "certbot-renew.service" ]; + wantedBy = [ "certbot-renew.service" ]; serviceConfig = { + Type = "oneshot"; User = "nginx"; # This config file path refers to "services.nginx.enableReload" ExecStart = ''${pkgs.nginx}/bin/nginx -s reload -c /etc/nginx/nginx.conf''; diff --git a/system/modules/openldap.nix b/system/modules/openldap.nix new file mode 100644 index 0000000..23bb98b --- /dev/null +++ b/system/modules/openldap.nix @@ -0,0 +1,129 @@ +{ + urlList ? [ "ldap:///" ], +}: +{ + pkgs, + config, + ... +}: +let + create_ldap_user = pkgs.writeShellScriptBin "create_ldap_user" '' + # Base DN for LDAP directory + BASE_DN="dc=net,dc=dn" + # Organizational Unit (OU) where users are stored + OU="people" + + # Prompt for username + read -p "Please enter the username: " USERNAME + + # Prompt for password (hidden input) + read -s -p "Please enter the password: " USER_PASSWORD + echo + # Prompt for password confirmation (hidden input) + read -s -p "Please confirm the password: " USER_PASSWORD_CONFIRM + echo + + # Check if the entered passwords match + if [ "$USER_PASSWORD" != "$USER_PASSWORD_CONFIRM" ]; then + echo "❌ Passwords do not match. Please run the script again." + exit 1 + fi + + # Hash the password using slappasswd + PASSWORD_HASH=$(slappasswd -s "$USER_PASSWORD") + + # Construct the Distinguished Name (DN) for the user + USER_DN="uid=$USERNAME,ou=$OU,$BASE_DN" + + # Check if the base DN (dc=net,dc=dn) exists, if not, create it + ldapsearch -x -b "$BASE_DN" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "⚠️ $BASE_DN does not exist. Creating it now..." + cat < /dev/null 2>&1 + if [ $? -ne 0 ]; then + echo "⚠️ OU=$OU does not exist. Creating it now..." + cat <