{ inputs, flake, self, ... }: { config, pkgs, lib, modulesPath, ... }: with builtins; with lib; let domain = "hectic-lab.com"; matrixDomain = "accord.tube"; sslOpts = { sslCertificate = config.sops.secrets."ssl/porkbun/${domain}/domain.cert.pem".path; sslCertificateKey = config.sops.secrets."ssl/porkbun/${domain}/private.key.pem".path; }; in { imports = [ self.nixosModules.hectic self.nixosModules.matrix-cluster inputs.sops-nix.nixosModules.sops self.nixosModules.matrix-cluster-users self.nixosModules."shadowsocks-rust" # NOTE(nrv): impl self.nixosModules."shadowsocks" # NOTE(nrv): usage/instance inputs.hectic-landing.nixosModules.hectic-landing (import ./containers.nix { inherit flake self inputs; }) (import ./mechabellum.nix { inherit flake self inputs domain sslOpts; }) (import (./. + "/sentinèlla.nix") { inherit flake self inputs domain sslOpts; }) ]; services.hectic-landing = { enable = true; package = inputs.hectic-landing.packages.${pkgs.stdenv.hostPlatform.system}.hectic-landing; domain = domain; port = 3000; host = "127.0.0.1"; }; # NOTE(yukkop): both nixos-mailserver and hectic-landing module set # security.acme.defaults.email. Force the mailserver-aligned address. security.acme.defaults.email = lib.mkForce "security@${domain}"; hectic = { archetype.dev.enable = true; hardware.hetzner-cloud = { enable = true; networkMatchConfigName = "enp1s0"; ipv4 = "128.140.75.58"; ipv6 = "2a01:4f8:c2c:d54a"; }; services.matrix = { enable = false; }; generic.matrix-cluster = { enable = true; overrideEnableSynapse = false; role = "standby"; inherit matrixDomain; signingKeyFile = config.sops.secrets."matrix/signing-key".path; secretsFile = config.sops.secrets."matrix/secrets".path; turnSecretFile = config.sops.secrets."matrix/turn-secret".path; publicIp = "128.140.75.58"; objectStorage.s3 = { bucket = "matrix-hectic-lab"; regionName = "hel1"; endpointUrl = "https://hel1.your-objectstorage.com"; credentialsFile = config.sops.secrets."matrix/object-storage/credentials".path; }; replication = { peerHost = "91.198.166.181"; passwordFile = config.sops.secrets."matrix/postgres-replication-password".path; allowedSourceIPs = [ "91.198.166.181/32" ]; }; acme = { enable = false; porkbunApiKeyFile = config.sops.secrets."matrix/porkbun-api-key".path; porkbunSecretApiKeyFile = config.sops.secrets."matrix/porkbun-secret-api-key".path; }; }; services.media-browser = { enable = true; port = 3001; s3Bucket = "matrix-hectic-lab"; s3Endpoint = "https://hel1.your-objectstorage.com"; s3Region = "hel1"; s3CredentialsFile = config.sops.secrets."matrix/object-storage/credentials".path; }; }; # NOTE(yukkop): disk was provisioned by Hetzner rescue image, disko was never # run, so partition labels don't exist. Override fileSystems with actual UUIDs. fileSystems."/" = lib.mkForce { device = "/dev/disk/by-uuid/48ba7286-d019-4cdc-9784-459767979b07"; fsType = "ext4"; }; fileSystems."/boot" = lib.mkForce { device = "/dev/disk/by-uuid/71F2-4E98"; fsType = "vfat"; options = [ "umask=0077" ]; }; programs.zsh.enable = true; programs.zsh.interactiveShellInit = '' setopt vi ''; environment.systemPackages = with pkgs; [ git rsync python311 kitty ]; # Secrets config sops = { gnupg.sshKeyPaths = [ ]; age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; defaultSopsFile = "${flake}/sus/hectic-lab.yaml"; }; users.users.root.openssh.authorizedKeys.keys = [ # yukkop "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMuP5NSfEQmO6m77xBWZvZ3hk7cw1q2k2vbsFd37rybU u0_a327@localhost" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJBLxMo5icX2Xyng7mcWGnIi+c4ZbVygjPhuU8noCkfZ" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGxgLlX/15Fk7PgIc9FSrA7oRtA8qK4GXfOhj7ZlNUaJ nix-on-droid@localhost" # snuff "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFouceNUxI3bGC24/hfA8J3VuBpvTcZh3KhixgrMiLte" # nrv "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIE/EhBI6sJb2yHbTkqhZiCzUrsLE6t+CZe7RhS22z7w5 nrv@adamantia" # github workflow "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKPEUArBxu7NUULT7Pi8ArtVxY1uVbIBSaeRKtqz1sz1" ]; users.users.ds4d = { # NOTE(nrv): artishoque isNormalUser = true; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINcjBc57N6MxtMYAHEB/nwZ+OGsG3P1KWO1ZXvzQyhKn ds4d@ds4d" ]; }; users.users.sshuttle = { isNormalUser = true; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKd4iU2E5fiwPwBbeo1ZPo0YBFEj9qBPew/KitaO+OHU" ]; }; sops.secrets."mailserver/security/hashedPassword" = {}; sops.secrets."mailserver/yukkop/hashedPassword" = {}; sops.secrets."mailserver/daniil-perlyk/hashedPassword" = {}; sops.secrets."mailserver/snuff/hashedPassword" = {}; sops.secrets."mailserver/antoshka/hashedPassword" = {}; sops.secrets."mailserver/founders/hashedPassword" = {}; sops.secrets."mailserver/lvgkcfjl/hashedPassword" = {}; sops.secrets."init-postgresql" = { key = "init-postgresql"; }; sops.secrets."matrix/secrets" = { key = "matrix/secrets"; owner = "matrix-synapse"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; sops.secrets."matrix/turn-secret" = { key = "matrix/turn-secret"; owner = "root"; group = "root"; mode = "0400"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; sops.secrets."matrix/object-storage/credentials" = { key = "matrix/object-storage/credentials"; owner = "matrix-synapse"; mode = "0400"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; # Shared cluster secrets (PL standby also reads from this file). sops.secrets."matrix/signing-key" = { key = "matrix/signing-key"; owner = "matrix-synapse"; mode = "0400"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; sops.secrets."matrix/postgres-replication-password" = { key = "matrix/postgres-replication-password"; owner = "postgres"; mode = "0400"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; sops.secrets."matrix/porkbun-api-key" = { key = "matrix/porkbun-api-key"; mode = "0400"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; sops.secrets."matrix/porkbun-secret-api-key" = { key = "matrix/porkbun-secret-api-key"; mode = "0400"; sopsFile = "${flake}/sus/matrix-cluster.yaml"; }; services.mailserver = { enable = true; domain = domain; loginAccounts = { "security" = { hashedPasswordFile = config.sops.secrets."mailserver/security/hashedPassword".path; }; "founders" = { hashedPasswordFile = config.sops.secrets."mailserver/founders/hashedPassword".path; }; "lvgkcfjl" = { hashedPasswordFile = config.sops.secrets."mailserver/lvgkcfjl/hashedPassword".path; }; "yukkop" = { hashedPasswordFile = config.sops.secrets."mailserver/yukkop/hashedPassword".path; }; "daniil-perlyk" = { hashedPasswordFile = config.sops.secrets."mailserver/daniil-perlyk/hashedPassword".path; }; "snuff" = { hashedPasswordFile = config.sops.secrets."mailserver/snuff/hashedPassword".path; }; "antoshka" = { hashedPasswordFile = config.sops.secrets."mailserver/antoshka/hashedPassword".path; }; }; }; mailserver.stateVersion = 3; services.redis.servers."vproxy-bot-test-state" = { enable = true; port = 6379; }; services.mysql = { enable = true; package = pkgs.mariadb; }; networking.firewall = { allowedTCPPorts = [ 80 443 3306 # mysql 11012 # gitea ssh 25565 55228 # ss-bfs ]; allowedUDPPorts = [ 51820 # wg-bfs 55228 # ss-bfs ]; # Postgres replication: only the PL standby peer may reach 5432. extraInputRules = '' ip saddr 91.198.166.181/32 tcp dport 5432 accept ''; }; virtualisation.docker.enable = true; systemd.tmpfiles.rules = [ "d /var/www/store 0755 nginx nginx -" ]; sops.secrets."ssl/porkbun/${domain}/domain.cert.pem" = { group = "nginx"; mode = "0440"; }; sops.secrets."ssl/porkbun/${domain}/private.key.pem" = { group = "nginx"; mode = "0440"; }; sops.secrets."ssl/porkbun/${domain}/public.key.pem" = { group = "nginx"; mode = "0440"; }; services.nginx = { enable = true; # NOTE(yukkop): virtualHosts.${domain} is owned by the hectic-landing module # (ACME-managed). See services.hectic-landing above. virtualHosts."store.${domain}" = sslOpts // { forceSSL = true; root = "/var/www/store"; locations."/" = { extraConfig = '' autoindex on; ''; }; }; virtualHosts."snuff.${domain}" = sslOpts // { forceSSL = true; locations."/" = { extraConfig = '' proxy_pass http://188.32.215.29:3993/; proxy_redirect off; ''; }; }; virtualHosts."nrv.${domain}" = sslOpts // { forceSSL = true; locations."/" = { extraConfig = '' proxy_pass http://127.0.0.1:22842/; proxy_redirect off; ''; }; }; virtualHosts."yukkop.${domain}" = sslOpts // { forceSSL = true; locations."/" = { extraConfig = '' proxy_pass http://127.0.0.1:9855/; proxy_redirect off; ''; }; }; virtualHosts."gitea.${domain}" = sslOpts // { forceSSL = true; locations."/" = { extraConfig = '' proxy_pass http://127.0.0.1:11011/; proxy_redirect off; ''; }; }; }; services = { gitea = { enable = true; settings.server = { HTTP_PORT = 11011; SSH_PORT = 11012; }; database = { createDatabase = false; type = "postgres"; socket = "/run/postgresql"; user = "gitea"; name = "gitea"; }; }; postgresql = { enable = true; ensureDatabases = [ "gitea" ]; ensureUsers = [ { name = "gitea"; ensureDBOwnership = true; } ]; authentication = '' local gitea gitea peer ''; }; }; # === WireGuard (disabled) === sops.secrets."wg-bfs/private-key" = {}; # networking.wireguard.interfaces = let # subnet = "10.13.37"; # externalInterface = "eth0"; # in { # wg-bfs = { # ips = [ "${subnet}.1/24" ]; # listenPort = 51820; # postSetup = '' # ${pkgs.iptables}/bin/iptables -t 'nat' -A 'POSTROUTING' -s '${subnet}.0/24' -o '${externalInterface}' -j 'MASQUERADE' # ''; # postShutdown = '' # ${pkgs.iptables}/bin/iptables -t 'nat' -D 'POSTROUTING' -s '${subnet}.0/24' -o '${externalInterface}' -j 'MASQUERADE' # ''; # privateKeyFile = config.sops.secrets."wg-bfs/private-key".path; # generatePrivateKeyFile = false; # peers = with lib; with builtins; let # pubkeys = [ # "3dVzf1jxnVVTkLAyxedW+kRQBexZDzYDwpaLIcTrLjc=" # nrv (host: 2) # "Kk2d0ncj24rO0qbuKh4V4t1OLnmVYbeaYvuEnL2OPFM=" # lysmi (host: 3) # "BkM/NEDbR/XQ6WYQ0Yt+nJrc2HFCVsoW4QxBmkqxHn8=" # yukkop (host: 4) # ]; # hosts = lists.range 2 254; # zipped = zipLists pubkeys hosts; # in flip map zipped ({ fst, snd }: { # publicKey = "${fst}"; # allowedIPs = [ "${subnet}.${toString snd}/32" ]; # }); # }; # }; }