From dca29c0156dcac99eacf0b061b611081533538f6 Mon Sep 17 00:00:00 2001 From: Grimmauld Date: Thu, 9 May 2024 14:55:02 +0200 Subject: [PATCH] globalized port/vhost config: move modules --- modules/default.nix | 134 +++++++++++++++++++++++------ modules/discord-matrix-bridge.nix | 10 +-- modules/email.nix | 19 +---- modules/gitea.nix | 31 ++----- modules/grafana.nix | 23 +---- modules/mastodon.nix | 5 +- modules/matrix.nix | 16 ++-- modules/nextcloud.nix | 29 ++----- modules/prometheus.nix | 35 ++------ modules/ptero.nix | 137 ------------------------------ modules/puffer.nix | 3 +- 11 files changed, 156 insertions(+), 286 deletions(-) delete mode 100644 modules/ptero.nix diff --git a/modules/default.nix b/modules/default.nix index d9df9a6..0037635 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -26,25 +26,68 @@ in options.serverConfig = with lib; { ports = mkOption { - type = types.attrsOf types.int; + type = types.attrsOf ( + types.submodule ( + { config, ... }: + rec { + options = { + port = mkOption { + type = types.int; + description = "port to define"; + }; + open = mkEnableOption "whether to open the port" // { + default = true; + }; + }; + } + ) + ); default = { }; description = "ports associated with services"; }; vhosts = mkOption { type = types.attrsOf ( - types.submodule { - options = { - port = mkOption { - type = types.int; - description = "port to redirect to this vhost"; + types.submodule ( + { config, ... }: + rec { + options = { + port = mkOption { + type = types.int; + default = 80; + description = "port to redirect to this vhost"; + }; + host = mkOption { + type = types.nonEmptyStr; + description = "name if the vhost"; + }; + accessType = mkOption { + type = types.enum [ + "proxy" + "redirect" + "custom" + "none" + ]; + default = "proxy"; + description = "nginx template to use"; + }; + extraNginx = mkOption { + type = types.attrs; + default = + if config.accessType == "redirect" then + { locations."/".return = "307 https://${domain}"; } + else + ( + if config.accessType == "proxy" then + { locations."/".proxyPass = "http://127.0.0.1:${builtins.toString config.port}"; } + else + { } + ); + description = "location definition for nginx"; + }; }; - host = mkOption { - type = types.nonEmptyStr; - description = "name if the vhost"; - }; - }; - } + } + ) ); default = { }; description = "vhosts associated with services"; @@ -52,13 +95,11 @@ in }; config = { - networking.firewall.allowedTCPPorts = - [ - 80 - 443 - ] - ++ lib.attrValues config.serverConfig.ports - ++ (lib.mapAttrsToList (n: v: v.port) config.serverConfig.vhosts); + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ] ++ (lib.mapAttrsToList (n: v: v.port) (lib.filterAttrs (n: v: v.open) config.serverConfig.ports)); + # ++ (lib.mapAttrsToList (n: v: v.port) (lib.filterAttrs (n: v: !v.disableWebAccess) config.serverConfig.vhosts)); services.nginx.virtualHosts = { @@ -76,16 +117,28 @@ in serverName = host.host; forceSSL = true; useACMEHost = domain; - locations."/" = { - proxyPass = "http://127.0.0.1:${builtins.toString host.port}"; - }; - }; - }) config.serverConfig.vhosts); + enableACME = lib.mkForce false; + } // host.extraNginx; + }) (lib.filterAttrs (n: v: v.accessType != "none") config.serverConfig.vhosts)); serverConfig = { ports = { - puffer_sftp_port = 5657; + puffer_sftp_port.port = 5657; + gitea_ssh_port.port = 2222; + node_exporter = { + port = 9002; + open = false; + }; + discord_matrix_bridge_port = { + port = 9005; + open = false; + }; + redis_nextcloud_port = { + port = 6379; + open = false; + }; }; + vhosts = { puffer_host = { port = 8080; @@ -95,6 +148,37 @@ in port = 8100; host = "tlemap.${domain}"; }; + mail_host = { + host = "mail.${domain}"; + accessType = "redirect"; + }; + gitea_host = { + host = "git.${domain}"; + port = 8081; + }; + matrix_host = { + accessType = "redirect"; + host = "matrix.${domain}"; + }; + prometheus_host = { + host = "prometheus.${domain}"; + port = 9090; + accessType = "redirect"; + }; + grafana_host = { + host = "grafana.${domain}"; + port = 8082; + }; + nextcloud_host = rec { + host = "cloud.${domain}"; + port = 8083; + accessType = "custom"; + extraNginx.serverName = host; + }; + mastodon_host = { + host = "mastodon.${domain}"; + accessType = "none"; + }; }; }; diff --git a/modules/discord-matrix-bridge.nix b/modules/discord-matrix-bridge.nix index 219b1bd..f65147c 100644 --- a/modules/discord-matrix-bridge.nix +++ b/modules/discord-matrix-bridge.nix @@ -5,7 +5,7 @@ ... }: let - bridge_port = 9005; # netstat -nlp | grep 9005 + inherit (config.serverConfig) ports vhosts; in { age.secrets.matrix_discord_bridge_token.file = ../secrets/matrix_discord_bridge_token.age; @@ -22,15 +22,15 @@ in }; bridge = { enableSelfServiceBridging = true; - inherit (config.networking) domain; - homeserverUrl = "https://${config.networking.domain}"; + domain = config.services.matrix-synapse-next.settings.server_name; + homeserverUrl = config.services.matrix-synapse-next.settings.public_baseurl; disablePresence = true; disableTypingNotifications = true; }; - # logging.console = "silly"; + # logging.console = "silly"; }; serviceDependencies = [ "matrix-synapse.target" ]; - port = bridge_port; + port = ports.discord_matrix_bridge_port.port; localpart = "_discord_"; package = pkgs.matrix-appservice-discord; environmentFile = config.age.secrets.matrix_discord_bridge_token.path; diff --git a/modules/email.nix b/modules/email.nix index 06fd8a4..5dafa50 100644 --- a/modules/email.nix +++ b/modules/email.nix @@ -1,15 +1,13 @@ { config, ... }: let + inherit (config.serverConfig) ports vhosts; inherit (config.networking) domain; - mail_host = "mail.${domain}"; in { - security.acme.certs."${domain}".extraDomainNames = [ mail_host ]; - # services.dovecot2.sieve.extensions = [ "fileinto" ]; # sives break without this for some reason mailserver = { enable = true; - fqdn = mail_host; + fqdn = vhosts.mail_host.host; domains = [ domain ]; # A list of all login accounts. To create the password hashes, use @@ -33,17 +31,4 @@ in certificateFile = "/var/lib/acme/${domain}/fullchain.pem"; keyFile = "/var/lib/acme/${domain}/key.pem"; }; - - services.nginx = { - enable = true; - virtualHosts."${mail_host}" = { - # you should NOT be here from a browser :P - serverName = mail_host; - forceSSL = true; - useACMEHost = domain; - locations."/" = { - return = "307 https://${domain}"; - }; - }; - }; } diff --git a/modules/gitea.nix b/modules/gitea.nix index 95d7f7e..8763579 100644 --- a/modules/gitea.nix +++ b/modules/gitea.nix @@ -7,9 +7,7 @@ }: let inherit (config.networking) domain; - gitea_host = "git.${domain}"; - gitea_port = 8081; - gitea_ssh_port = 2222; + inherit (config.serverConfig) ports vhosts; in { services.gitea = { @@ -17,17 +15,17 @@ in settings = { service.DISABLE_REGISTRATION = true; server = { - HTTP_PORT = gitea_port; - ROOT_URL = "https://${gitea_host}/"; + HTTP_PORT = vhosts.gitea_host.port; + ROOT_URL = "https://${vhosts.gitea_host.host}/"; DISABLE_SSH = false; SSH_DOMAIN = domain; START_SSH_SERVER = true; BUILTIN_SSH_SERVER_USER = "git"; - SSH_PORT = gitea_ssh_port; - # SSH_LISTEN_HOST="::"; # fixme? - # SSH_AUTHORIZED_PRINCIPALS_ALLOW="username"; + SSH_PORT = ports.gitea_ssh_port.port; + # SSH_LISTEN_HOST="::"; # fixme? + # SSH_AUTHORIZED_PRINCIPALS_ALLOW="username"; }; - # log.LEVEL = "Debug"; + # log.LEVEL = "Debug"; "ssh.minimum_key_sizes".RSA = 2048; "git.timeout".MIGRATE = 6000; }; @@ -35,19 +33,4 @@ in }; environment.systemPackages = with pkgs; [ gitea ]; - - security.acme.certs."${domain}".extraDomainNames = [ gitea_host ]; - networking.firewall.allowedTCPPorts = [ gitea_ssh_port ]; - - services.nginx = { - enable = true; - virtualHosts."${gitea_host}" = { - serverName = gitea_host; - forceSSL = true; - useACMEHost = domain; - locations."/" = { - proxyPass = "http://127.0.0.1:${builtins.toString config.services.gitea.settings.server.HTTP_PORT}"; - }; - }; - }; } diff --git a/modules/grafana.nix b/modules/grafana.nix index 69f3dc2..2887495 100644 --- a/modules/grafana.nix +++ b/modules/grafana.nix @@ -1,8 +1,7 @@ { config, ... }: let + inherit (config.serverConfig) ports vhosts; inherit (config.networking) domain; - grafana_host = "grafana.${domain}"; - grafana_port = 8082; in { age.secrets.grafana_admin_pass = { @@ -12,7 +11,6 @@ in mode = "0600"; }; - security.acme.certs."${domain}".extraDomainNames = [ grafana_host ]; services.grafana = { enable = true; settings = { @@ -22,22 +20,9 @@ in admin_password = "$__file{${config.age.secrets.grafana_admin_pass.path}}"; }; server = { - domain = grafana_host; - root_url = "https://${grafana_host}"; - http_port = grafana_port; - }; - }; - }; - - services.nginx = { - enable = true; - virtualHosts."${grafana_host}" = { - serverName = grafana_host; - forceSSL = true; - useACMEHost = domain; - locations."/" = { - proxyPass = "http://127.0.0.1:${builtins.toString config.services.grafana.settings.server.http_port}"; - proxyWebsockets = true; + domain = vhosts.grafana_host.host; + root_url = "https://${vhosts.grafana_host.host}"; + http_port = vhosts.grafana_host.port; }; }; }; diff --git a/modules/mastodon.nix b/modules/mastodon.nix index 0d3258e..a7866c2 100644 --- a/modules/mastodon.nix +++ b/modules/mastodon.nix @@ -1,13 +1,12 @@ { config, ... }: let + inherit (config.serverConfig) ports vhosts; inherit (config.networking) domain; - mastodon_host = "mastodon.${domain}"; in { - security.acme.certs."${domain}".extraDomainNames = [ mastodon_host ]; services.mastodon = { enable = true; - localDomain = mastodon_host; + localDomain = vhosts.mastodon_host.host; streamingProcesses = 7; configureNginx = true; smtp = { diff --git a/modules/matrix.nix b/modules/matrix.nix index 7351e6b..d472c17 100644 --- a/modules/matrix.nix +++ b/modules/matrix.nix @@ -7,7 +7,7 @@ }: let inherit (config.networking) domain; - matrix_host = "matrix.${domain}"; + inherit (config.serverConfig) ports vhosts; in { services.postgresql = { @@ -80,16 +80,16 @@ in enable_registration = true; registration_requires_token = true; registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path; - # enable_registration_without_verification = true; - # mainLogConfig = ./matrix_synapse_log_config.yaml; + # enable_registration_without_verification = true; + # mainLogConfig = ./matrix_synapse_log_config.yaml; - # registrations_require_3pid = [ "email" ]; + # registrations_require_3pid = [ "email" ]; database = { name = "psycopg2"; args = { host = "localhost"; - port = 5432; + port = config.services.postgresql.port; dbname = "synapse"; user = "synapse"; cp_min = 5; @@ -129,17 +129,17 @@ in enable = true; virtualHosts."${domain}" = { forceSSL = true; - enableACME = false; # use the cert above, not some weird one that matrix-synapse module supplies + enableACME = lib.mkForce false; # use the cert above, not some weird one that matrix-synapse module supplies useACMEHost = domain; locations."/.well-known/matrix/server" = { - return = "200 '{\"m.server\":\"${matrix_host}:443\"}'"; + return = "200 '{\"m.server\":\"${vhosts.matrix_host.host}:443\"}'"; extraConfig = '' default_type application/json; add_header Access-Control-Allow-Origin *; add_header Accept-Ranges bytes;''; }; locations."/.well-known/matrix/client" = { - return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${matrix_host}\"}}'"; + return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${vhosts.matrix_host.host}\"}}'"; extraConfig = '' add_header Access-Control-Allow-Origin *; default_type application/json; diff --git a/modules/nextcloud.nix b/modules/nextcloud.nix index d953b44..19313df 100644 --- a/modules/nextcloud.nix +++ b/modules/nextcloud.nix @@ -5,9 +5,7 @@ ... }: let - inherit (config.networking) domain; - nextcloud_host = "cloud.${domain}"; - nextcloud_port = 8083; + inherit (config.serverConfig) ports vhosts; in { services.postgresql = { @@ -21,7 +19,6 @@ in ]; }; - security.acme.certs."${domain}".extraDomainNames = [ nextcloud_host ]; age.secrets = { nextcloud_admin_pass = { file = ../secrets/nextcloud_admin_pass.age; @@ -34,13 +31,13 @@ in services.redis.servers.nextcloud = { enable = true; bind = "::1"; - port = 6379; + port = ports.redis_nextcloud_port.port; }; systemd.services.nextcloud-setup.serviceConfig.ExecStartPost = pkgs.writeScript "nextcloud-redis.sh" '' #!${pkgs.runtimeShell} nextcloud-occ config:system:set redis 'host' --value '::1' --type string - nextcloud-occ config:system:set redis 'port' --value 6379 --type integer + nextcloud-occ config:system:set redis '${builtins.toString config.services.redis.servers.nextcloud.port}' --value 6379 --type integer nextcloud-occ config:system:set memcache.local --value '\OC\Memcache\Redis' --type string nextcloud-occ config:system:set memcache.locking --value '\OC\Memcache\Redis' --type string ''; @@ -48,13 +45,14 @@ in services.nextcloud = { enable = true; https = true; - hostName = nextcloud_host; + hostName = vhosts.nextcloud_host.host; package = pkgs.nextcloud28; caching.redis = true; - # extraApps = with config.services.nextcloud.package.packages.apps; [ - # news contacts calendar tasks; - # ]; + extraApps = { + inherit (config.services.nextcloud.package.packages.apps) calendar; + }; + config = { adminpassFile = config.age.secrets.nextcloud_admin_pass.path; dbuser = "nextcloud"; @@ -67,7 +65,7 @@ in filelocking.enabled = true; redis = { host = "localhost"; - port = 6379; + port = config.services.redis.servers.nextcloud.port; timeout = 0.0; }; }; @@ -75,13 +73,4 @@ in "opcache.interned_strings_buffer" = "12"; }; }; - - services.nginx = { - enable = true; - virtualHosts."${nextcloud_host}" = { - serverName = nextcloud_host; - forceSSL = true; - useACMEHost = domain; - }; - }; } diff --git a/modules/prometheus.nix b/modules/prometheus.nix index 32ffead..5b44aa0 100644 --- a/modules/prometheus.nix +++ b/modules/prometheus.nix @@ -1,26 +1,22 @@ -{ config, ... }: +{ config, lib, ... }: let - inherit (config.networking) domain; - prometheus_host = "prometheus.${domain}"; - prometheus_port = 9090; # netstat -nlp | grep 9090 + inherit (config.serverConfig) ports vhosts; in { - security.acme.certs."${domain}".extraDomainNames = [ prometheus_host ]; - services.prometheus = { enable = true; - port = prometheus_port; + port = vhosts.prometheus_host.port; globalConfig.scrape_interval = "15s"; scrapeConfigs = [ { job_name = "chrysalis"; static_configs = [ { - targets = [ - "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" - "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}" - "127.0.0.1:${toString config.services.prometheus.exporters.postgres.port}" - ]; + targets = + with lib; + map (v: "127.0.0.1:${toString v.port}") ( + filter (v: (isAttrs v) && v.enable) (attrValues config.services.prometheus.exporters) + ); } ]; } @@ -35,20 +31,7 @@ in node = { enable = true; enabledCollectors = [ "systemd" ]; - port = 9002; - }; - }; - }; - - services.nginx = { - enable = true; - virtualHosts."${prometheus_host}" = { - serverName = prometheus_host; - forceSSL = true; - useACMEHost = domain; - locations."/" = { - # proxyPass = "http://127.0.0.1:${builtins.toString config.services.prometheus.port}"; - return = "307 https://${domain}"; # nuh uh, no raw prometheus access for you! + port = ports.node_exporter.port; }; }; }; diff --git a/modules/ptero.nix b/modules/ptero.nix deleted file mode 100644 index 2cfaed6..0000000 --- a/modules/ptero.nix +++ /dev/null @@ -1,137 +0,0 @@ -{ config, pkgs, ... }: -let - inherit (config.networking) domain; - root_email = "contact@${domain}"; - ptero_host = "ptero.${domain}"; - DATA_DIR = "/var/lib/pterodactylpanel"; - panel_user = "pterodactyl"; - local_bridge = "ptero-local-br"; - ptero_ver = "1.11.5"; - ptero_port = "8042"; -in -{ - users.users.${panel_user} = { - isSystemUser = true; - extraGroups = [ "docker" ]; - group = panel_user; - }; - users.groups.${panel_user} = { }; - - age.secrets.ptero_env = { - file = ../secrets/ptero_env.age; - }; - - systemd.services.init-ptero-data-dir = { - description = "Create the pterodactyl panel data dir"; - wantedBy = [ "multi-user.target" ]; - - serviceConfig.Type = "oneshot"; - script = '' - mkdir -p ${DATA_DIR}/database - mkdir -p ${DATA_DIR}/cache - mkdir -p ${DATA_DIR}/panel/var - mkdir -p ${DATA_DIR}/panel/logs - mkdir -p ${DATA_DIR}/panel/nginx - chown ${panel_user}:${panel_user} -R ${DATA_DIR} - chmod +777 -R ${DATA_DIR} - ''; - }; - - virtualisation.oci-containers.backend = "podman"; - - systemd.services.init-ptero-local-network = { - description = "Create the network bridge ${local_bridge} for ptero."; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - - serviceConfig.Type = "oneshot"; - script = - let - podmancli = "${config.virtualisation.podman.package}/bin/podman"; - in - '' - check=$(${podmancli} pod ls | grep "ptero" || true) - if [ -z "$check" ]; then - ${podmancli} pod create -p "${ptero_port}:80" ptero - else - echo "ptero pod already exists" - fi - ''; - }; - - virtualisation.oci-containers.containers."ptero-mysql" = { - image = "library/mysql:8.0"; - workdir = "${DATA_DIR}/database"; - extraOptions = [ "--pod=ptero" ]; - environment = { - "MYSQL_USER" = "pterodactyl"; - "MYSQL_DATABASE" = "panel"; - }; - environmentFiles = [ config.age.secrets.ptero_env.path ]; - volumes = [ - "${DATA_DIR}/database:/var/lib/mysql" - "${DATA_DIR}/database:${DATA_DIR}/database" - ]; - cmd = [ "--default-authentication-plugin=mysql_native_password" ]; - }; - - virtualisation.oci-containers.containers."ptero-cache" = { - image = "redis:alpine"; - workdir = "${DATA_DIR}/cache"; - volumes = [ "${DATA_DIR}/cache:${DATA_DIR}/cache" ]; - extraOptions = [ "--pod=ptero" ]; - }; - - virtualisation.oci-containers.containers."ptero-panel" = { - image = "ghcr.io/pterodactyl/panel:v${ptero_ver}"; - volumes = [ - "${DATA_DIR}/panel/var/:/app/var/" - "${DATA_DIR}/panel/logs/:/app/storage/logs" - "${DATA_DIR}/panel/nginx/:/etc/nginx/conf.d/" - ]; - extraOptions = [ "--pod=ptero" ]; - environment = { - "APP_URL" = "https://${ptero_host}"; - "APP_TIMEZONE" = "Europe/Berlin"; - "APP_SERVICE_AUTHOR" = root_email; - - "MAIL_FROM" = "noreply@${domain}"; - "MAIL_DRIVER" = "smtp"; - "MAIL_HOST" = "mail"; - "MAIL_PORT" = "25"; - "MAIL_USERNAME" = ""; - "MAIL_PASSWORD" = ""; - "MAIL_ENCRYPTION" = "true"; - - "APP_ENV" = "production"; - "APP_ENVIRONMENT_ONLY" = "false"; - "CACHE_DRIVER" = "redis"; - "SESSION_DRIVER" = "redis"; - "QUEUE_DRIVER" = "redis"; - "REDIS_HOST" = "127.0.0.1"; - "DB_HOST" = "127.0.0.1"; - "TRUSTED_PROXIES" = "*"; - }; - labels = { - "traefik.http.routers.pterodactyl_panel.entrypoints" = "web"; - }; - environmentFiles = [ config.age.secrets.ptero_env.path ]; - }; - - security.acme.certs."${domain}".extraDomainNames = [ ptero_host ]; - services.nginx = { - enable = true; - virtualHosts."${ptero_host}" = { - serverName = ptero_host; - forceSSL = true; - useACMEHost = domain; - locations."/" = { - proxyPass = "http://127.0.0.1:${ptero_port}"; - }; - }; - }; - - environment.systemPackages = with pkgs; [ - (writeShellScriptBin "ptero-nix" "${config.virtualisation.podman.package}/bin/podman exec -it ptero-panel php artisan $@") - ]; -} diff --git a/modules/puffer.nix b/modules/puffer.nix index 54d6370..55b8c48 100644 --- a/modules/puffer.nix +++ b/modules/puffer.nix @@ -6,7 +6,6 @@ ... }: let - inherit (config.networking) domain; inherit (config.serverConfig) ports vhosts; in { @@ -14,7 +13,7 @@ in enable = true; environment = { PUFFER_WEB_HOST = ":${builtins.toString vhosts.puffer_host.port}"; - PUFFER_DAEMON_SFTP_HOST = ":${builtins.toString ports.puffer_sftp_port}"; + PUFFER_DAEMON_SFTP_HOST = ":${builtins.toString ports.puffer_sftp_port.port}"; }; extraPackages = with pkgs; [ ]; extraGroups = [ "docker" ];