diff --git a/hosts/ext-julia/default.nix b/hosts/ext-julia/default.nix index f3953c0..92c90f8 100644 --- a/hosts/ext-julia/default.nix +++ b/hosts/ext-julia/default.nix @@ -3,16 +3,27 @@ ./boot.nix ./hardware-configuration.nix - ../../modules/hosting/wordpress-simple/kiezpalme.nix - ../../modules/hosting/wordpress-simple/pertineo.nix + #../../modules/hosting/wordpress-simple/kiezpalme.nix + #../../modules/hosting/wordpress-simple/pertineo.nix + ../../modules/hosting/wordpress.nix ../../modules/sec_auth/ssh-server.nix ../../system_profiles/server.nix ]; - services.mysql = { + #services.mysql = { + # enable = true; + # package = pkgs.mariadb; + #}; + + services.cWordpress."example-site" = { enable = true; - package = pkgs.mariadb; + sitePort = 80; + }; + + services.cWordpress."example-site2" = { + enable = true; + sitePort = 81; }; services.openssh.ports = [11522]; diff --git a/modules/game/server/luanti/cleanup-and-pull.nix b/modules/game/server/luanti/cleanup-and-pull.nix new file mode 100644 index 0000000..af5dd69 --- /dev/null +++ b/modules/game/server/luanti/cleanup-and-pull.nix @@ -0,0 +1,3 @@ +{pkgs, ...}: { + +} diff --git a/modules/hosting/wordpress.nix b/modules/hosting/wordpress.nix index efa46c6..fb22fb9 100644 --- a/modules/hosting/wordpress.nix +++ b/modules/hosting/wordpress.nix @@ -1,133 +1,186 @@ -{config, pkgs, lib, ...}: - -let - cfg = config.services.cWordpress; -in { - options = { - services.cWordpress = { +{ + config, + pkgs, + lib, + ... +}: let + siteOpts = lib.types.submodule ({ + options = { enable = lib.mkEnableOption "custom WordPress service"; siteName = lib.mkOption { - type = lib.types.str; - default = "example-name"; - description = ""; # TODO: + type = lib.types.nullOr lib.types.str; + default = null; }; + sitePort = lib.mkOption { - type = lib.types.port; - default = 80; - description = ""; # TODO: + type = lib.types.port; + default = 80; + description = ""; # TODO: }; + + #siteDataDir = lib.mkOption { + # type = lib.types.str; + # default = "/srv/http/${siteName}"; + #}; + #siteUser = lib.mkOption { + # type = lib.types.str; + # default = "user-${siteName}"; + #}; + #siteGroup = lib.mkOption { + # type = lib.types.str; + # default = config.services.nginx.user; + #}; + #siteUserPhp = lib.mkOption { + # type = lib.types.str; + # default = "${siteUser}-php"; + #}; + #siteGroupPhp = lib.mkOption { + # type = lib.types.str; + # default = siteUserPhp; + #}; + #sitePhpPool = lib.mkOption { + # type = lib.types.str; + # default = "wordpress-${siteName}"; + #}; + }; + }); + #sites = builtins.mapAttrs (siteName2: siteConfig: + # let + # siteName = if siteConfig.siteName != null then siteConfig.siteName else siteName2; + # in siteConfig // {siteName = siteName;} + #) cfg; + # + #enabledSites = lib.filterAttrs (name: config: config.enable) cfg; + #magie = banana: builtins.mapAttrs (siteName: site: banana) enabledSites; + + mkMergeTopLevel = names: attrs: + lib.getAttrs names ( + lib.mapAttrs (k: v: lib.mkMerge v) (lib.foldAttrs (n: a: [n] ++ a) [] attrs) + ); + + cfg = config.services.cWordpress; +in { + options = { + services.cWordpress = lib.mkOption { + type = lib.types.attrsOf siteOpts; + + default = {}; + description = ""; # TODO: }; }; - config = let - siteDataDir = "/srv/http/${cfg.siteName}"; - siteUser = "user-${cfg.siteName}"; - siteGroup = config.services.nginx.user; - siteUserPhp = "${siteUser}-php"; - siteGroupPhp = siteUserPhp; - sitePhpPool = "wordpress-${cfg.siteName}"; - in lib.mkIf cfg.enable { - users = { - users = { - "${siteUser}" = { - isSystemUser = true; - group = siteGroup; - home = siteDataDir; - createHome = false; - shell = "${pkgs.shadow}/bin/nologin"; - }; + config = mkMergeTopLevel ["users" "services" "environment" "system"] (lib.mapAttrsToList ( + siteName: opts: let + siteDataDir = "/srv/http/${siteName}"; + siteUser = "user-${siteName}"; + siteGroup = config.services.nginx.user; + siteUserPhp = "${siteUser}-php"; + siteGroupPhp = siteUserPhp; + sitePhpPool = "wordpress-${siteName}"; + in { + users = { + users = { + "${siteUser}" = { + isSystemUser = true; + group = siteGroup; + home = siteDataDir; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; - ### 3) Service account for PHP-FPM pool - "${siteUserPhp}" = { - isSystemUser = true; - group = siteGroupPhp; - home = "/var/empty"; - createHome = false; - shell = "${pkgs.shadow}/bin/nologin"; - }; - }; - - groups = { - "${siteGroup}" = {}; - "${siteGroupPhp}" = {}; - }; - }; - - services = { - mysql = { - enable = true; - package = pkgs.mariadb; - }; - - phpfpm.pools."${sitePhpPool}" = { - user = siteUserPhp; - group = siteGroupPhp; - - settings = { - # Socket ownership so Nginx can connect - "listen.owner" = config.services.nginx.user; - "listen.group" = siteGroupPhp; - "listen.mode" = "0660"; - - # Dynamic process management tuned for small sites - pm = "dynamic"; - "pm.max_children" = "5"; - "pm.start_servers" = "2"; - "pm.min_spare_servers" = "1"; - "pm.max_spare_servers" = "3"; - - # Logging - "catch_workers_output" = true; - "php_admin_flag[log_errors]" = true; - }; - }; - - nginx = { - enable = true; - virtualHosts."${cfg.siteName}" = { - default = true; - root = siteDataDir; - - listen = [ - { - addr = "0.0.0.0"; - port = cfg.sitePort; - ssl = false; - } - ]; - - # Fallback for pretty permalinks - locations."/" = { - tryFiles = "$uri $uri/ /index.php?$args"; + "${siteUserPhp}" = { + isSystemUser = true; + group = siteGroupPhp; + home = "/var/empty"; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; }; - extraConfig = '' - index index.php; - ''; - # 6.2 Handle PHP scripts - locations."~ \\.php$" = { - extraConfig = '' - fastcgi_split_path_info ^(.+\\.php)(/.+)$; - fastcgi_pass unix:${config.services.phpfpm.pools."${sitePhpPool}".socket}; - fastcgi_index index.php; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - include ${pkgs.nginx}/conf/fastcgi_params; - ''; + groups = { + "${siteGroup}" = {}; + "${siteGroupPhp}" = {}; }; }; - }; - }; - # Bootstrap WordPress on activation - environment.systemPackages = [pkgs.unzip]; # TODO: why is unzip needed here? - system.activationScripts."setupWordpress-${cfg.siteName}".text = '' - mkdir -p ${siteDataDir} - if [ ! -f ${siteDataDir}/wp-config.php ]; then - cp -R ${pkgs.wordpress}/share/wordpress/* ${siteDataDir}/ - chown -R ${siteUser}:${siteGroup} ${siteDataDir} - chmod -R 755 ${siteDataDir} - fi - ''; - }; + services = { + mysql = { + enable = true; + package = pkgs.mariadb; + }; + + phpfpm.pools."${sitePhpPool}" = { + user = siteUserPhp; + group = siteGroupPhp; + + settings = { + # Socket ownership so Nginx can connect + "listen.owner" = config.services.nginx.user; + "listen.group" = siteGroupPhp; + "listen.mode" = "0660"; + + # Dynamic process management tuned for small sites + pm = "dynamic"; + "pm.max_children" = "5"; + "pm.start_servers" = "2"; + "pm.min_spare_servers" = "1"; + "pm.max_spare_servers" = "3"; + + # Logging + "catch_workers_output" = true; + "php_admin_flag[log_errors]" = true; + }; + }; + + nginx = { + enable = true; + virtualHosts."${siteName}" = { + default = true; + root = siteDataDir; + + listen = [ + { + addr = "0.0.0.0"; + port = opts.sitePort; + ssl = false; + } + ]; + + # Fallback for pretty permalinks + locations."/" = { + tryFiles = "$uri $uri/ /index.php?$args"; + }; + + extraConfig = '' + index index.php; + ''; + + # Handle PHP scripts + locations."~ \\.php$" = { + extraConfig = '' + fastcgi_split_path_info ^(.+\\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools."${sitePhpPool}".socket}; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include ${pkgs.nginx}/conf/fastcgi_params; + ''; + }; + }; + }; + }; + + # Bootstrap WordPress on activation + environment.systemPackages = [pkgs.unzip]; # TODO: why is unzip needed here? + system.activationScripts."setupWordpress-${siteName}".text = '' + mkdir -p ${siteDataDir} + if [ ! -f ${siteDataDir}/wp-config.php ]; then + cp -R ${pkgs.wordpress}/share/wordpress/* ${siteDataDir}/ + chown -R ${siteUser}:${siteGroup} ${siteDataDir} + chmod -R 755 ${siteDataDir} + fi + ''; # TODO: tighten permissions (not 755) + } + ) + cfg); } diff --git a/modules/hosting/wordpress_from_krebs.nix b/modules/hosting/wordpress_from_krebs.nix new file mode 100644 index 0000000..28c143f --- /dev/null +++ b/modules/hosting/wordpress_from_krebs.nix @@ -0,0 +1,186 @@ +{ + config, + pkgs, + lib, + ... +}: let + siteOpts = lib.types.submodule ({name, ...}: { + options = { + enable = lib.mkEnableOption "custom WordPress service"; + + siteName = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + + sitePort = lib.mkOption { + type = lib.types.port; + default = 80; + description = ""; # TODO: + }; + + #siteDataDir = lib.mkOption { + # type = lib.types.str; + # default = "/srv/http/${siteName}"; + #}; + #siteUser = lib.mkOption { + # type = lib.types.str; + # default = "user-${siteName}"; + #}; + #siteGroup = lib.mkOption { + # type = lib.types.str; + # default = config.services.nginx.user; + #}; + #siteUserPhp = lib.mkOption { + # type = lib.types.str; + # default = "${siteUser}-php"; + #}; + #siteGroupPhp = lib.mkOption { + # type = lib.types.str; + # default = siteUserPhp; + #}; + #sitePhpPool = lib.mkOption { + # type = lib.types.str; + # default = "wordpress-${siteName}"; + #}; + }; + }); + #sites = builtins.mapAttrs (siteName2: siteConfig: + # let + # siteName = if siteConfig.siteName != null then siteConfig.siteName else siteName2; + # in siteConfig // {siteName = siteName;} + #) cfg; + # + #enabledSites = lib.filterAttrs (name: config: config.enable) cfg; + #magie = banana: builtins.mapAttrs (siteName: site: banana) enabledSites; + + mkMergeTopLevel = names: attrs: + lib.getAttrs names ( + lib.mapAttrs (k: v: lib.mkMerge v) (lib.foldAttrs (n: a: [n] ++ a) [] attrs) + ); + + cfg = config.services.cWordpress; + + opts = siteName: { + siteDataDir = "/srv/http/${siteName}"; + siteUser = "user-${siteName}"; + siteGroup = config.services.nginx.user; + siteUserPhp = "${siteUser}-php"; + siteGroupPhp = siteUserPhp; + sitePhpPool = "wordpress-${siteName}"; + }; +in { + options = { + services.cWordpress = lib.mkOption { + type = lib.types.attrsOf siteOpts; + + default = {}; + description = ""; # TODO: + }; + }; + + config = { + users.users = lib.mapAttrs' (siteName: siteConfig: { + "user-${siteName}" = { + isSystemUser = true; + group = config.services.nginx.user; + home = "/srv/http/${siteName}"; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; + + "user-${siteName}-php" = { + isSystemUser = true; + group = "user-${siteName}-php"; + home = "/var/empty"; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; + }) cfg; + + users.groups = lib.mapAttrs' (siteName: siteConfig: { + ${config.services.nginx.user} = {}; + "user-${siteName}-php" = {}; + }) cfg; + + services = { + mysql = { + enable = true; + package = pkgs.mariadb; + }; + + phpfpm.pools."${sitePhpPool}" = { + user = siteUserPhp; + group = siteGroupPhp; + + settings = { + # Socket ownership so Nginx can connect + "listen.owner" = config.services.nginx.user; + "listen.group" = siteGroupPhp; + "listen.mode" = "0660"; + + # Dynamic process management tuned for small sites + pm = "dynamic"; + "pm.max_children" = "5"; + "pm.start_servers" = "2"; + "pm.min_spare_servers" = "1"; + "pm.max_spare_servers" = "3"; + + # Logging + "catch_workers_output" = true; + "php_admin_flag[log_errors]" = true; + }; + }; + + nginx = { + enable = true; + virtualHosts."${siteName}" = { + default = true; + root = siteDataDir; + + listen = [ + { + addr = "0.0.0.0"; + port = opts.sitePort; + ssl = false; + } + ]; + + # Fallback for pretty permalinks + locations."/" = { + tryFiles = "$uri $uri/ /index.php?$args"; + }; + + extraConfig = '' + index index.php; + ''; + + # Handle PHP scripts + locations."~ \\.php$" = { + extraConfig = '' + fastcgi_split_path_info ^(.+\\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools."${sitePhpPool}".socket}; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include ${pkgs.nginx}/conf/fastcgi_params; + ''; + }; + }; + }; + }; + + # Bootstrap WordPress on activation + environment.systemPackages = [pkgs.unzip]; # TODO: why is unzip needed here? + system.activationScripts."setupWordpress-${siteName}".text = '' + mkdir -p ${siteDataDir} + if [ ! -f ${siteDataDir}/wp-config.php ]; then + cp -R ${pkgs.wordpress}/share/wordpress/* ${siteDataDir}/ + chown -R ${siteUser}:${siteGroup} ${siteDataDir} + chmod -R 755 ${siteDataDir} + fi + ''; # TODO: tighten permissions (not 755) + } + ) + cfg); +} + diff --git a/modules/hosting/wordpress_new.nix b/modules/hosting/wordpress_new.nix new file mode 100644 index 0000000..0bb7752 --- /dev/null +++ b/modules/hosting/wordpress_new.nix @@ -0,0 +1,138 @@ +{ + config, + pkgs, + lib, + ... +}: let + cfg = config.services.cWordpress; +in { + options = { + services.cWordpress = lib.mkOption { + type = lib.types.attrsOf (lib.types.submodule { + options.enable = lib.mkEnableOption "custom WordPress service"; + + options.sitePort = lib.mkOption { + type = lib.types.port; + default = 80; + description = ""; # TODO: + }; + }); + default = {}; + description = ""; # TODO: per-site WordPress configs + }; + }; + + config = lib.foldAttrs' (siteName: cfg: let + siteDataDir = "/srv/http/${siteName}"; + siteUser = "user-${siteName}"; + siteGroup = config.services.nginx.user; + siteUserPhp = "${siteUser}-php"; + siteGroupPhp= siteUserPhp; + sitePhpPool = "wordpress-${siteName}"; + in + lib.mkIf cfg.enable { + users = { + users = { + "${siteUser}" = { + isSystemUser = true; + group = siteGroup; + home = siteDataDir; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; + + ### 3) Service account for PHP-FPM pool + "${siteUserPhp}" = { + isSystemUser = true; + group = siteGroupPhp; + home = "/var/empty"; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; + }; + + groups = { + "${siteGroup}" = {}; + "${siteGroupPhp}" = {}; + }; + }; + + services = { + mysql = { + enable = true; + package = pkgs.mariadb; + }; + + phpfpm.pools."${sitePhpPool}" = { + user = siteUserPhp; + group = siteGroupPhp; + + settings = { + # Socket ownership so Nginx can connect + "listen.owner" = config.services.nginx.user; + "listen.group" = siteGroupPhp; + "listen.mode" = "0660"; + + # Dynamic process management tuned for small sites + pm = "dynamic"; + "pm.max_children" = "5"; + "pm.start_servers" = "2"; + "pm.min_spare_servers" = "1"; + "pm.max_spare_servers" = "3"; + + # Logging + "catch_workers_output" = true; + "php_admin_flag[log_errors]" = true; + }; + }; + + nginx = { + enable = true; + virtualHosts."${siteName}" = { + default = true; + root = siteDataDir; + + listen = [ + { + addr = "0.0.0.0"; + port = cfg.sitePort; + ssl = false; + } + ]; + + # Fallback for pretty permalinks + locations."/" = { + tryFiles = "$uri $uri/ /index.php?$args"; + }; + + extraConfig = '' + index index.php; + ''; + + # Handle PHP scripts + locations."~ \\.php$" = { + extraConfig = '' + fastcgi_split_path_info ^(.+\\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools."${sitePhpPool}".socket}; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + include ${pkgs.nginx}/conf/fastcgi_params; + ''; + }; + }; + }; + }; + + # Bootstrap WordPress on activation + environment.systemPackages = [pkgs.unzip]; # TODO: why is unzip needed here? + system.activationScripts."setupWordpress-${siteName}".text = '' + mkdir -p ${siteDataDir} + if [ ! -f ${siteDataDir}/wp-config.php ]; then + cp -R ${pkgs.wordpress}/share/wordpress/* ${siteDataDir}/ + chown -R ${siteUser}:${siteGroup} ${siteDataDir} + chmod -R 755 ${siteDataDir} + fi + ''; + }}) {} cfg; +} + diff --git a/modules/hosting/wordpress_refactor.nix b/modules/hosting/wordpress_refactor.nix new file mode 100644 index 0000000..953f5f9 --- /dev/null +++ b/modules/hosting/wordpress_refactor.nix @@ -0,0 +1,145 @@ +{ + config, + pkgs, + lib, + ... +}: let + siteOpts = lib.types.submodule ({...}: { + options = { + enable = lib.mkEnableOption "custom WordPress service"; + + siteName = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + }; + + sitePort = lib.mkOption { + type = lib.types.port; + default = 80; + description = ""; # TODO: + }; + }; + }); + + cfg = config.services.cWordpress; + + opts = siteName: rec { + siteDataDir = "/srv/http/${siteName}"; + siteUser = "user-${siteName}"; + siteGroup = config.services.nginx.user; + siteUserPhp = "${siteUser}-php"; + siteGroupPhp = siteUserPhp; + sitePhpPool = "wordpress-${siteName}"; + }; +in { + options = { + services.cWordpress = lib.mkOption { + type = lib.types.attrsOf siteOpts; + + default = {}; + description = ""; # TODO: + }; + }; + + config = { + users.users = lib.mapAttrs' (siteName: siteConfig: { + "user-${siteName}" = { + isSystemUser = true; + group = config.services.nginx.user; + home = "/srv/http/${siteName}"; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; + + "user-${siteName}-php" = { + isSystemUser = true; + group = "user-${siteName}-php"; + home = "/var/empty"; + createHome = false; + shell = "${pkgs.shadow}/bin/nologin"; + }; + }) cfg; + + users.groups = lib.mapAttrs' (siteName: siteConfig: { + ${config.services.nginx.user} = {}; + "user-${siteName}-php" = {}; + }) cfg; + + # services = { + # mysql = { + # enable = true; + # package = pkgs.mariadb; + # }; + # + # phpfpm.pools."${sitePhpPool}" = { + # user = siteUserPhp; + # group = siteGroupPhp; + # + # settings = { + # # Socket ownership so Nginx can connect + # "listen.owner" = config.services.nginx.user; + # "listen.group" = siteGroupPhp; + # "listen.mode" = "0660"; + # + # # Dynamic process management tuned for small sites + # pm = "dynamic"; + # "pm.max_children" = "5"; + # "pm.start_servers" = "2"; + # "pm.min_spare_servers" = "1"; + # "pm.max_spare_servers" = "3"; + # + # # Logging + # "catch_workers_output" = true; + # "php_admin_flag[log_errors]" = true; + # }; + # }; + # + # nginx = { + # enable = true; + # virtualHosts."${siteName}" = { + # default = true; + # root = siteDataDir; + # + # listen = [ + # { + # addr = "0.0.0.0"; + # port = opts.sitePort; + # ssl = false; + # } + # ]; + # + # # Fallback for pretty permalinks + # locations."/" = { + # tryFiles = "$uri $uri/ /index.php?$args"; + # }; + # + # extraConfig = '' + # index index.php; + # ''; + # + # # Handle PHP scripts + # locations."~ \\.php$" = { + # extraConfig = '' + # fastcgi_split_path_info ^(.+\\.php)(/.+)$; + # fastcgi_pass unix:${config.services.phpfpm.pools."${sitePhpPool}".socket}; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + # include ${pkgs.nginx}/conf/fastcgi_params; + # ''; + # }; + # }; + # }; + # }; + # + # # Bootstrap WordPress on activation + # environment.systemPackages = [pkgs.unzip]; # TODO: why is unzip needed here? + # system.activationScripts."setupWordpress-${siteName}".text = '' + # mkdir -p ${siteDataDir} + # if [ ! -f ${siteDataDir}/wp-config.php ]; then + # cp -R ${pkgs.wordpress}/share/wordpress/* ${siteDataDir}/ + # chown -R ${siteUser}:${siteGroup} ${siteDataDir} + # chmod -R 755 ${siteDataDir} + # fi + # ''; # TODO: tighten permissions (not 755) + }; +} diff --git a/outputs.nix b/outputs.nix index 98bff11..a4f6976 100644 --- a/outputs.nix +++ b/outputs.nix @@ -17,12 +17,12 @@ in { #jitsi = {stateVersion = "24.11";}; - # game-luanti = { - # stateVersion = "25.05"; - # unstable = true; - # }; + #game-luanti = { + # stateVersion = "25.05"; + # unstable = true; + #}; - ext-julia = {stateVersion = "24.11";}; + #ext-julia = {stateVersion = "24.11";}; }; # Your custom packages