From 3e95cd0310cab23f1df128c5945cc442688061fd Mon Sep 17 00:00:00 2001 From: kurogeek Date: Mon, 24 Nov 2025 13:40:14 +0000 Subject: [PATCH] mob next [ci-skip] [ci skip] [skip ci] lastFile:modules/nixos/think-gtcm.nix --- modules/nixos/think-gtcm.nix | 238 ++++++++++++++++++++++++----------- 1 file changed, 166 insertions(+), 72 deletions(-) diff --git a/modules/nixos/think-gtcm.nix b/modules/nixos/think-gtcm.nix index b8ea322..b6c981e 100644 --- a/modules/nixos/think-gtcm.nix +++ b/modules/nixos/think-gtcm.nix @@ -11,14 +11,33 @@ let defaultUser = "gtcm"; defaultGroup = "gtcm"; - env-nonfile-values = lib.attrsets.filterAttrs (n: v: !lib.strings.hasSuffix "_FILE" n) cfg.settings; - - think-gtcm-maintenance = pkgs.writeShellScript "think-gtcm-maintenance.sh" '' - set -a - ${lib.strings.toShellVars env-nonfile-values} - set +a + php = pkgs.php83; + artisan = pkgs.writeShellScript "gtcm" '' + #! #{pkgs.runtimeShell} + cd ${think-gtcm} + sudo() { + if [[ "$USER" != ${cfg.user} ]]; then + exec /run/wrappers/bin/sudo -u ${cfg.user} "$@" + else + exec "$@" + fi + } + sudo ${php} artisan "$@" ''; + artisan-be = pkgs.writeShellScript "gtcm-be" '' + #! #{pkgs.runtimeShell} + cd ${think-gtcm} + sudo() { + if [[ "$USER" != ${cfg.user} ]]; then + exec /run/wrappers/bin/sudo -u ${cfg.user} "$@" + else + exec "$@" + fi + } + sudo ${php} artisan "$@" + ''; + in { options.services.think-greaterchiangmai = { @@ -64,64 +83,54 @@ in }; settings = lib.mkOption { + lib.type = + with lib.types; + attrsOf ( + nullOr ( + either + (oneOf [ + bool + int + port + path + str + ]) + (submodule { + options = { + _secret = mkOption { + type = nullOr str; + description = '' + The path to a file containing the value the + option should be set to in the final + configuration file. + ''; + }; + }; + }) + ) + ); default = { }; description = '' Options for settings environment variables ''; example = lib.literalExpression '' { - APP_NAME=Laravel - APP_ENV=local - APP_KEY= - APP_DEBUG=true - APP_URL=http://localhost + APP_NAME = "Laravel"; + APP_ENV = "local"; + APP_KEY = "key"; + APP_DEBUG = true; + APP_URL = "http://localhost"; - LOG_CHANNEL=stack - LOG_DEPRECATIONS_CHANNEL=null - LOG_LEVEL=debug + LOG_CHANNEL = "stack"; + LOG_DEPRECATIONS_CHANNEL = "null"; + LOG_LEVEL = "debug"; - DB_CONNECTION=mysql - DB_HOST=127.0.0.1 - DB_PORT=3306 - DB_DATABASE=laravel - DB_USERNAME=root - DB_PASSWORD= - - BROADCAST_DRIVER=log - CACHE_DRIVER=file - FILESYSTEM_DISK=local - QUEUE_CONNECTION=sync - SESSION_DRIVER=file - SESSION_LIFETIME=120 - - MEMCACHED_HOST=127.0.0.1 - - REDIS_HOST=127.0.0.1 - REDIS_PASSWORD=null - REDIS_PORT=6379 - - MAIL_MAILER=smtp - MAIL_HOST=mailpit - MAIL_PORT=1025 - MAIL_USERNAME=null - MAIL_PASSWORD=null - MAIL_ENCRYPTION=null - MAIL_FROM_ADDRESS="hello@example.com" - MAIL_FROM_NAME="''${APP_NAME}" - - AWS_ACCESS_KEY_ID= - AWS_SECRET_ACCESS_KEY= - AWS_DEFAULT_REGION=us-east-1 - AWS_BUCKET= - AWS_USE_PATH_STYLE_ENDPOINT=false - - PUSHER_APP_ID= - PUSHER_APP_KEY= - PUSHER_APP_SECRET= - PUSHER_HOST= - PUSHER_PORT=443 - PUSHER_SCHEME=https - PUSHER_APP_CLUSTER=mt1 + DB_CONNECTION = "mysql"; + DB_HOST = "127.0.0.1"; + DB_PORT = "3306"; + DB_DATABASE = "laravel"; + DB_USERNAME = "root"; + DB_PASSWORD = ""; } ''; type = lib.types.submodule { @@ -201,11 +210,12 @@ in }; users.groups.${cfg.group} = { }; - services.phpfpm.pools.think-greaterchiangmai = { + services.phpfpm.pools.think-gtcm = { inherit (cfg) user group; + phpPackage = php; settings = { - "listen.owner" = config.services.nginx.user; - "listen.group" = config.services.nginx.group; + "listen.owner" = cfg.user; + "listen.group" = cfg.group; "listen.mode" = "0600"; "pm" = lib.mkDefault "dynamic"; "pm.max_children" = lib.mkDefault 10; @@ -222,33 +232,117 @@ in systemd.services.think-gtcm-setup = { description = "think.greaterchiangmai installation"; - requiredBy = [ "phpfpm-think-greaterchiangmai.service" ]; - before = [ "phpfpm-think-greaterchiangmai.service" ]; + requiredBy = [ "phpfpm-think-gtcm.service" ]; + before = [ "phpfpm-think-gtcm.service" ]; requires = [ "mysql.service" ]; after = [ "mysql.service" ]; - path = [ config.services.phpfpm.phpPackage ]; serviceConfig = { + type = "oneshot"; RemainAfterExit = true; User = cfg.user; UMask = 77; - WorkingDirectory = "${agorakit}"; - RuntimeDirectory = "agorakit/cache"; + WorkingDirectory = "${think-gtcm}"; + RuntimeDirectory = "think-gtcm/cache"; RuntimeDirectoryMode = 700; - ExecStart = think-gtcm-maintenance; }; + path = [ pkgs.replace-secret ]; + script = + let + isSecret = v: lib.isAttrs v && v ? _secret && lib.isString v._secret; + gtcmEnvVars = lib.generators.toKeyValue { + mkKeyValue = lib.flip lib.generators.mkKeyValueDefault "=" { + mkValueString = + v: + with builtins; + if isInt v then + toString v + else if isString v then + v + else if true == v then + "true" + else if false == v then + "false" + else if isSecret v then + hashString "sha256" v._secret + else + throw "unsupported type ${typeOf v}: ${(lib.generators.toPretty { }) v}"; + }; + }; + secretPaths = lib.mapAttrsToList (_: v: v._secret) (lib.filterAttrs (_: isSecret) cfg.config); + mkSecretReplacement = file: '' + replace-secret ${ + lib.escapeShellArgs [ + (builtins.hashString "sha256" file) + file + "${cfg.dataDir}/.env" + ] + } + ''; + secretReplacements = lib.concatMapStrings mkSecretReplacement secretPaths; + filteredConfig = lib.converge (lib.filterAttrsRecursive ( + _: v: + !lib.elem v [ + { } + null + ] + )) cfg.settings; + gtcmEnv = pkgs.writeText "gtcm.env" (gtcmEnvVars filteredConfig); + in + '' + # error handling + set -euo pipefail + + # create .env file + install -T -m 0600 -o ${cfg.user} ${gtcmEnv} "${cfg.dataDir}/.env" + ${secretReplacements} + if ! grep 'APP_KEY=base64:' "${cfg.dataDir}/.env" >/dev/null; then + sed -i 's/APP_KEY=/APP_KEY=base64:/' "${cfg.dataDir}/.env" + fi + + # migrate & seed db + ${php} artisan key:generate --force + ${php} artisan migrate --force + ${php} artisan config:cache + ''; }; + systemd.tmpfiles.rules = [ + "d ${cfg.dataDir} 0710 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/public 0750 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/public/uploads 0750 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/app 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/fonts 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/framework 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/framework/cache 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/framework/sessions 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/framework/views 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/logs 0700 ${cfg.user} ${cfg.group} - -" + "d ${cfg.dataDir}/storage/uploads 0700 ${cfg.user} ${cfg.group} - -" + ]; + services.nginx = { enable = true; + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + recommendedBrotliSettings = true; + recommendedProxySettings = true; virtualHosts."${cfg.domain}" = { root = "${cfg.package}/share/php/think-gtcm/public"; - locations."~ \\.php$".extraConfig = '' - fastcgi_pass unix:${config.services.phpfpm.pools.think-greaterchiangmai.socket}; - fastcgi_index index.php; - ''; - extraConfig = '' - index index.php; - ''; + locations = { + "/" = { + index = "index.php"; + tryFiles = "$uri $uri/ /index.php?$query_string"; + }; + + "~ \\.php$".extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools."think-gtcm".socket}; + ''; + "~ \\.(js|css|gif|png|ico|jpg|jpeg)$" = { + extraConfig = "expires 365d;"; + }; + }; }; # virtualHosts."${cfg.backendDomain}" = { # root = "${cfg.packageBackend}/share/php/think-backend-gtcm/public";