From 84c39b405972516a9be2e8be8729097f8691050f Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Fri, 17 Oct 2025 08:31:18 +0530 Subject: chore(os/kay): refactor --- os/kay/modules/acme.nix | 24 -- os/kay/modules/alina.nix | 30 -- os/kay/modules/cgit.nix | 34 --- os/kay/modules/github-runner.nix | 41 --- os/kay/modules/headscale.nix | 112 ------- os/kay/modules/home-assistant.nix | 47 --- os/kay/modules/hurricane.nix | 132 --------- os/kay/modules/immich.nix | 23 -- os/kay/modules/internal/acme.nix | 24 ++ os/kay/modules/internal/postgresql.nix | 28 ++ os/kay/modules/internal/www.nix | 323 ++++++++++++++++++++ os/kay/modules/iperf3.nix | 10 - os/kay/modules/mail.nix | 173 ----------- os/kay/modules/matrix/default.nix | 22 -- os/kay/modules/matrix/dendrite.nix | 109 ------- os/kay/modules/matrix/matrix-sliding-sync.nix | 123 -------- os/kay/modules/minio.nix | 36 --- os/kay/modules/network.nix | 70 ----- os/kay/modules/network/default.nix | 72 +++++ os/kay/modules/network/headscale.nix | 112 +++++++ os/kay/modules/network/hurricane.nix | 132 +++++++++ os/kay/modules/network/router.nix | 72 +++++ os/kay/modules/network/wireguard.nix | 71 +++++ os/kay/modules/nix-cache.nix | 12 - os/kay/modules/postgresql.nix | 28 -- os/kay/modules/router.nix | 77 ----- os/kay/modules/services/alina.nix | 30 ++ os/kay/modules/services/cgit.nix | 34 +++ os/kay/modules/services/github-runner.nix | 41 +++ os/kay/modules/services/home-assistant.nix | 47 +++ os/kay/modules/services/immich.nix | 23 ++ os/kay/modules/services/iperf3.nix | 10 + os/kay/modules/services/mail.nix | 173 +++++++++++ os/kay/modules/services/matrix/default.nix | 22 ++ os/kay/modules/services/matrix/dendrite.nix | 109 +++++++ .../services/matrix/matrix-sliding-sync.nix | 123 ++++++++ os/kay/modules/services/minio.nix | 36 +++ os/kay/modules/services/nix-cache.nix | 12 + os/kay/modules/services/sftp.nix | 59 ++++ os/kay/modules/sftp.nix | 59 ---- os/kay/modules/sshfwd.nix | 32 -- os/kay/modules/wireguard.nix | 71 ----- os/kay/modules/www.nix | 328 --------------------- 43 files changed, 1553 insertions(+), 1593 deletions(-) delete mode 100644 os/kay/modules/acme.nix delete mode 100644 os/kay/modules/alina.nix delete mode 100644 os/kay/modules/cgit.nix delete mode 100644 os/kay/modules/github-runner.nix delete mode 100644 os/kay/modules/headscale.nix delete mode 100644 os/kay/modules/home-assistant.nix delete mode 100644 os/kay/modules/hurricane.nix delete mode 100644 os/kay/modules/immich.nix create mode 100644 os/kay/modules/internal/acme.nix create mode 100644 os/kay/modules/internal/postgresql.nix create mode 100644 os/kay/modules/internal/www.nix delete mode 100644 os/kay/modules/iperf3.nix delete mode 100644 os/kay/modules/mail.nix delete mode 100644 os/kay/modules/matrix/default.nix delete mode 100644 os/kay/modules/matrix/dendrite.nix delete mode 100644 os/kay/modules/matrix/matrix-sliding-sync.nix delete mode 100644 os/kay/modules/minio.nix delete mode 100644 os/kay/modules/network.nix create mode 100644 os/kay/modules/network/default.nix create mode 100644 os/kay/modules/network/headscale.nix create mode 100644 os/kay/modules/network/hurricane.nix create mode 100644 os/kay/modules/network/router.nix create mode 100644 os/kay/modules/network/wireguard.nix delete mode 100644 os/kay/modules/nix-cache.nix delete mode 100644 os/kay/modules/postgresql.nix delete mode 100644 os/kay/modules/router.nix create mode 100644 os/kay/modules/services/alina.nix create mode 100644 os/kay/modules/services/cgit.nix create mode 100644 os/kay/modules/services/github-runner.nix create mode 100644 os/kay/modules/services/home-assistant.nix create mode 100644 os/kay/modules/services/immich.nix create mode 100644 os/kay/modules/services/iperf3.nix create mode 100644 os/kay/modules/services/mail.nix create mode 100644 os/kay/modules/services/matrix/default.nix create mode 100644 os/kay/modules/services/matrix/dendrite.nix create mode 100644 os/kay/modules/services/matrix/matrix-sliding-sync.nix create mode 100644 os/kay/modules/services/minio.nix create mode 100644 os/kay/modules/services/nix-cache.nix create mode 100644 os/kay/modules/services/sftp.nix delete mode 100644 os/kay/modules/sftp.nix delete mode 100644 os/kay/modules/sshfwd.nix delete mode 100644 os/kay/modules/wireguard.nix delete mode 100644 os/kay/modules/www.nix (limited to 'os/kay/modules') diff --git a/os/kay/modules/acme.nix b/os/kay/modules/acme.nix deleted file mode 100644 index 60e40a8..0000000 --- a/os/kay/modules/acme.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ config, pkgs, ... }: -let - email = config.global.userdata.email; - domain = config.global.userdata.domain; - - environmentFile = pkgs.writeText "acme-dns" "RFC2136_NAMESERVER='[2001:470:ee65::1]:53'"; -in -{ - security.acme = { - acceptTerms = true; - defaults.email = email; - - certs.${domain} = { - inherit domain; - extraDomainNames = [ "*.${domain}" ]; - - dnsProvider = "rfc2136"; - dnsPropagationCheck = false; # local DNS server - - inherit environmentFile; - group = config.services.nginx.group; - }; - }; -} diff --git a/os/kay/modules/alina.nix b/os/kay/modules/alina.nix deleted file mode 100644 index c567953..0000000 --- a/os/kay/modules/alina.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ config, alina, ... }: -let - domain = "alinafs.com"; -in -{ - imports = [ alina.nixosModules.alina ]; - - sops.secrets."misc/alina" = { }; - - services.postgresql = { - ensureDatabases = [ "alina" ]; - ensureUsers = [ - { - name = "alina"; - ensureDBOwnership = true; - } - ]; - }; - - services.alina = { - enable = true; - port = 8006; - environmentFile = config.sops.secrets."misc/alina".path; - settings.server = { - data = "/hdd/alina"; - file_size_limit = 1024 * 1024 * 1024; # 1GB - public_url = "https://${domain}"; - }; - }; -} diff --git a/os/kay/modules/cgit.nix b/os/kay/modules/cgit.nix deleted file mode 100644 index 254cc80..0000000 --- a/os/kay/modules/cgit.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ config, pkgs, ... }: - -let - domain = config.global.userdata.domain; - user = config.global.userdata.name; -in -{ - users.users.${user}.packages = with pkgs; [ git ]; - environment.systemPackages = with pkgs; [ - luajitPackages.luaossl - lua52Packages.luaossl - ]; - - services.cgit."git.${domain}" = { - enable = true; - nginx.virtualHost = "git.${domain}"; - scanPath = "/var/lib/git"; - settings = { - project-list = "/var/lib/git/project.list"; - remove-suffix = 1; - enable-commit-graph = 1; - root-title = "${user}'s git repository"; - root-desc = "how do i learn github anon"; - source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; - about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; - readme = ":README.md"; - footer = ""; - enable-blame = 1; - clone-url = "https://git.${domain}/$CGIT_REPO_URL"; - enable-log-filecount = 1; - enable-log-linecount = 1; - }; - }; -} diff --git a/os/kay/modules/github-runner.nix b/os/kay/modules/github-runner.nix deleted file mode 100644 index dd4d48d..0000000 --- a/os/kay/modules/github-runner.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ config, ... }: -let - repo = "nocodb/nocodb"; - nocodbRunnerUser = "nocodbrunner"; - user = config.global.userdata.name; -in -{ - sops.secrets = { - "github-runner/nocodb-registration-token" = { }; - "github-runner/age-master-key" = { }; - }; - - # required by github:nocodb/nocodb docker builds - virtualisation.docker.enable = true; - users.groups.${nocodbRunnerUser} = { }; - users.extraGroups.docker.members = [ - user - nocodbRunnerUser - ]; - users.users.nocodbrunner = { - name = nocodbRunnerUser; - group = nocodbRunnerUser; - isSystemUser = true; - }; - services.github-runners.kay = { - user = nocodbRunnerUser; - group = nocodbRunnerUser; - enable = true; - noDefaultLabels = true; - extraLabels = [ "nix" ]; - tokenFile = config.sops.secrets."github-runner/nocodb-registration-token".path; - url = "https://github.com/${repo}"; - }; - - systemd.services."github-runner-kay" = { - environment.SOPS_AGE_KEY_FILE = "%d/age-master-key"; - serviceConfig.LoadCredential = "age-master-key:${ - config.sops.secrets."github-runner/age-master-key".path - }"; - }; -} diff --git a/os/kay/modules/headscale.nix b/os/kay/modules/headscale.nix deleted file mode 100644 index 24df170..0000000 --- a/os/kay/modules/headscale.nix +++ /dev/null @@ -1,112 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -let - domain = "headscale.${config.global.userdata.domain}"; - stunPort = 3478; - - # A workaround generate a valid Headscale config accepted by Headplane when `config_strict == true`. - settings = lib.recursiveUpdate config.services.headscale.settings { - tls_cert_path = "/dev/null"; - tls_key_path = "/dev/null"; - policy.path = "/dev/null"; - }; - format = pkgs.formats.yaml { }; - headscaleConfig = format.generate "headscale.yml" settings; - - policyFormat = pkgs.formats.json { }; - policy = { - groups = { - "group:owner" = [ "sinan@" ]; - "group:bud" = [ - "sinan@" - "ann@" - ]; - }; - tagOwners = { - "tag:bud_clients" = [ "group:bud" ]; - "tag:internal" = [ "group:owner" ]; - "tag:cusat" = [ "group:owner" ]; - "tag:gaijin" = [ "group:owner" ]; - }; - acls = [ - { - action = "accept"; - src = [ "group:owner" ]; - dst = [ "*:*" ]; - } - - { - action = "accept"; - src = [ "group:bud" ]; - dst = [ "tag:bud_clients:*" ]; - } - ]; - }; -in -{ - sops.secrets = { - "headplane/cookie_secret".owner = config.services.headscale.user; - "headplane/preauth_key".owner = config.services.headscale.user; - "headscale/noise_private_key".owner = config.services.headscale.user; - "headscale/derp_private_key".owner = config.services.headscale.user; - }; - - networking.firewall.interfaces.ppp0.allowedUDPPorts = [ stunPort ]; - - services = { - headscale = { - enable = true; - port = 8139; - - settings = { - logtail.enabled = false; - server_url = "https://${domain}"; - noise.private_key_path = config.sops.secrets."headscale/noise_private_key".path; - dns = { - base_domain = "tsnet.${config.global.userdata.domain}"; - override_local_dns = false; - }; - derp = { - server = { - enabled = true; - private_key_path = config.sops.secrets."headscale/derp_private_key".path; - region_code = config.networking.hostName; - region_name = config.networking.hostName; - stun_listen_addr = "0.0.0.0:${toString stunPort}"; - region_id = 6969; - automatically_add_embedded_derp_region = true; - }; - urls = [ ]; - }; - policy = { - mode = "file"; - path = policyFormat.generate "acl.json" policy; - }; - }; - }; - - headplane = { - enable = true; - settings = { - server = { - port = 8140; - cookie_secret_path = config.sops.secrets."headplane/cookie_secret".path; - }; - headscale = { - url = "https://${domain}"; - config_path = "${headscaleConfig}"; - }; - integration.agent = { - enabled = true; - pre_authkey_path = config.sops.secrets."headplane/preauth_key".path; - }; - }; - }; - }; - - environment.systemPackages = [ config.services.headscale.package ]; -} diff --git a/os/kay/modules/home-assistant.nix b/os/kay/modules/home-assistant.nix deleted file mode 100644 index 65807f7..0000000 --- a/os/kay/modules/home-assistant.nix +++ /dev/null @@ -1,47 +0,0 @@ -{ pkgs, ... }: -{ - services.postgresql = { - enable = true; - - ensureDatabases = [ "hass" ]; - ensureUsers = [ - { - name = "hass"; - ensureDBOwnership = true; - } - ]; - }; - - services.home-assistant = { - enable = true; - package = - (pkgs.home-assistant.override { - extraPackages = py: with py; [ psycopg2 ]; - }).overrideAttrs - (oldAttrs: { - doInstallCheck = false; - }); - - extraComponents = [ - "analytics" - "google_translate" - "met" - "radio_browser" - "shopping_list" - "tplink" - "tuya" - "utility_meter" - ]; - - config = { - default_config = { }; - - recorder.db_url = "postgresql://@/hass"; - http = { - server_host = "127.0.0.1"; - trusted_proxies = [ "127.0.0.1" ]; - use_x_forwarded_for = true; - }; - }; - }; -} diff --git a/os/kay/modules/hurricane.nix b/os/kay/modules/hurricane.nix deleted file mode 100644 index e815136..0000000 --- a/os/kay/modules/hurricane.nix +++ /dev/null @@ -1,132 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: - -let - iface = "hurricane"; - remote = "216.218.221.42"; - - clinet = "2001:470:35:72a::2"; - server = "2001:470:35:72a::1"; - - prefix64 = "2001:470:36:72a::/64"; - prefix48 = "2001:470:ee65::/48"; - - makeAddr = - prefix: host: - let - split = lib.strings.splitString "/" prefix; - in - { - address = "${lib.head split}${host}"; - prefixLength = lib.toInt (lib.last split); - }; -in -{ - networking = { - sits.${iface} = { - inherit remote; - ttl = 225; - }; - interfaces.${iface} = { - mtu = 1472; # 1492(ppp0) - 20 - ipv6.addresses = [ - { - address = clinet; - prefixLength = 64; - } - - (makeAddr prefix64 "1") - (makeAddr prefix48 "1") - (makeAddr prefix48 "1337") - ]; - }; - - iproute2 = { - enable = true; - rttablesExtraConfig = "200 hurricane"; - }; - - firewall = { - extraCommands = "iptables -A INPUT --proto 41 --source ${remote} --jump ACCEPT"; - extraStopCommands = "iptables -D INPUT --proto 41 --source ${remote} --jump ACCEPT"; - }; - }; - - sops.secrets = { - "hurricane/username" = { }; - "hurricane/update_key" = { }; - "hurricane/tunnel_id" = { }; - }; - - systemd.services."network-route-${iface}" = { - description = "Routing configuration of ${iface}"; - wantedBy = [ - "network-setup.service" - "network.target" - ]; - before = [ "network-setup.service" ]; - bindsTo = [ "network-addresses-hurricane.service" ]; - after = [ - "network-pre.target" - "network-addresses-hurricane.service" - ]; - # restart rather than stop+start this unit to prevent the - # network from dying during switch-to-configuration. - stopIfChanged = false; - - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - - path = [ pkgs.iproute2 ]; - script = '' - echo -n "adding route" - - ip -6 rule add from ${clinet}/64 table hurricane || exit 1 - ip -6 rule add from ${prefix64} table hurricane || exit 1 - ip -6 rule add from ${prefix48} table hurricane || exit 1 - - ip -6 route add default via ${server} dev hurricane table hurricane || exit 1 - ''; - preStop = '' - echo -n "deleting route" - - ip -6 route del default via ${server} dev hurricane table hurricane || exit 1 - - ip -6 rule del from ${prefix48} table hurricane || exit 1 - ip -6 rule del from ${prefix64} table hurricane || exit 1 - ip -6 rule del from ${clinet}/64 table hurricane || exit 1 - ''; - }; - - services.pppd.script."01-${iface}" = { - runtimeInputs = with pkgs; [ - curl - coreutils - iproute2 - iputils - ]; - text = '' - wan_ip="$4" - username="$(cat ${config.sops.secrets."hurricane/username".path})" - update_key="$(cat ${config.sops.secrets."hurricane/update_key".path})" - tunnel_id="$(cat ${config.sops.secrets."hurricane/tunnel_id".path})" - - auth_url="https://$username:$update_key@ipv4.tunnelbroker.net/nic/update?hostname=$tunnel_id" - until curl --silent "$auth_url"; do - sleep 1 - done - - while [ ! -e /sys/class/net/${iface} ]; do - sleep 1 # make sure ${iface} is up - done - - ip tunnel change ${iface} local "$wan_ip" mode sit - ''; - }; -} diff --git a/os/kay/modules/immich.nix b/os/kay/modules/immich.nix deleted file mode 100644 index 5e5eaf4..0000000 --- a/os/kay/modules/immich.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, ... }: -let - domain = config.global.userdata.domain; - mediaLocation = "/hdd/immich"; -in -{ - services.immich = { - enable = true; - inherit mediaLocation; - settings.server.externalDomain = "https://immich.${domain}"; - }; - - systemd.tmpfiles.settings.immich.${mediaLocation}.d = { - group = config.services.immich.group; - user = config.services.immich.user; - mode = "0755"; - }; - - users.users.immich.extraGroups = [ - "video" - "render" - ]; -} diff --git a/os/kay/modules/internal/acme.nix b/os/kay/modules/internal/acme.nix new file mode 100644 index 0000000..60e40a8 --- /dev/null +++ b/os/kay/modules/internal/acme.nix @@ -0,0 +1,24 @@ +{ config, pkgs, ... }: +let + email = config.global.userdata.email; + domain = config.global.userdata.domain; + + environmentFile = pkgs.writeText "acme-dns" "RFC2136_NAMESERVER='[2001:470:ee65::1]:53'"; +in +{ + security.acme = { + acceptTerms = true; + defaults.email = email; + + certs.${domain} = { + inherit domain; + extraDomainNames = [ "*.${domain}" ]; + + dnsProvider = "rfc2136"; + dnsPropagationCheck = false; # local DNS server + + inherit environmentFile; + group = config.services.nginx.group; + }; + }; +} diff --git a/os/kay/modules/internal/postgresql.nix b/os/kay/modules/internal/postgresql.nix new file mode 100644 index 0000000..6ba5398 --- /dev/null +++ b/os/kay/modules/internal/postgresql.nix @@ -0,0 +1,28 @@ +{ + config, + lib, + pkgs, + ... +}: +{ + services.postgresql = { + enable = true; + package = with pkgs; postgresql_15; + authentication = lib.mkForce '' + #type database DBuser origin-address auth-method + # unix socket + local all all trust + # ipv4 + host all all 127.0.0.1/32 trust + # ipv6 + host all all ::1/128 trust + ''; + + settings.log_timezone = config.time.timeZone; + }; + + services.prometheus.exporters.postgres = { + enable = true; + listenAddress = "127.0.0.1"; + }; +} diff --git a/os/kay/modules/internal/www.nix b/os/kay/modules/internal/www.nix new file mode 100644 index 0000000..dd0a1ef --- /dev/null +++ b/os/kay/modules/internal/www.nix @@ -0,0 +1,323 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + domain = config.global.userdata.domain; + storage = "/hdd/users/sftp/shr"; +in +{ + security.acme.certs.${domain}.postRun = "systemctl reload nginx.service"; + networking.firewall = { + allowedTCPPorts = [ + 80 + 443 + ]; + allowedUDPPorts = [ 443 ]; + }; + + services.prometheus.exporters = { + nginxlog = { + enable = true; + listenAddress = "127.0.0.1"; + }; + nginx = { + enable = true; + listenAddress = "127.0.0.1"; + }; + }; + + services.nginx = { + enable = true; + statusPage = true; + package = pkgs.nginxQuic; + enableQuicBPF = true; + + recommendedTlsSettings = true; + # breaks home-assistant proxy for some reason + # only the first request goes through, then site hangs + # recommendedZstdSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedProxySettings = true; + recommendedBrotliSettings = true; + eventsConfig = "worker_connections 1024;"; + appendHttpConfig = '' + quic_retry on; + quic_gso on; + add_header Alt-Svc 'h3=":443"; ma=2592000; persist=1'; + ''; + + virtualHosts = + let + defaultOpts = { + # reuseport = true; + quic = true; + http3 = true; + forceSSL = true; + useACMEHost = domain; + }; + in + { + "${domain}" = defaultOpts // { + default = true; + globalRedirect = "www.${domain}"; + + extraConfig = '' + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + + locations = { + "/.well-known/matrix/server".return = '' + 200 '{ "m.server": "${domain}:443" }' + ''; + + "/.well-known/matrix/client".return = '' + 200 '${ + builtins.toJSON { + "m.homeserver".base_url = "https://${domain}"; + "org.matrix.msc3575.proxy".url = "https://sliding.${domain}"; + "m.identity_server".base_url = "https://vector.im"; + } + }' + ''; + + "/.well-known/".proxyPass = "http://127.0.0.1:8085"; + + "~ ^(\\/_matrix|\\/_synapse\\/client)".proxyPass = + "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; + }; + }; + + "sliding.${domain}" = defaultOpts // { + extraConfig = '' + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://${config.services.matrix-sliding-sync-dirty.settings.SYNCV3_BINDADDR}"; + }; + }; + + "headscale.${domain}" = defaultOpts // { + locations = { + "/" = { + proxyWebsockets = true; + proxyPass = "http://localhost:${toString config.services.headscale.port}"; + }; + "= /".return = "307 https://headscale.${domain}/admin"; + "/admin".proxyPass = "http://localhost:${toString config.services.headplane.settings.server.port}"; + }; + }; + + "${config.services.grafana.settings.server.domain}" = defaultOpts // { + extraConfig = '' + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://${config.services.grafana.settings.server.http_addr}:${builtins.toString config.services.grafana.settings.server.http_port}"; + }; + }; + + "www.${domain}" = defaultOpts // { + extraConfig = '' + ssl_early_data on; + ''; + + root = "/var/www/${domain}"; + }; + + "git.${domain}" = defaultOpts // { + extraConfig = '' + ssl_early_data on; + ''; + }; + + "bin.${domain}" = defaultOpts // { + extraConfig = '' + ssl_early_data on; + ''; + root = "${storage}/bin"; + locations."= /".return = "307 https://www.${domain}"; + }; + + "static.${domain}" = defaultOpts // { + extraConfig = '' + ssl_early_data on; + ''; + root = "${storage}/static"; + locations."= /".return = "301 https://www.${domain}"; + }; + + "home.${domain}" = defaultOpts // { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://127.0.0.1:${builtins.toString config.services.home-assistant.config.http.server_port}"; + }; + }; + + "stalwart.${domain}" = defaultOpts // { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://127.0.0.1:8085"; + }; + }; + + "s3.${domain}" = defaultOpts // { + extraConfig = '' + # Allow special characters in headers + ignore_invalid_headers off; + # Allow any size file to be uploaded. + # Set to a value such as 1000m; to restrict file size to a specific value + client_max_body_size 0; + # Disable buffering + proxy_buffering off; + proxy_request_buffering off; + ''; + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://127.0.0.1:9000"; + extraConfig = '' + proxy_connect_timeout 300; + chunked_transfer_encoding off; + ''; + }; + }; + + "minio.${domain}" = defaultOpts // { + extraConfig = '' + # Allow special characters in headers + ignore_invalid_headers off; + # Allow any size file to be uploaded. + # Set to a value such as 1000m; to restrict file size to a specific value + client_max_body_size 0; + # Disable buffering + proxy_buffering off; + proxy_request_buffering off; + ''; + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://127.0.0.1:9003"; + extraConfig = '' + # This is necessary to pass the correct IP to be hashed + real_ip_header X-Real-IP; + proxy_connect_timeout 300; + chunked_transfer_encoding off; + ''; + }; + }; + + "mta-sts.${domain}" = defaultOpts // { + extraConfig = '' + ssl_early_data on; + ''; + locations."= /.well-known/mta-sts.txt".return = ''200 "${ + lib.strings.concatStringsSep "\\n" [ + "version: STSv1" + "mode: enforce" + "mx: mail.${domain}" + "max_age: 86400" + ] + }"''; + }; + + "immich.${domain}" = defaultOpts // { + locations."/" = { + proxyWebsockets = true; + proxyPass = "http://${config.services.immich.host}:${builtins.toString config.services.immich.port}"; + }; + + extraConfig = '' + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + }; + + "nixbin.${domain}" = defaultOpts // { + extraConfig = '' + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + + locations = { + "= /files".return = "301 https://nixbin.${domain}/files/"; + "/files/" = { + alias = "/nix/store/"; + extraConfig = "autoindex on;"; + }; + + "= /" = { + extraConfig = '' + add_header Content-Type text/html; + add_header Alt-Svc 'h3=":443"; ma=2592000; persist=1'; + ''; + return = '' + 200 + ' + + + + Nix Cache + + +
+

+ ❄️ Nix Cache +

+

+ Public Key: nixbin.sinanmohd.com:dXV3KDPVrm+cGJ2M1ZmTeQJqFGaEapqiVoWHgYDh03k= +

+
+ + ' + ''; + }; + + "/".proxyPass = + "http://${config.services.nix-serve.bindAddress}:${toString config.services.nix-serve.port}"; + }; + }; + + "www.alinafs.com" = defaultOpts // { + useACMEHost = null; + enableACME = true; + globalRedirect = "alinafs.com/home"; + extraConfig = '' + ssl_early_data on; + ''; + }; + "alinafs.com" = defaultOpts // { + useACMEHost = null; + enableACME = true; + + locations = { + "/metrics".return = "307 /home/"; + "/" = { + proxyWebsockets = true; + proxyPass = "http://127.0.0.1:${builtins.toString config.services.alina.port}"; + }; + }; + + extraConfig = '' + proxy_buffering off; + proxy_request_buffering off; + client_max_body_size 0; + ''; + }; + }; + }; +} diff --git a/os/kay/modules/iperf3.nix b/os/kay/modules/iperf3.nix deleted file mode 100644 index 2c8afef..0000000 --- a/os/kay/modules/iperf3.nix +++ /dev/null @@ -1,10 +0,0 @@ -{ ... }: - -{ - services.iperf3 = { - enable = true; - - bind = "192.168.43.1"; - openFirewall = true; - }; -} diff --git a/os/kay/modules/mail.nix b/os/kay/modules/mail.nix deleted file mode 100644 index 685461f..0000000 --- a/os/kay/modules/mail.nix +++ /dev/null @@ -1,173 +0,0 @@ -{ config, pkgs, ... }: -let - ipv6 = "2001:470:ee65::1337"; - domain = config.global.userdata.domain; - username = config.global.userdata.name; - email = [ - "${username}@${domain}" - - # used by github automation - # https://github.com/nocodb/nocodb/blob/32826d4b24e9285b898bb3547fdf550f81c930bb/nix/bumper/bumper.sh#L5 - "auto@${domain}" - # used by mail.sinanmohd.com - "postmaster@${domain}" - # used by ns1.sinanmohd.com - "hostmaster@${domain}" - ]; - - credentials_directory = "/run/credentials/stalwart-mail.service"; -in -{ - security.acme.certs.${domain}.postRun = "systemctl restart stalwart-mail.service"; - sops.secrets = { - "mail.${domain}/dkim_rsa" = { }; - "mail.${domain}/dkim_ed25519" = { }; - "mail.${domain}/password" = { }; - }; - - systemd.services.stalwart-mail.serviceConfig.LoadCredential = [ - "password:${config.sops.secrets."mail.${domain}/password".path}" - - "dkim_rsa:${config.sops.secrets."mail.${domain}/dkim_rsa".path}" - "dkim_ed25519:${config.sops.secrets."mail.${domain}/dkim_ed25519".path}" - - "cert:${config.security.acme.certs.${domain}.directory}/fullchain.pem" - "key:${config.security.acme.certs.${domain}.directory}/key.pem" - ]; - - services.postgresql = { - ensureDatabases = [ "stalwart" ]; - ensureUsers = [ - { - name = "stalwart"; - ensureDBOwnership = true; - } - ]; - }; - - services.stalwart-mail = { - enable = true; - openFirewall = true; - - settings = { - queue.outbound = { - ip-strategy = "ipv6_then_ipv4"; - source-ip.v6 = "['${ipv6}']"; - tls.starttls = "optional"; - }; - http.url = "'https://stalwart.${domain}'"; - - server = { - hostname = "mail.${domain}"; - listener = { - smtp = { - bind = [ - "[${ipv6}]:25" - "0.0.0.0:25" - ]; - protocol = "smtp"; - }; - submission = { - bind = "[::]:587"; - protocol = "smtp"; - }; - submissions = { - bind = "[::]:465"; - protocol = "smtp"; - tls.implicit = true; - }; - imaptls = { - bind = "[::]:993"; - protocol = "imap"; - tls.implicit = true; - }; - http = { - bind = "[::]:8085"; - protocol = "http"; - }; - }; - }; - - signature = { - rsa = { - private-key = "%{file:${credentials_directory}/dkim_rsa}%"; - inherit domain; - selector = "rsa"; - headers = [ - "From" - "To" - "Date" - "Subject" - "Message-ID" - ]; - algorithm = "rsa-sha-256"; - canonicalization = "simple/simple"; - - set-body-length = true; - expire = "2d"; - report = true; - }; - ed25519 = { - private-key = "%{file:${credentials_directory}/dkim_ed25519}%"; - inherit domain; - selector = "ed25519"; - headers = [ - "From" - "To" - "Date" - "Subject" - "Message-ID" - ]; - algorithm = "ed25519-sha256"; - canonicalization = "simple/simple"; - - set-body-length = true; - expire = "2d"; - report = true; - }; - }; - - certificate."default" = { - cert = "%{file:${credentials_directory}/cert}%"; - private-key = "%{file:${credentials_directory}/key}%"; - }; - - storage = { - data = "postgresql"; - fts = "postgresql"; - blob = "postgresql"; - lookup = "postgresql"; - directory = "memory"; - }; - store.postgresql = { - type = "postgresql"; - host = "localhost"; - database = "stalwart"; - user = "stalwart"; - timeout = "15s"; - tls.enable = false; - pool.max-connections = 10; - }; - - directory."memory" = { - type = "memory"; - - principals = [ - { - class = "admin"; - name = "${username}@${domain}"; - secret = "%{file:${credentials_directory}/password}%"; - inherit email; - } - { - # for mta-sts & dmarc reports - class = "individual"; - name = "reports@${domain}"; - secret = "%{file:${credentials_directory}/password}%"; - email = [ "reports@${domain}" ]; - } - ]; - }; - }; - }; -} diff --git a/os/kay/modules/matrix/default.nix b/os/kay/modules/matrix/default.nix deleted file mode 100644 index 1b9564d..0000000 --- a/os/kay/modules/matrix/default.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ config, ... }: -let - domain = config.global.userdata.domain; -in -{ - imports = [ - ./dendrite.nix - ./matrix-sliding-sync.nix - ]; - - sops.secrets."matrix-${domain}/sliding_sync" = { }; - - services.matrix-sliding-sync-dirty = { - enable = true; - environmentFile = config.sops.secrets."matrix-${domain}/sliding_sync".path; - - settings = { - SYNCV3_LOG_LEVEL = "warn"; - SYNCV3_SERVER = "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; - }; - }; -} diff --git a/os/kay/modules/matrix/dendrite.nix b/os/kay/modules/matrix/dendrite.nix deleted file mode 100644 index e66c5a5..0000000 --- a/os/kay/modules/matrix/dendrite.nix +++ /dev/null @@ -1,109 +0,0 @@ -{ config, ... }: - -let - domain = config.global.userdata.domain; - database = { - connection_string = "postgres:///dendrite?host=/run/postgresql"; - max_open_conns = 90; - max_idle_conns = 5; - conn_max_lifetime = -1; - }; -in -{ - sops.secrets."matrix-${domain}/key" = { }; - systemd.services.dendrite.after = [ "postgresql.service" ]; - - services = { - postgresql = { - ensureDatabases = [ "dendrite" ]; - ensureUsers = [ - { - name = "dendrite"; - ensureDBOwnership = true; - } - ]; - }; - - dendrite = { - enable = true; - loadCredential = [ - "private_key:${config.sops.secrets."matrix-${domain}/key".path}" - ]; - - settings = { - sync_api.search = { - enabled = true; - index_path = "/var/lib/dendrite/searchindex"; - }; - global = { - metrics.enabled = true; - server_name = domain; - private_key = "$CREDENTIALS_DIRECTORY/private_key"; - trusted_third_party_id_servers = [ - "matrix.org" - "vector.im" - ]; - inherit database; - }; - logging = [ - { - type = "std"; - level = "warn"; - } - ]; - mscs = { - inherit database; - mscs = [ "msc2836" ]; - }; - sync_api = { - inherit database; - real_ip_header = "X-Real-IP"; - }; - media_api = { - inherit database; - dynamic_thumbnails = true; - max_file_size_bytes = 12800000000; - }; - federation_api = { - inherit database; - send_max_retries = 8; - key_perspectives = [ - { - server_name = "matrix.org"; - keys = [ - { - key_id = "ed25519:auto"; - public_key = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; - } - { - key_id = "ed25519:a_RXGa"; - public_key = "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ"; - } - ]; - } - ]; - }; - - app_service_api = { - inherit database; - }; - room_server = { - inherit database; - }; - push_server = { - inherit database; - }; - relay_api = { - inherit database; - }; - key_server = { - inherit database; - }; - user_api = { - account_database = database; - device_database = database; - }; - }; - }; - }; -} diff --git a/os/kay/modules/matrix/matrix-sliding-sync.nix b/os/kay/modules/matrix/matrix-sliding-sync.nix deleted file mode 100644 index 63d95ad..0000000 --- a/os/kay/modules/matrix/matrix-sliding-sync.nix +++ /dev/null @@ -1,123 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: - -let - cfg = config.services.matrix-sliding-sync-dirty; - matrix-sliding-sync = pkgs.callPackage ../../pkgs/matrix-sliding-sync.nix { }; -in -{ - imports = [ - (lib.mkRenamedOptionModule - [ "services" "matrix-synapse" "sliding-sync" ] - [ "services" "matrix-sliding-sync" ] - ) - ]; - - options.services.matrix-sliding-sync-dirty = { - enable = lib.mkEnableOption "sliding sync"; - - settings = lib.mkOption { - type = lib.types.submodule { - freeformType = with lib.types; attrsOf str; - options = { - SYNCV3_SERVER = lib.mkOption { - type = lib.types.str; - description = '' - The destination homeserver to talk to not including `/_matrix/` e.g `https://matrix.example.org`. - ''; - }; - - SYNCV3_DB = lib.mkOption { - type = lib.types.str; - default = "postgresql:///matrix-sliding-sync?host=/run/postgresql"; - description = '' - The postgres connection string. - Refer to . - ''; - }; - - SYNCV3_BINDADDR = lib.mkOption { - type = lib.types.str; - default = "127.0.0.1:8009"; - example = "[::]:8008"; - description = "The interface and port or path (for unix socket) to listen on."; - }; - - SYNCV3_LOG_LEVEL = lib.mkOption { - type = lib.types.enum [ - "trace" - "debug" - "info" - "warn" - "error" - "fatal" - ]; - default = "info"; - description = "The level of verbosity for messages logged."; - }; - }; - }; - default = { }; - description = '' - Freeform environment variables passed to the sliding sync proxy. - Refer to for all supported values. - ''; - }; - - createDatabase = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - Whether to enable and configure `services.postgres` to ensure that the database user `matrix-sliding-sync` - and the database `matrix-sliding-sync` exist. - ''; - }; - - environmentFile = lib.mkOption { - type = lib.types.str; - description = '' - Environment file as defined in {manpage}`systemd.exec(5)`. - - This must contain the {env}`SYNCV3_SECRET` variable which should - be generated with {command}`openssl rand -hex 32`. - ''; - }; - }; - - config = lib.mkIf cfg.enable { - services.postgresql = lib.optionalAttrs cfg.createDatabase { - enable = true; - ensureDatabases = [ "matrix-sliding-sync" ]; - ensureUsers = [ - { - name = "matrix-sliding-sync"; - ensureDBOwnership = true; - } - ]; - }; - - systemd.services.matrix-sliding-sync = rec { - after = - lib.optional cfg.createDatabase "postgresql.service" - ++ lib.optional config.services.dendrite.enable "dendrite.service" - ++ lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; - wants = after; - wantedBy = [ "multi-user.target" ]; - environment = cfg.settings; - serviceConfig = { - DynamicUser = true; - EnvironmentFile = cfg.environmentFile; - ExecStart = lib.getExe matrix-sliding-sync; - StateDirectory = "matrix-sliding-sync"; - WorkingDirectory = "%S/matrix-sliding-sync"; - RuntimeDirectory = "matrix-sliding-sync"; - Restart = "on-failure"; - RestartSec = "1s"; - }; - }; - }; -} diff --git a/os/kay/modules/minio.nix b/os/kay/modules/minio.nix deleted file mode 100644 index d440e50..0000000 --- a/os/kay/modules/minio.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -let - email = config.global.userdata.email; -in -{ - sops.secrets."misc/default_password" = { }; - systemd.services.minio.serviceConfig.LoadCredential = [ - "password:${config.sops.secrets."misc/default_password".path}" - ]; - - services.minio = { - enable = true; - consoleAddress = ":9003"; - - package = pkgs.stdenv.mkDerivation { - name = "minio-with-secrets"; - dontUnpack = true; - buildInputs = with pkgs; [ - makeWrapper - minio - ]; - installPhase = '' - mkdir -p $out/bin - makeWrapper ${lib.getExe pkgs.minio} $out/bin/minio \ - --run 'echo "Seting Minio Secrets"' \ - --set MINIO_ROOT_USER ${email} \ - --run 'export MINIO_ROOT_PASSWORD="$(cat "$CREDENTIALS_DIRECTORY"/password)"' - ''; - }; - }; -} diff --git a/os/kay/modules/network.nix b/os/kay/modules/network.nix deleted file mode 100644 index 1315289..0000000 --- a/os/kay/modules/network.nix +++ /dev/null @@ -1,70 +0,0 @@ -{ config, ... }: - -let - inetVlan = 1003; - wanInterface = "enp3s0"; - nameServer = [ - "1.0.0.1" - "1.1.1.1" - ]; -in -{ - imports = [ - ./router.nix - ./hurricane.nix - ]; - - sops.secrets = { - "ppp/chap-secrets" = { }; - "ppp/pap-secrets" = { }; - "ppp/username" = { }; - }; - - networking = { - tempAddresses = "disabled"; - vlans.wan = { - id = inetVlan; - interface = wanInterface; - }; - }; - - services = { - dnsmasq = { - enable = true; - settings = { - server = nameServer; - bind-interfaces = true; - }; - }; - - pppd = { - enable = true; - - config = '' - plugin pppoe.so - debug - - nic-wan - defaultroute - ipv6 ::1, - noauth - - persist - lcp-echo-adaptive - lcp-echo-interval 1 - lcp-echo-failure 5 - ''; - - peers.keralavision = { - enable = true; - autostart = true; - configFile = config.sops.secrets."ppp/username".path; - }; - - secret = { - chap = config.sops.secrets."ppp/chap-secrets".path; - pap = config.sops.secrets."ppp/pap-secrets".path; - }; - }; - }; -} diff --git a/os/kay/modules/network/default.nix b/os/kay/modules/network/default.nix new file mode 100644 index 0000000..56371c7 --- /dev/null +++ b/os/kay/modules/network/default.nix @@ -0,0 +1,72 @@ +{ config, ... }: + +let + inetVlan = 1003; + wanInterface = "enp3s0"; + nameServer = [ + "1.0.0.1" + "1.1.1.1" + ]; +in +{ + imports = [ + ./router.nix + ./hurricane.nix + ./wireguard.nix + ./headscale.nix + ]; + + sops.secrets = { + "ppp/chap-secrets" = { }; + "ppp/pap-secrets" = { }; + "ppp/username" = { }; + }; + + networking = { + tempAddresses = "disabled"; + vlans.wan = { + id = inetVlan; + interface = wanInterface; + }; + }; + + services = { + dnsmasq = { + enable = true; + settings = { + server = nameServer; + bind-interfaces = true; + }; + }; + + pppd = { + enable = true; + + config = '' + plugin pppoe.so + debug + + nic-wan + defaultroute + ipv6 ::1, + noauth + + persist + lcp-echo-adaptive + lcp-echo-interval 1 + lcp-echo-failure 5 + ''; + + peers.keralavision = { + enable = true; + autostart = true; + configFile = config.sops.secrets."ppp/username".path; + }; + + secret = { + chap = config.sops.secrets."ppp/chap-secrets".path; + pap = config.sops.secrets."ppp/pap-secrets".path; + }; + }; + }; +} diff --git a/os/kay/modules/network/headscale.nix b/os/kay/modules/network/headscale.nix new file mode 100644 index 0000000..24df170 --- /dev/null +++ b/os/kay/modules/network/headscale.nix @@ -0,0 +1,112 @@ +{ + config, + pkgs, + lib, + ... +}: +let + domain = "headscale.${config.global.userdata.domain}"; + stunPort = 3478; + + # A workaround generate a valid Headscale config accepted by Headplane when `config_strict == true`. + settings = lib.recursiveUpdate config.services.headscale.settings { + tls_cert_path = "/dev/null"; + tls_key_path = "/dev/null"; + policy.path = "/dev/null"; + }; + format = pkgs.formats.yaml { }; + headscaleConfig = format.generate "headscale.yml" settings; + + policyFormat = pkgs.formats.json { }; + policy = { + groups = { + "group:owner" = [ "sinan@" ]; + "group:bud" = [ + "sinan@" + "ann@" + ]; + }; + tagOwners = { + "tag:bud_clients" = [ "group:bud" ]; + "tag:internal" = [ "group:owner" ]; + "tag:cusat" = [ "group:owner" ]; + "tag:gaijin" = [ "group:owner" ]; + }; + acls = [ + { + action = "accept"; + src = [ "group:owner" ]; + dst = [ "*:*" ]; + } + + { + action = "accept"; + src = [ "group:bud" ]; + dst = [ "tag:bud_clients:*" ]; + } + ]; + }; +in +{ + sops.secrets = { + "headplane/cookie_secret".owner = config.services.headscale.user; + "headplane/preauth_key".owner = config.services.headscale.user; + "headscale/noise_private_key".owner = config.services.headscale.user; + "headscale/derp_private_key".owner = config.services.headscale.user; + }; + + networking.firewall.interfaces.ppp0.allowedUDPPorts = [ stunPort ]; + + services = { + headscale = { + enable = true; + port = 8139; + + settings = { + logtail.enabled = false; + server_url = "https://${domain}"; + noise.private_key_path = config.sops.secrets."headscale/noise_private_key".path; + dns = { + base_domain = "tsnet.${config.global.userdata.domain}"; + override_local_dns = false; + }; + derp = { + server = { + enabled = true; + private_key_path = config.sops.secrets."headscale/derp_private_key".path; + region_code = config.networking.hostName; + region_name = config.networking.hostName; + stun_listen_addr = "0.0.0.0:${toString stunPort}"; + region_id = 6969; + automatically_add_embedded_derp_region = true; + }; + urls = [ ]; + }; + policy = { + mode = "file"; + path = policyFormat.generate "acl.json" policy; + }; + }; + }; + + headplane = { + enable = true; + settings = { + server = { + port = 8140; + cookie_secret_path = config.sops.secrets."headplane/cookie_secret".path; + }; + headscale = { + url = "https://${domain}"; + config_path = "${headscaleConfig}"; + }; + integration.agent = { + enabled = true; + pre_authkey_path = config.sops.secrets."headplane/preauth_key".path; + }; + }; + }; + }; + + environment.systemPackages = [ config.services.headscale.package ]; +} diff --git a/os/kay/modules/network/hurricane.nix b/os/kay/modules/network/hurricane.nix new file mode 100644 index 0000000..e815136 --- /dev/null +++ b/os/kay/modules/network/hurricane.nix @@ -0,0 +1,132 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + iface = "hurricane"; + remote = "216.218.221.42"; + + clinet = "2001:470:35:72a::2"; + server = "2001:470:35:72a::1"; + + prefix64 = "2001:470:36:72a::/64"; + prefix48 = "2001:470:ee65::/48"; + + makeAddr = + prefix: host: + let + split = lib.strings.splitString "/" prefix; + in + { + address = "${lib.head split}${host}"; + prefixLength = lib.toInt (lib.last split); + }; +in +{ + networking = { + sits.${iface} = { + inherit remote; + ttl = 225; + }; + interfaces.${iface} = { + mtu = 1472; # 1492(ppp0) - 20 + ipv6.addresses = [ + { + address = clinet; + prefixLength = 64; + } + + (makeAddr prefix64 "1") + (makeAddr prefix48 "1") + (makeAddr prefix48 "1337") + ]; + }; + + iproute2 = { + enable = true; + rttablesExtraConfig = "200 hurricane"; + }; + + firewall = { + extraCommands = "iptables -A INPUT --proto 41 --source ${remote} --jump ACCEPT"; + extraStopCommands = "iptables -D INPUT --proto 41 --source ${remote} --jump ACCEPT"; + }; + }; + + sops.secrets = { + "hurricane/username" = { }; + "hurricane/update_key" = { }; + "hurricane/tunnel_id" = { }; + }; + + systemd.services."network-route-${iface}" = { + description = "Routing configuration of ${iface}"; + wantedBy = [ + "network-setup.service" + "network.target" + ]; + before = [ "network-setup.service" ]; + bindsTo = [ "network-addresses-hurricane.service" ]; + after = [ + "network-pre.target" + "network-addresses-hurricane.service" + ]; + # restart rather than stop+start this unit to prevent the + # network from dying during switch-to-configuration. + stopIfChanged = false; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + path = [ pkgs.iproute2 ]; + script = '' + echo -n "adding route" + + ip -6 rule add from ${clinet}/64 table hurricane || exit 1 + ip -6 rule add from ${prefix64} table hurricane || exit 1 + ip -6 rule add from ${prefix48} table hurricane || exit 1 + + ip -6 route add default via ${server} dev hurricane table hurricane || exit 1 + ''; + preStop = '' + echo -n "deleting route" + + ip -6 route del default via ${server} dev hurricane table hurricane || exit 1 + + ip -6 rule del from ${prefix48} table hurricane || exit 1 + ip -6 rule del from ${prefix64} table hurricane || exit 1 + ip -6 rule del from ${clinet}/64 table hurricane || exit 1 + ''; + }; + + services.pppd.script."01-${iface}" = { + runtimeInputs = with pkgs; [ + curl + coreutils + iproute2 + iputils + ]; + text = '' + wan_ip="$4" + username="$(cat ${config.sops.secrets."hurricane/username".path})" + update_key="$(cat ${config.sops.secrets."hurricane/update_key".path})" + tunnel_id="$(cat ${config.sops.secrets."hurricane/tunnel_id".path})" + + auth_url="https://$username:$update_key@ipv4.tunnelbroker.net/nic/update?hostname=$tunnel_id" + until curl --silent "$auth_url"; do + sleep 1 + done + + while [ ! -e /sys/class/net/${iface} ]; do + sleep 1 # make sure ${iface} is up + done + + ip tunnel change ${iface} local "$wan_ip" mode sit + ''; + }; +} diff --git a/os/kay/modules/network/router.nix b/os/kay/modules/network/router.nix new file mode 100644 index 0000000..aeb008c --- /dev/null +++ b/os/kay/modules/network/router.nix @@ -0,0 +1,72 @@ +{ ... }: +let + wanInterface = "ppp0"; + + gponInterface = "enp3s0"; + gponHost = "192.168.38.1"; + gponPrefix = 24; + + lanInterface = "enp8s0f3u1c2"; + bridgeInterface = "lan"; + subnet = "192.168.43.0"; + prefix = 24; + host = "192.168.43.1"; + leaseRangeStart = "192.168.43.100"; + leaseRangeEnd = "192.168.43.254"; + + wapMac = "40:86:cb:d7:40:49"; + wapIp = "192.168.43.2"; +in +{ + networking = { + bridges.${bridgeInterface}.interfaces = [ lanInterface ]; + + nat = { + enable = true; + externalInterface = wanInterface; + internalInterfaces = [ bridgeInterface ]; + }; + interfaces = { + ${bridgeInterface}.ipv4.addresses = [ + { + address = host; + prefixLength = prefix; + } + ]; + ${gponInterface}.ipv4.addresses = [ + { + address = gponHost; + prefixLength = gponPrefix; + } + ]; + }; + firewall = { + allowedUDPPorts = [ + 53 + 67 + ]; + allowedTCPPorts = [ 53 ]; + extraCommands = '' + iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ + -o ${wanInterface} \ + -j TCPMSS --clamp-mss-to-pmtu + ''; + extraStopCommands = '' + iptables -t mangle -D FORWARD -p tcp --tcp-flags SYN,RST SYN \ + -o ${wanInterface} \ + -j TCPMSS --clamp-mss-to-pmtu + ''; + }; + }; + + services.dnsmasq.settings = { + dhcp-range = [ "${leaseRangeStart},${leaseRangeEnd}" ]; + dhcp-host = "${wapMac},${wapIp}"; + interface = [ bridgeInterface ]; + }; + + services.prometheus.exporters.dnsmasq = { + enable = true; + listenAddress = "127.0.0.1"; + }; +} diff --git a/os/kay/modules/network/wireguard.nix b/os/kay/modules/network/wireguard.nix new file mode 100644 index 0000000..fd00804 --- /dev/null +++ b/os/kay/modules/network/wireguard.nix @@ -0,0 +1,71 @@ +{ + config, + pkgs, + lib, + ... +}: +let + wgInterface = "wg"; + wanInterface = "ppp0"; + port = 51820; + + wgConf = pkgs.writeText "wg.conf" '' + [interface] + Address = 10.0.1.1/24 + MTU = 1412 + ListenPort = 51820 + PostUp = ${ + lib.getExe ( + pkgs.writeShellApplication { + name = "wg_set_key"; + runtimeInputs = with pkgs; [ wireguard-tools ]; + text = '' + wg set ${wgInterface} private-key <(cat ${config.sops.secrets."misc/wireguard".path}) + ''; + } + ) + } + + [Peer] + # friendly_name = cez + PublicKey = IcMpAs/D0u8O/AcDBPC7pFUYSeFQXQpTqHpGOeVpjS8= + AllowedIPs = 10.0.1.2/32 + + [Peer] + # friendly_name = exy + PublicKey = bJ9aqGYD2Jh4MtWIL7q3XxVHFuUdwGJwO8p7H3nNPj8= + AllowedIPs = 10.0.1.3/32 + + [Peer] + # friendly_name = dad + PublicKey = q70IyOS2IpubIRWqo5sL3SeEjtUy2V/PT8yqVExiHTQ= + AllowedIPs = 10.0.1.4/32 + ''; +in +{ + sops.secrets."misc/wireguard" = { }; + + networking = { + nat = { + enable = true; + externalInterface = wanInterface; + internalInterfaces = [ wgInterface ]; + }; + + firewall.allowedUDPPorts = [ port ]; + wg-quick.interfaces.${wgInterface}.configFile = builtins.toString wgConf; + }; + + services.dnsmasq.settings = { + no-dhcp-interface = wgInterface; + interface = [ wgInterface ]; + }; + + services.prometheus.exporters.wireguard = { + enable = true; + withRemoteIp = true; + wireguardConfig = builtins.toString wgConf; + singleSubnetPerField = true; + listenAddress = "127.0.0.1"; + }; +} diff --git a/os/kay/modules/nix-cache.nix b/os/kay/modules/nix-cache.nix deleted file mode 100644 index 9c81b56..0000000 --- a/os/kay/modules/nix-cache.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, ... }: -let - keyname = "misc/nixbin.${config.global.userdata.domain}"; -in -{ - sops.secrets.${keyname} = { }; - - services.nix-serve = { - enable = true; - secretKeyFile = config.sops.secrets.${keyname}.path; - }; -} diff --git a/os/kay/modules/postgresql.nix b/os/kay/modules/postgresql.nix deleted file mode 100644 index 6ba5398..0000000 --- a/os/kay/modules/postgresql.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -{ - services.postgresql = { - enable = true; - package = with pkgs; postgresql_15; - authentication = lib.mkForce '' - #type database DBuser origin-address auth-method - # unix socket - local all all trust - # ipv4 - host all all 127.0.0.1/32 trust - # ipv6 - host all all ::1/128 trust - ''; - - settings.log_timezone = config.time.timeZone; - }; - - services.prometheus.exporters.postgres = { - enable = true; - listenAddress = "127.0.0.1"; - }; -} diff --git a/os/kay/modules/router.nix b/os/kay/modules/router.nix deleted file mode 100644 index 7280401..0000000 --- a/os/kay/modules/router.nix +++ /dev/null @@ -1,77 +0,0 @@ -{ ... }: -let - wanInterface = "ppp0"; - - gponInterface = "enp3s0"; - gponHost = "192.168.38.1"; - gponPrefix = 24; - - lanInterface = "enp8s0f3u1c2"; - bridgeInterface = "lan"; - subnet = "192.168.43.0"; - prefix = 24; - host = "192.168.43.1"; - leaseRangeStart = "192.168.43.100"; - leaseRangeEnd = "192.168.43.254"; - - wapMac = "40:86:cb:d7:40:49"; - wapIp = "192.168.43.2"; -in -{ - imports = [ - ./wireguard.nix - ./iperf3.nix - ]; - - networking = { - bridges.${bridgeInterface}.interfaces = [ lanInterface ]; - - nat = { - enable = true; - externalInterface = wanInterface; - internalInterfaces = [ bridgeInterface ]; - }; - interfaces = { - ${bridgeInterface}.ipv4.addresses = [ - { - address = host; - prefixLength = prefix; - } - ]; - ${gponInterface}.ipv4.addresses = [ - { - address = gponHost; - prefixLength = gponPrefix; - } - ]; - }; - firewall = { - allowedUDPPorts = [ - 53 - 67 - ]; - allowedTCPPorts = [ 53 ]; - extraCommands = '' - iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ - -o ${wanInterface} \ - -j TCPMSS --clamp-mss-to-pmtu - ''; - extraStopCommands = '' - iptables -t mangle -D FORWARD -p tcp --tcp-flags SYN,RST SYN \ - -o ${wanInterface} \ - -j TCPMSS --clamp-mss-to-pmtu - ''; - }; - }; - - services.dnsmasq.settings = { - dhcp-range = [ "${leaseRangeStart},${leaseRangeEnd}" ]; - dhcp-host = "${wapMac},${wapIp}"; - interface = [ bridgeInterface ]; - }; - - services.prometheus.exporters.dnsmasq = { - enable = true; - listenAddress = "127.0.0.1"; - }; -} diff --git a/os/kay/modules/services/alina.nix b/os/kay/modules/services/alina.nix new file mode 100644 index 0000000..c567953 --- /dev/null +++ b/os/kay/modules/services/alina.nix @@ -0,0 +1,30 @@ +{ config, alina, ... }: +let + domain = "alinafs.com"; +in +{ + imports = [ alina.nixosModules.alina ]; + + sops.secrets."misc/alina" = { }; + + services.postgresql = { + ensureDatabases = [ "alina" ]; + ensureUsers = [ + { + name = "alina"; + ensureDBOwnership = true; + } + ]; + }; + + services.alina = { + enable = true; + port = 8006; + environmentFile = config.sops.secrets."misc/alina".path; + settings.server = { + data = "/hdd/alina"; + file_size_limit = 1024 * 1024 * 1024; # 1GB + public_url = "https://${domain}"; + }; + }; +} diff --git a/os/kay/modules/services/cgit.nix b/os/kay/modules/services/cgit.nix new file mode 100644 index 0000000..254cc80 --- /dev/null +++ b/os/kay/modules/services/cgit.nix @@ -0,0 +1,34 @@ +{ config, pkgs, ... }: + +let + domain = config.global.userdata.domain; + user = config.global.userdata.name; +in +{ + users.users.${user}.packages = with pkgs; [ git ]; + environment.systemPackages = with pkgs; [ + luajitPackages.luaossl + lua52Packages.luaossl + ]; + + services.cgit."git.${domain}" = { + enable = true; + nginx.virtualHost = "git.${domain}"; + scanPath = "/var/lib/git"; + settings = { + project-list = "/var/lib/git/project.list"; + remove-suffix = 1; + enable-commit-graph = 1; + root-title = "${user}'s git repository"; + root-desc = "how do i learn github anon"; + source-filter = "${pkgs.cgit}/lib/cgit/filters/syntax-highlighting.py"; + about-filter = "${pkgs.cgit}/lib/cgit/filters/about-formatting.sh"; + readme = ":README.md"; + footer = ""; + enable-blame = 1; + clone-url = "https://git.${domain}/$CGIT_REPO_URL"; + enable-log-filecount = 1; + enable-log-linecount = 1; + }; + }; +} diff --git a/os/kay/modules/services/github-runner.nix b/os/kay/modules/services/github-runner.nix new file mode 100644 index 0000000..dd4d48d --- /dev/null +++ b/os/kay/modules/services/github-runner.nix @@ -0,0 +1,41 @@ +{ config, ... }: +let + repo = "nocodb/nocodb"; + nocodbRunnerUser = "nocodbrunner"; + user = config.global.userdata.name; +in +{ + sops.secrets = { + "github-runner/nocodb-registration-token" = { }; + "github-runner/age-master-key" = { }; + }; + + # required by github:nocodb/nocodb docker builds + virtualisation.docker.enable = true; + users.groups.${nocodbRunnerUser} = { }; + users.extraGroups.docker.members = [ + user + nocodbRunnerUser + ]; + users.users.nocodbrunner = { + name = nocodbRunnerUser; + group = nocodbRunnerUser; + isSystemUser = true; + }; + services.github-runners.kay = { + user = nocodbRunnerUser; + group = nocodbRunnerUser; + enable = true; + noDefaultLabels = true; + extraLabels = [ "nix" ]; + tokenFile = config.sops.secrets."github-runner/nocodb-registration-token".path; + url = "https://github.com/${repo}"; + }; + + systemd.services."github-runner-kay" = { + environment.SOPS_AGE_KEY_FILE = "%d/age-master-key"; + serviceConfig.LoadCredential = "age-master-key:${ + config.sops.secrets."github-runner/age-master-key".path + }"; + }; +} diff --git a/os/kay/modules/services/home-assistant.nix b/os/kay/modules/services/home-assistant.nix new file mode 100644 index 0000000..65807f7 --- /dev/null +++ b/os/kay/modules/services/home-assistant.nix @@ -0,0 +1,47 @@ +{ pkgs, ... }: +{ + services.postgresql = { + enable = true; + + ensureDatabases = [ "hass" ]; + ensureUsers = [ + { + name = "hass"; + ensureDBOwnership = true; + } + ]; + }; + + services.home-assistant = { + enable = true; + package = + (pkgs.home-assistant.override { + extraPackages = py: with py; [ psycopg2 ]; + }).overrideAttrs + (oldAttrs: { + doInstallCheck = false; + }); + + extraComponents = [ + "analytics" + "google_translate" + "met" + "radio_browser" + "shopping_list" + "tplink" + "tuya" + "utility_meter" + ]; + + config = { + default_config = { }; + + recorder.db_url = "postgresql://@/hass"; + http = { + server_host = "127.0.0.1"; + trusted_proxies = [ "127.0.0.1" ]; + use_x_forwarded_for = true; + }; + }; + }; +} diff --git a/os/kay/modules/services/immich.nix b/os/kay/modules/services/immich.nix new file mode 100644 index 0000000..5e5eaf4 --- /dev/null +++ b/os/kay/modules/services/immich.nix @@ -0,0 +1,23 @@ +{ config, ... }: +let + domain = config.global.userdata.domain; + mediaLocation = "/hdd/immich"; +in +{ + services.immich = { + enable = true; + inherit mediaLocation; + settings.server.externalDomain = "https://immich.${domain}"; + }; + + systemd.tmpfiles.settings.immich.${mediaLocation}.d = { + group = config.services.immich.group; + user = config.services.immich.user; + mode = "0755"; + }; + + users.users.immich.extraGroups = [ + "video" + "render" + ]; +} diff --git a/os/kay/modules/services/iperf3.nix b/os/kay/modules/services/iperf3.nix new file mode 100644 index 0000000..2c8afef --- /dev/null +++ b/os/kay/modules/services/iperf3.nix @@ -0,0 +1,10 @@ +{ ... }: + +{ + services.iperf3 = { + enable = true; + + bind = "192.168.43.1"; + openFirewall = true; + }; +} diff --git a/os/kay/modules/services/mail.nix b/os/kay/modules/services/mail.nix new file mode 100644 index 0000000..685461f --- /dev/null +++ b/os/kay/modules/services/mail.nix @@ -0,0 +1,173 @@ +{ config, pkgs, ... }: +let + ipv6 = "2001:470:ee65::1337"; + domain = config.global.userdata.domain; + username = config.global.userdata.name; + email = [ + "${username}@${domain}" + + # used by github automation + # https://github.com/nocodb/nocodb/blob/32826d4b24e9285b898bb3547fdf550f81c930bb/nix/bumper/bumper.sh#L5 + "auto@${domain}" + # used by mail.sinanmohd.com + "postmaster@${domain}" + # used by ns1.sinanmohd.com + "hostmaster@${domain}" + ]; + + credentials_directory = "/run/credentials/stalwart-mail.service"; +in +{ + security.acme.certs.${domain}.postRun = "systemctl restart stalwart-mail.service"; + sops.secrets = { + "mail.${domain}/dkim_rsa" = { }; + "mail.${domain}/dkim_ed25519" = { }; + "mail.${domain}/password" = { }; + }; + + systemd.services.stalwart-mail.serviceConfig.LoadCredential = [ + "password:${config.sops.secrets."mail.${domain}/password".path}" + + "dkim_rsa:${config.sops.secrets."mail.${domain}/dkim_rsa".path}" + "dkim_ed25519:${config.sops.secrets."mail.${domain}/dkim_ed25519".path}" + + "cert:${config.security.acme.certs.${domain}.directory}/fullchain.pem" + "key:${config.security.acme.certs.${domain}.directory}/key.pem" + ]; + + services.postgresql = { + ensureDatabases = [ "stalwart" ]; + ensureUsers = [ + { + name = "stalwart"; + ensureDBOwnership = true; + } + ]; + }; + + services.stalwart-mail = { + enable = true; + openFirewall = true; + + settings = { + queue.outbound = { + ip-strategy = "ipv6_then_ipv4"; + source-ip.v6 = "['${ipv6}']"; + tls.starttls = "optional"; + }; + http.url = "'https://stalwart.${domain}'"; + + server = { + hostname = "mail.${domain}"; + listener = { + smtp = { + bind = [ + "[${ipv6}]:25" + "0.0.0.0:25" + ]; + protocol = "smtp"; + }; + submission = { + bind = "[::]:587"; + protocol = "smtp"; + }; + submissions = { + bind = "[::]:465"; + protocol = "smtp"; + tls.implicit = true; + }; + imaptls = { + bind = "[::]:993"; + protocol = "imap"; + tls.implicit = true; + }; + http = { + bind = "[::]:8085"; + protocol = "http"; + }; + }; + }; + + signature = { + rsa = { + private-key = "%{file:${credentials_directory}/dkim_rsa}%"; + inherit domain; + selector = "rsa"; + headers = [ + "From" + "To" + "Date" + "Subject" + "Message-ID" + ]; + algorithm = "rsa-sha-256"; + canonicalization = "simple/simple"; + + set-body-length = true; + expire = "2d"; + report = true; + }; + ed25519 = { + private-key = "%{file:${credentials_directory}/dkim_ed25519}%"; + inherit domain; + selector = "ed25519"; + headers = [ + "From" + "To" + "Date" + "Subject" + "Message-ID" + ]; + algorithm = "ed25519-sha256"; + canonicalization = "simple/simple"; + + set-body-length = true; + expire = "2d"; + report = true; + }; + }; + + certificate."default" = { + cert = "%{file:${credentials_directory}/cert}%"; + private-key = "%{file:${credentials_directory}/key}%"; + }; + + storage = { + data = "postgresql"; + fts = "postgresql"; + blob = "postgresql"; + lookup = "postgresql"; + directory = "memory"; + }; + store.postgresql = { + type = "postgresql"; + host = "localhost"; + database = "stalwart"; + user = "stalwart"; + timeout = "15s"; + tls.enable = false; + pool.max-connections = 10; + }; + + directory."memory" = { + type = "memory"; + + principals = [ + { + class = "admin"; + name = "${username}@${domain}"; + secret = "%{file:${credentials_directory}/password}%"; + inherit email; + } + { + # for mta-sts & dmarc reports + class = "individual"; + name = "reports@${domain}"; + secret = "%{file:${credentials_directory}/password}%"; + email = [ "reports@${domain}" ]; + } + ]; + }; + }; + }; +} diff --git a/os/kay/modules/services/matrix/default.nix b/os/kay/modules/services/matrix/default.nix new file mode 100644 index 0000000..1b9564d --- /dev/null +++ b/os/kay/modules/services/matrix/default.nix @@ -0,0 +1,22 @@ +{ config, ... }: +let + domain = config.global.userdata.domain; +in +{ + imports = [ + ./dendrite.nix + ./matrix-sliding-sync.nix + ]; + + sops.secrets."matrix-${domain}/sliding_sync" = { }; + + services.matrix-sliding-sync-dirty = { + enable = true; + environmentFile = config.sops.secrets."matrix-${domain}/sliding_sync".path; + + settings = { + SYNCV3_LOG_LEVEL = "warn"; + SYNCV3_SERVER = "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; + }; + }; +} diff --git a/os/kay/modules/services/matrix/dendrite.nix b/os/kay/modules/services/matrix/dendrite.nix new file mode 100644 index 0000000..e66c5a5 --- /dev/null +++ b/os/kay/modules/services/matrix/dendrite.nix @@ -0,0 +1,109 @@ +{ config, ... }: + +let + domain = config.global.userdata.domain; + database = { + connection_string = "postgres:///dendrite?host=/run/postgresql"; + max_open_conns = 90; + max_idle_conns = 5; + conn_max_lifetime = -1; + }; +in +{ + sops.secrets."matrix-${domain}/key" = { }; + systemd.services.dendrite.after = [ "postgresql.service" ]; + + services = { + postgresql = { + ensureDatabases = [ "dendrite" ]; + ensureUsers = [ + { + name = "dendrite"; + ensureDBOwnership = true; + } + ]; + }; + + dendrite = { + enable = true; + loadCredential = [ + "private_key:${config.sops.secrets."matrix-${domain}/key".path}" + ]; + + settings = { + sync_api.search = { + enabled = true; + index_path = "/var/lib/dendrite/searchindex"; + }; + global = { + metrics.enabled = true; + server_name = domain; + private_key = "$CREDENTIALS_DIRECTORY/private_key"; + trusted_third_party_id_servers = [ + "matrix.org" + "vector.im" + ]; + inherit database; + }; + logging = [ + { + type = "std"; + level = "warn"; + } + ]; + mscs = { + inherit database; + mscs = [ "msc2836" ]; + }; + sync_api = { + inherit database; + real_ip_header = "X-Real-IP"; + }; + media_api = { + inherit database; + dynamic_thumbnails = true; + max_file_size_bytes = 12800000000; + }; + federation_api = { + inherit database; + send_max_retries = 8; + key_perspectives = [ + { + server_name = "matrix.org"; + keys = [ + { + key_id = "ed25519:auto"; + public_key = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + } + { + key_id = "ed25519:a_RXGa"; + public_key = "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ"; + } + ]; + } + ]; + }; + + app_service_api = { + inherit database; + }; + room_server = { + inherit database; + }; + push_server = { + inherit database; + }; + relay_api = { + inherit database; + }; + key_server = { + inherit database; + }; + user_api = { + account_database = database; + device_database = database; + }; + }; + }; + }; +} diff --git a/os/kay/modules/services/matrix/matrix-sliding-sync.nix b/os/kay/modules/services/matrix/matrix-sliding-sync.nix new file mode 100644 index 0000000..63d95ad --- /dev/null +++ b/os/kay/modules/services/matrix/matrix-sliding-sync.nix @@ -0,0 +1,123 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.matrix-sliding-sync-dirty; + matrix-sliding-sync = pkgs.callPackage ../../pkgs/matrix-sliding-sync.nix { }; +in +{ + imports = [ + (lib.mkRenamedOptionModule + [ "services" "matrix-synapse" "sliding-sync" ] + [ "services" "matrix-sliding-sync" ] + ) + ]; + + options.services.matrix-sliding-sync-dirty = { + enable = lib.mkEnableOption "sliding sync"; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = with lib.types; attrsOf str; + options = { + SYNCV3_SERVER = lib.mkOption { + type = lib.types.str; + description = '' + The destination homeserver to talk to not including `/_matrix/` e.g `https://matrix.example.org`. + ''; + }; + + SYNCV3_DB = lib.mkOption { + type = lib.types.str; + default = "postgresql:///matrix-sliding-sync?host=/run/postgresql"; + description = '' + The postgres connection string. + Refer to . + ''; + }; + + SYNCV3_BINDADDR = lib.mkOption { + type = lib.types.str; + default = "127.0.0.1:8009"; + example = "[::]:8008"; + description = "The interface and port or path (for unix socket) to listen on."; + }; + + SYNCV3_LOG_LEVEL = lib.mkOption { + type = lib.types.enum [ + "trace" + "debug" + "info" + "warn" + "error" + "fatal" + ]; + default = "info"; + description = "The level of verbosity for messages logged."; + }; + }; + }; + default = { }; + description = '' + Freeform environment variables passed to the sliding sync proxy. + Refer to for all supported values. + ''; + }; + + createDatabase = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to enable and configure `services.postgres` to ensure that the database user `matrix-sliding-sync` + and the database `matrix-sliding-sync` exist. + ''; + }; + + environmentFile = lib.mkOption { + type = lib.types.str; + description = '' + Environment file as defined in {manpage}`systemd.exec(5)`. + + This must contain the {env}`SYNCV3_SECRET` variable which should + be generated with {command}`openssl rand -hex 32`. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.postgresql = lib.optionalAttrs cfg.createDatabase { + enable = true; + ensureDatabases = [ "matrix-sliding-sync" ]; + ensureUsers = [ + { + name = "matrix-sliding-sync"; + ensureDBOwnership = true; + } + ]; + }; + + systemd.services.matrix-sliding-sync = rec { + after = + lib.optional cfg.createDatabase "postgresql.service" + ++ lib.optional config.services.dendrite.enable "dendrite.service" + ++ lib.optional config.services.matrix-synapse.enable config.services.matrix-synapse.serviceUnit; + wants = after; + wantedBy = [ "multi-user.target" ]; + environment = cfg.settings; + serviceConfig = { + DynamicUser = true; + EnvironmentFile = cfg.environmentFile; + ExecStart = lib.getExe matrix-sliding-sync; + StateDirectory = "matrix-sliding-sync"; + WorkingDirectory = "%S/matrix-sliding-sync"; + RuntimeDirectory = "matrix-sliding-sync"; + Restart = "on-failure"; + RestartSec = "1s"; + }; + }; + }; +} diff --git a/os/kay/modules/services/minio.nix b/os/kay/modules/services/minio.nix new file mode 100644 index 0000000..d440e50 --- /dev/null +++ b/os/kay/modules/services/minio.nix @@ -0,0 +1,36 @@ +{ + config, + lib, + pkgs, + ... +}: +let + email = config.global.userdata.email; +in +{ + sops.secrets."misc/default_password" = { }; + systemd.services.minio.serviceConfig.LoadCredential = [ + "password:${config.sops.secrets."misc/default_password".path}" + ]; + + services.minio = { + enable = true; + consoleAddress = ":9003"; + + package = pkgs.stdenv.mkDerivation { + name = "minio-with-secrets"; + dontUnpack = true; + buildInputs = with pkgs; [ + makeWrapper + minio + ]; + installPhase = '' + mkdir -p $out/bin + makeWrapper ${lib.getExe pkgs.minio} $out/bin/minio \ + --run 'echo "Seting Minio Secrets"' \ + --set MINIO_ROOT_USER ${email} \ + --run 'export MINIO_ROOT_PASSWORD="$(cat "$CREDENTIALS_DIRECTORY"/password)"' + ''; + }; + }; +} diff --git a/os/kay/modules/services/nix-cache.nix b/os/kay/modules/services/nix-cache.nix new file mode 100644 index 0000000..9c81b56 --- /dev/null +++ b/os/kay/modules/services/nix-cache.nix @@ -0,0 +1,12 @@ +{ config, ... }: +let + keyname = "misc/nixbin.${config.global.userdata.domain}"; +in +{ + sops.secrets.${keyname} = { }; + + services.nix-serve = { + enable = true; + secretKeyFile = config.sops.secrets.${keyname}.path; + }; +} diff --git a/os/kay/modules/services/sftp.nix b/os/kay/modules/services/sftp.nix new file mode 100644 index 0000000..f75abc4 --- /dev/null +++ b/os/kay/modules/services/sftp.nix @@ -0,0 +1,59 @@ +{ config, ... }: + +let + storage = "/hdd/users"; + user = config.global.userdata.name; + pubKeys = config.users.users.${user}.openssh.authorizedKeys.keys; +in +{ + users = { + groups."sftp".members = [ ]; + + users."sftp" = { + group = "sftp"; + shell = "/run/current-system/sw/bin/nologin"; + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFmA1dyV+o9gfoxlbVG0Y+dn3lVqdFs5fMqfxyNc5/Lr sftp@cez" + # https://github.com/zhanghai/MaterialFiles + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILxKrIaWRACi0oKfJRv6m3uUWKjKNyd9edbbFR5pAONH sftp@paq" + # samsung files only support PEM, hence RSA key + # https://r1.community.samsung.com/t5/galaxy-s/unable-to-remotely-connect-to-sftp-server-through-my-files/m-p/16347552/highlight/true#M105871 + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqe7CcXJw+dhXKUVeuj1iGOcV7KhyiJ55PxhGDXfQdu1YS5gi/pBnOk39pL22+QBFZX0trU/JNHpCMZWyFp/Fz9GBxp2LJERHwkANu0lk0PJ7QZdg79YN5lKpWTo2GpA3gHHC555Rm5V5BknwbZwVXWvGhSR93g/2b6AjcSZn4ZUwFF8soSb2EYsRa7blVbBv2njV2SGI9FezfHBF+N3CNOP7kxk63Pilk9NEUQuvYF1tmF7z/zIXbyLNaLT1MJE8KCbayM7E/WZuonSBqFf3fsmQge0La/LveRehQHb503uHNHzlFHXdMMZQrzOAHHyFQUHhYECvhLNDhGJb1KrjZcEiKmqCMmvHCG4JssRdJB5mq6J0g05ZmMrKt0srIT6lginkHy89AKkqt83xHHvXhZEw40zoGcq2rZD1dPN3toNZL/uGaIK0u1eMxFbuVKK3OjMg2UwzaHX1DDZyJdRes5huG/uXTgN7xamUu/TIBOK+WgibJeNf93i3GbsYezTs= sftp@paq" + ] + ++ pubKeys; + }; + + users."nazer" = { + group = "sftp"; + shell = "/run/current-system/sw/bin/nologin"; + isNormalUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV09w9Ovk9wk4Bhn/06iOn+Ss8lK3AmQAl8+lXHRycu nazu@pc" + ]; + }; + }; + + services.openssh = { + # support samsing files + settings = { + HostKeyAlgorithms = "+ssh-rsa"; + PubkeyAcceptedAlgorithms = "+ssh-rsa"; + Macs = [ "hmac-sha2-256" ]; + }; + + # sandboxing + extraConfig = '' + Match Group sftp + # chroot dir should be owned by root + # and sub dirs by %u + ChrootDirectory ${storage}/%u + ForceCommand internal-sftp + + PermitTunnel no + AllowAgentForwarding no + AllowTcpForwarding no + X11Forwarding no + ''; + }; +} diff --git a/os/kay/modules/sftp.nix b/os/kay/modules/sftp.nix deleted file mode 100644 index f75abc4..0000000 --- a/os/kay/modules/sftp.nix +++ /dev/null @@ -1,59 +0,0 @@ -{ config, ... }: - -let - storage = "/hdd/users"; - user = config.global.userdata.name; - pubKeys = config.users.users.${user}.openssh.authorizedKeys.keys; -in -{ - users = { - groups."sftp".members = [ ]; - - users."sftp" = { - group = "sftp"; - shell = "/run/current-system/sw/bin/nologin"; - isNormalUser = true; - openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFmA1dyV+o9gfoxlbVG0Y+dn3lVqdFs5fMqfxyNc5/Lr sftp@cez" - # https://github.com/zhanghai/MaterialFiles - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILxKrIaWRACi0oKfJRv6m3uUWKjKNyd9edbbFR5pAONH sftp@paq" - # samsung files only support PEM, hence RSA key - # https://r1.community.samsung.com/t5/galaxy-s/unable-to-remotely-connect-to-sftp-server-through-my-files/m-p/16347552/highlight/true#M105871 - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCqe7CcXJw+dhXKUVeuj1iGOcV7KhyiJ55PxhGDXfQdu1YS5gi/pBnOk39pL22+QBFZX0trU/JNHpCMZWyFp/Fz9GBxp2LJERHwkANu0lk0PJ7QZdg79YN5lKpWTo2GpA3gHHC555Rm5V5BknwbZwVXWvGhSR93g/2b6AjcSZn4ZUwFF8soSb2EYsRa7blVbBv2njV2SGI9FezfHBF+N3CNOP7kxk63Pilk9NEUQuvYF1tmF7z/zIXbyLNaLT1MJE8KCbayM7E/WZuonSBqFf3fsmQge0La/LveRehQHb503uHNHzlFHXdMMZQrzOAHHyFQUHhYECvhLNDhGJb1KrjZcEiKmqCMmvHCG4JssRdJB5mq6J0g05ZmMrKt0srIT6lginkHy89AKkqt83xHHvXhZEw40zoGcq2rZD1dPN3toNZL/uGaIK0u1eMxFbuVKK3OjMg2UwzaHX1DDZyJdRes5huG/uXTgN7xamUu/TIBOK+WgibJeNf93i3GbsYezTs= sftp@paq" - ] - ++ pubKeys; - }; - - users."nazer" = { - group = "sftp"; - shell = "/run/current-system/sw/bin/nologin"; - isNormalUser = true; - openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICV09w9Ovk9wk4Bhn/06iOn+Ss8lK3AmQAl8+lXHRycu nazu@pc" - ]; - }; - }; - - services.openssh = { - # support samsing files - settings = { - HostKeyAlgorithms = "+ssh-rsa"; - PubkeyAcceptedAlgorithms = "+ssh-rsa"; - Macs = [ "hmac-sha2-256" ]; - }; - - # sandboxing - extraConfig = '' - Match Group sftp - # chroot dir should be owned by root - # and sub dirs by %u - ChrootDirectory ${storage}/%u - ForceCommand internal-sftp - - PermitTunnel no - AllowAgentForwarding no - AllowTcpForwarding no - X11Forwarding no - ''; - }; -} diff --git a/os/kay/modules/sshfwd.nix b/os/kay/modules/sshfwd.nix deleted file mode 100644 index fcafd17..0000000 --- a/os/kay/modules/sshfwd.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ ... }: -let - group = "sshfwd"; -in -{ - networking.firewall.allowedTCPPorts = [ 2222 ]; - - users = { - groups.${group}.members = [ ]; - - users."lia" = { - inherit group; - isSystemUser = true; - - openssh.authorizedKeys.keys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAe7fJlh9L+9JSq0+hK7jNZjszmZqNXwzqcZ+zx0yJyU lia" - ]; - }; - }; - - services.openssh.extraConfig = '' - Match Group ${group} - ForceCommand echo 'this account is only usable for remote forwarding' - PermitTunnel no - AllowAgentForwarding no - X11Forwarding no - - AllowTcpForwarding remote - GatewayPorts clientspecified - PermitListen *:2222 - ''; -} diff --git a/os/kay/modules/wireguard.nix b/os/kay/modules/wireguard.nix deleted file mode 100644 index fd00804..0000000 --- a/os/kay/modules/wireguard.nix +++ /dev/null @@ -1,71 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: -let - wgInterface = "wg"; - wanInterface = "ppp0"; - port = 51820; - - wgConf = pkgs.writeText "wg.conf" '' - [interface] - Address = 10.0.1.1/24 - MTU = 1412 - ListenPort = 51820 - PostUp = ${ - lib.getExe ( - pkgs.writeShellApplication { - name = "wg_set_key"; - runtimeInputs = with pkgs; [ wireguard-tools ]; - text = '' - wg set ${wgInterface} private-key <(cat ${config.sops.secrets."misc/wireguard".path}) - ''; - } - ) - } - - [Peer] - # friendly_name = cez - PublicKey = IcMpAs/D0u8O/AcDBPC7pFUYSeFQXQpTqHpGOeVpjS8= - AllowedIPs = 10.0.1.2/32 - - [Peer] - # friendly_name = exy - PublicKey = bJ9aqGYD2Jh4MtWIL7q3XxVHFuUdwGJwO8p7H3nNPj8= - AllowedIPs = 10.0.1.3/32 - - [Peer] - # friendly_name = dad - PublicKey = q70IyOS2IpubIRWqo5sL3SeEjtUy2V/PT8yqVExiHTQ= - AllowedIPs = 10.0.1.4/32 - ''; -in -{ - sops.secrets."misc/wireguard" = { }; - - networking = { - nat = { - enable = true; - externalInterface = wanInterface; - internalInterfaces = [ wgInterface ]; - }; - - firewall.allowedUDPPorts = [ port ]; - wg-quick.interfaces.${wgInterface}.configFile = builtins.toString wgConf; - }; - - services.dnsmasq.settings = { - no-dhcp-interface = wgInterface; - interface = [ wgInterface ]; - }; - - services.prometheus.exporters.wireguard = { - enable = true; - withRemoteIp = true; - wireguardConfig = builtins.toString wgConf; - singleSubnetPerField = true; - listenAddress = "127.0.0.1"; - }; -} diff --git a/os/kay/modules/www.nix b/os/kay/modules/www.nix deleted file mode 100644 index e64c65c..0000000 --- a/os/kay/modules/www.nix +++ /dev/null @@ -1,328 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: - -let - domain = config.global.userdata.domain; - storage = "/hdd/users/sftp/shr"; -in -{ - imports = [ - ./matrix - ./cgit.nix - ]; - - security.acme.certs.${domain}.postRun = "systemctl reload nginx.service"; - networking.firewall = { - allowedTCPPorts = [ - 80 - 443 - ]; - allowedUDPPorts = [ 443 ]; - }; - - services.prometheus.exporters = { - nginxlog = { - enable = true; - listenAddress = "127.0.0.1"; - }; - nginx = { - enable = true; - listenAddress = "127.0.0.1"; - }; - }; - - services.nginx = { - enable = true; - statusPage = true; - package = pkgs.nginxQuic; - enableQuicBPF = true; - - recommendedTlsSettings = true; - # breaks home-assistant proxy for some reason - # only the first request goes through, then site hangs - # recommendedZstdSettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - recommendedProxySettings = true; - recommendedBrotliSettings = true; - eventsConfig = "worker_connections 1024;"; - appendHttpConfig = '' - quic_retry on; - quic_gso on; - add_header Alt-Svc 'h3=":443"; ma=2592000; persist=1'; - ''; - - virtualHosts = - let - defaultOpts = { - # reuseport = true; - quic = true; - http3 = true; - forceSSL = true; - useACMEHost = domain; - }; - in - { - "${domain}" = defaultOpts // { - default = true; - globalRedirect = "www.${domain}"; - - extraConfig = '' - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - - locations = { - "/.well-known/matrix/server".return = '' - 200 '{ "m.server": "${domain}:443" }' - ''; - - "/.well-known/matrix/client".return = '' - 200 '${ - builtins.toJSON { - "m.homeserver".base_url = "https://${domain}"; - "org.matrix.msc3575.proxy".url = "https://sliding.${domain}"; - "m.identity_server".base_url = "https://vector.im"; - } - }' - ''; - - "/.well-known/".proxyPass = "http://127.0.0.1:8085"; - - "~ ^(\\/_matrix|\\/_synapse\\/client)".proxyPass = - "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; - }; - }; - - "sliding.${domain}" = defaultOpts // { - extraConfig = '' - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://${config.services.matrix-sliding-sync-dirty.settings.SYNCV3_BINDADDR}"; - }; - }; - - "headscale.${domain}" = defaultOpts // { - locations = { - "/" = { - proxyWebsockets = true; - proxyPass = "http://localhost:${toString config.services.headscale.port}"; - }; - "= /".return = "307 https://headscale.${domain}/admin"; - "/admin".proxyPass = "http://localhost:${toString config.services.headplane.settings.server.port}"; - }; - }; - - "${config.services.grafana.settings.server.domain}" = defaultOpts // { - extraConfig = '' - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://${config.services.grafana.settings.server.http_addr}:${builtins.toString config.services.grafana.settings.server.http_port}"; - }; - }; - - "www.${domain}" = defaultOpts // { - extraConfig = '' - ssl_early_data on; - ''; - - root = "/var/www/${domain}"; - }; - - "git.${domain}" = defaultOpts // { - extraConfig = '' - ssl_early_data on; - ''; - }; - - "bin.${domain}" = defaultOpts // { - extraConfig = '' - ssl_early_data on; - ''; - root = "${storage}/bin"; - locations."= /".return = "307 https://www.${domain}"; - }; - - "static.${domain}" = defaultOpts // { - extraConfig = '' - ssl_early_data on; - ''; - root = "${storage}/static"; - locations."= /".return = "301 https://www.${domain}"; - }; - - "home.${domain}" = defaultOpts // { - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://127.0.0.1:${builtins.toString config.services.home-assistant.config.http.server_port}"; - }; - }; - - "stalwart.${domain}" = defaultOpts // { - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://127.0.0.1:8085"; - }; - }; - - "s3.${domain}" = defaultOpts // { - extraConfig = '' - # Allow special characters in headers - ignore_invalid_headers off; - # Allow any size file to be uploaded. - # Set to a value such as 1000m; to restrict file size to a specific value - client_max_body_size 0; - # Disable buffering - proxy_buffering off; - proxy_request_buffering off; - ''; - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://127.0.0.1:9000"; - extraConfig = '' - proxy_connect_timeout 300; - chunked_transfer_encoding off; - ''; - }; - }; - - "minio.${domain}" = defaultOpts // { - extraConfig = '' - # Allow special characters in headers - ignore_invalid_headers off; - # Allow any size file to be uploaded. - # Set to a value such as 1000m; to restrict file size to a specific value - client_max_body_size 0; - # Disable buffering - proxy_buffering off; - proxy_request_buffering off; - ''; - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://127.0.0.1:9003"; - extraConfig = '' - # This is necessary to pass the correct IP to be hashed - real_ip_header X-Real-IP; - proxy_connect_timeout 300; - chunked_transfer_encoding off; - ''; - }; - }; - - "mta-sts.${domain}" = defaultOpts // { - extraConfig = '' - ssl_early_data on; - ''; - locations."= /.well-known/mta-sts.txt".return = ''200 "${ - lib.strings.concatStringsSep "\\n" [ - "version: STSv1" - "mode: enforce" - "mx: mail.${domain}" - "max_age: 86400" - ] - }"''; - }; - - "immich.${domain}" = defaultOpts // { - locations."/" = { - proxyWebsockets = true; - proxyPass = "http://${config.services.immich.host}:${builtins.toString config.services.immich.port}"; - }; - - extraConfig = '' - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - }; - - "nixbin.${domain}" = defaultOpts // { - extraConfig = '' - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - - locations = { - "= /files".return = "301 https://nixbin.${domain}/files/"; - "/files/" = { - alias = "/nix/store/"; - extraConfig = "autoindex on;"; - }; - - "= /" = { - extraConfig = '' - add_header Content-Type text/html; - add_header Alt-Svc 'h3=":443"; ma=2592000; persist=1'; - ''; - return = '' - 200 - ' - - - - Nix Cache - - -
-

- ❄️ Nix Cache -

-

- Public Key: nixbin.sinanmohd.com:dXV3KDPVrm+cGJ2M1ZmTeQJqFGaEapqiVoWHgYDh03k= -

-
- - ' - ''; - }; - - "/".proxyPass = - "http://${config.services.nix-serve.bindAddress}:${toString config.services.nix-serve.port}"; - }; - }; - - "www.alinafs.com" = defaultOpts // { - useACMEHost = null; - enableACME = true; - globalRedirect = "alinafs.com/home"; - extraConfig = '' - ssl_early_data on; - ''; - }; - "alinafs.com" = defaultOpts // { - useACMEHost = null; - enableACME = true; - - locations = { - "/metrics".return = "307 /home/"; - "/" = { - proxyWebsockets = true; - proxyPass = "http://127.0.0.1:${builtins.toString config.services.alina.port}"; - }; - }; - - extraConfig = '' - proxy_buffering off; - proxy_request_buffering off; - client_max_body_size 0; - ''; - }; - }; - }; -} -- cgit v1.2.3