globalized port/vhost config: move modules

This commit is contained in:
Grimmauld 2024-05-09 14:55:02 +02:00
parent 181f108308
commit dca29c0156
Signed by: Grimmauld
GPG key ID: C2946668769F91FB
11 changed files with 156 additions and 286 deletions

View file

@ -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";
};
};
};

View file

@ -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;

View file

@ -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}";
};
};
};
}

View file

@ -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}";
};
};
};
}

View file

@ -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;
};
};
};

View file

@ -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 = {

View file

@ -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;

View file

@ -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;
};
};
}

View file

@ -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;
};
};
};

View file

@ -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 $@")
];
}

View file

@ -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" ];