{ config, lib, pkgs, ... }: let format = pkgs.formats.yaml { }; settings = lib.recursiveUpdate config.services.headscale.settings { acme_email = "/dev/null"; tls_cert_path = "/dev/null"; tls_key_path = "/dev/null"; policy.path = "/dev/null"; oidc.client_secret_path = "/dev/null"; }; headscaleConfig = format.generate "headscale.yml" settings; in { imports = [ ./auth ./git ]; networking.firewall = { enable = true; allowedTCPPorts = [ 80 443 ]; }; services.fail2ban.jails = { # max 6 failures in 600 seconds "nginx-spam" = '' enabled = true filter = nginx-bruteforce logpath = /var/log/nginx/access.log backend = auto maxretry = 6 findtime = 600 ''; }; services.nginx = { enable = true; recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; }; services.headscale = { enable = true; address = "0.0.0.0"; port = 8080; settings = { server_url = "https://headscale.escapeangle.com"; dns = { base_domain = "tailnet.escapeangle.com"; }; }; }; services.headplane = { enable = true; agent.enable = false; settings = { server = { host = "127.0.0.1"; port = 8081; cookie_secret = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; # replaced in env cookie_secure = true; }; headscale = { url = "https://headscale.escapeangle.com"; config_path = "${headscaleConfig}"; config_strict = true; }; integration.proc.enabled = true; }; }; services.nginx.virtualHosts."headscale.escapeangle.com" = { forceSSL = true; enableACME = true; locations."/" = { proxyPass = "http://localhost:${toString config.services.headscale.port}"; proxyWebsockets = true; }; locations."/admin" = { proxyPass = "http://127.0.0.1:${toString config.services.headplane.settings.server.port}"; proxyWebsockets = true; }; }; users.users.mealie = { enable = true; group = "mealie"; isSystemUser = true; }; users.groups.mealie = { }; services.mealie = { enable = true; settings = { BASE_URL = "https://recipes.escapeangle.com/"; DB_ENGINE = "postgres"; POSTGRES_SERVER = "db-01.tailnet.escapeangle.com"; ALLOW_SIGNUP = "false"; ALLOW_PASSWORD_LOGIN = "false"; OIDC_AUTH_ENABLED = "true"; OIDC_SIGNUP_ENABLED = "true"; OIDC_CONFIGURATION_URL = "https://auth.escapeangle.com/.well-known/openid-configuration"; OIDC_CLIENT_ID = "mealie"; OIDC_AUTO_REDIRECT = "false"; OIDC_ADMIN_GROUP = "mealie-admins"; OIDC_USER_GROUP = "mealie-users"; }; credentialsFile = config.sops.secrets.mealie-env.path; }; services.nginx.virtualHosts."recipes.escapeangle.com" = { forceSSL = true; enableACME = true; locations."/" = { proxyPass = "http://localhost:${toString config.services.mealie.port}"; }; }; services.atuin = { enable = true; openRegistration = false; database = { uri = "postgresql://atuin@db-01.tailnet.escapeangle.com:5432/atuin"; createLocally = false; }; }; services.nginx.virtualHosts."atuin.escapeangle.com" = { forceSSL = true; enableACME = true; locations."/" = { proxyPass = "http://localhost:${toString config.services.atuin.port}"; }; }; services.vaultwarden = { enable = true; dbBackend = "postgresql"; config = { DOMAIN = "https://bitwarden.kinkystar.com"; ROCKET_PORT = 8222; }; environmentFile = config.sops.secrets.vaultwarden.path; }; services.nginx.virtualHosts."bitwarden.kinkystar.com" = { forceSSL = true; enableACME = true; locations."/" = { proxyPass = "http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT}"; }; }; virtualisation.oci-containers = { backend = "podman"; containers = { docuseal = { image = "docuseal/docuseal:latest"; ports = [ "3001:3000" ]; environmentFiles = [ config.sops.secrets.docusealEnvironment.path ]; extraOptions = [ "--dns=100.100.100.100" ]; }; }; }; services.nginx.virtualHosts."sign.kinkystar.com" = { forceSSL = true; enableACME = true; locations."/" = { proxyPass = "http://localhost:3001"; }; }; sops = { defaultSopsFile = ./hosting-01.yaml; validateSopsFiles = false; secrets = { mealie-env = { owner = "mealie"; }; vaultwarden = { owner = "root"; }; docusealEnvironment = { owner = "root"; }; }; }; system.stateVersion = "25.05"; }