From 5892f7caed66837c635b0f39d075303f6970aa95 Mon Sep 17 00:00:00 2001 From: kurogeek Date: Tue, 25 Nov 2025 14:11:59 +0700 Subject: [PATCH] mob next [ci-skip] [ci skip] [skip ci] lastFile:modules/nixos/think-backend-gtcm.nix --- modules/nixos/flake-module.nix | 3 + modules/nixos/think-backend-gtcm.nix | 281 +++++++++++++++++++++++++++ modules/nixos/think-gtcm.nix | 26 ++- 3 files changed, 300 insertions(+), 10 deletions(-) create mode 100644 modules/nixos/think-backend-gtcm.nix diff --git a/modules/nixos/flake-module.nix b/modules/nixos/flake-module.nix index 2f56f14..f0a8017 100644 --- a/modules/nixos/flake-module.nix +++ b/modules/nixos/flake-module.nix @@ -6,5 +6,8 @@ think-gtcm = { imports = [ ./think-gtcm.nix ]; }; + think-backend-gtcm = { + imports = [ ./think-backend-gtcm.nix ]; + }; }; } diff --git a/modules/nixos/think-backend-gtcm.nix b/modules/nixos/think-backend-gtcm.nix new file mode 100644 index 0000000..fd4cdf1 --- /dev/null +++ b/modules/nixos/think-backend-gtcm.nix @@ -0,0 +1,281 @@ +{ + config, + pkgs, + lib, + ... +}: +let + cfg = config.services.think-backcend-greaterchiangmai; + think-backend-gtcm = pkgs.think-backend-gtcm.override { dataDir = cfg.dataDir; }; + defaultUser = "gtcm"; + defaultGroup = "gtcm"; + + php = pkgs.php83; + + artisan-be = pkgs.writeScriptBin "gtcm-be" '' + #! ${pkgs.runtimeShell} + cd ${think-backend-gtcm} + sudo() { + if [[ "$USER" != ${cfg.user} ]]; then + exec /run/wrappers/bin/sudo -u ${cfg.user} "$@" + else + exec "$@" + fi + } + sudo ${lib.getExe php} artisan "$@" + ''; + +in +{ + options.services.think-backend-greaterchiangmai = { + enable = lib.mkEnableOption "To enable think.greaterchiangmai.com"; + + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/think-backend.greaterchiangmai.com"; + description = ''A place where to store states''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = defaultUser; + description = "User account under which this runs."; + }; + + group = lib.mkOption { + type = lib.types.str; + default = defaultGroup; + defaultText = "${defaultGroup}"; + description = '' + Group under which the website runs. + ''; + }; + + package = lib.mkPackageOption pkgs "think-backend-gtcm" { }; + + domain = lib.mkOption { + type = lib.types.str; + default = "think-backend.greaterchiangmai.com"; + example = "forum.example.com"; + description = "Domain to serve on."; + }; + + settings = lib.mkOption { + 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 = "key"; + APP_DEBUG = true; + APP_URL = "http://localhost"; + + 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 = ""; + } + ''; + }; + + }; + config = lib.mkIf cfg.enable { + users.users.${cfg.user} = { + isSystemUser = true; + home = cfg.dataDir; + createHome = true; + homeMode = "755"; + group = cfg.group; + }; + users.groups.${cfg.group} = { }; + + services.phpfpm.pools.think-be-gtcm = { + inherit (cfg) user group; + phpPackage = php; + settings = { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + "listen.mode" = "0600"; + "pm" = lib.mkDefault "dynamic"; + "pm.max_children" = lib.mkDefault 10; + "pm.max_requests" = lib.mkDefault 500; + "pm.start_servers" = lib.mkDefault 2; + "pm.min_spare_servers" = lib.mkDefault 1; + "pm.max_spare_servers" = lib.mkDefault 3; + }; + phpOptions = '' + error_log = syslog + log_errors = on + ''; + }; + + environment.systemPackages = [ + artisan-be + ]; + + systemd.services.think-be-gtcm-setup = { + description = "think-backend.greaterchiangmai installation"; + requiredBy = [ "phpfpm-think-be-gtcm.service" ]; + before = [ "phpfpm-think-be-gtcm.service" ]; + requires = [ "mysql.service" ]; + after = [ "mysql.service" ]; + serviceConfig = { + type = "oneshot"; + RemainAfterExit = true; + User = cfg.user; + UMask = 77; + WorkingDirectory = "${think-backend-gtcm}"; + RuntimeDirectory = "think-be-gtcm/cache"; + RuntimeDirectoryMode = 700; + }; + 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.settings); + 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 + ${lib.getExe php} artisan key:generate --force + ${lib.getExe php} artisan migrate --force + ${lib.getExe 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 = "${think-backend-gtcm}/public"; + locations = { + "/" = { + index = "index.php"; + tryFiles = "$uri $uri/ /index.php?$query_string"; + }; + + "~ \\.php$".extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools."think-backend-gtcm".socket}; + ''; + "~ \\.(js|css|gif|png|ico|jpg|jpeg)$" = { + extraConfig = "expires 365d;"; + }; + }; + }; + }; + + services.mysql = { + enable = true; + package = pkgs.mariadb; + ensureDatabases = [ cfg.settings.DB_DATABASE ]; + ensureUsers = [ + { + name = cfg.settings.DB_USERNAME; + ensurePermissions = { + "${cfg.settings.DB_DATABASE}.*" = "ALL PRIVILEGES"; + }; + } + ]; + }; + }; +} diff --git a/modules/nixos/think-gtcm.nix b/modules/nixos/think-gtcm.nix index ee9fdc4..e0b6105 100644 --- a/modules/nixos/think-gtcm.nix +++ b/modules/nixos/think-gtcm.nix @@ -285,16 +285,22 @@ in }; }; }; - # virtualHosts."${cfg.backendDomain}" = { - # root = "${cfg.packageBackend}/share/php/think-backend-gtcm/public"; - # locations."~ \\.php$".extraConfig = '' - # fastcgi_pass unix:${config.services.phpfpm.pools.think-greaterchiangmai.socket}; - # fastcgi_index index.php; - # ''; - # extraConfig = '' - # index index.php; - # ''; - # }; + virtualHosts."${cfg.backendDomain}" = { + root = "${think-backend-gtcm}/public"; + locations = { + "/" = { + index = "index.php"; + tryFiles = "$uri $uri/ /index.php?$query_string"; + }; + + "~ \\.php$".extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools."think-backend-gtcm".socket}; + ''; + "~ \\.(js|css|gif|png|ico|jpg|jpeg)$" = { + extraConfig = "expires 365d;"; + }; + }; + }; }; services.mysql = {