mob next [ci-skip] [ci skip] [skip ci]

lastFile:modules/nixos/think-gtcm.nix
This commit is contained in:
2025-11-24 13:40:14 +00:00
parent 52df526ac5
commit 3e95cd0310

View File

@@ -11,14 +11,33 @@ let
defaultUser = "gtcm"; defaultUser = "gtcm";
defaultGroup = "gtcm"; defaultGroup = "gtcm";
env-nonfile-values = lib.attrsets.filterAttrs (n: v: !lib.strings.hasSuffix "_FILE" n) cfg.settings; php = pkgs.php83;
think-gtcm-maintenance = pkgs.writeShellScript "think-gtcm-maintenance.sh" ''
set -a
${lib.strings.toShellVars env-nonfile-values}
set +a
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 in
{ {
options.services.think-greaterchiangmai = { options.services.think-greaterchiangmai = {
@@ -64,64 +83,54 @@ in
}; };
settings = lib.mkOption { 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 = { }; default = { };
description = '' description = ''
Options for settings environment variables Options for settings environment variables
''; '';
example = lib.literalExpression '' example = lib.literalExpression ''
{ {
APP_NAME=Laravel APP_NAME = "Laravel";
APP_ENV=local APP_ENV = "local";
APP_KEY= APP_KEY = "key";
APP_DEBUG=true APP_DEBUG = true;
APP_URL=http://localhost APP_URL = "http://localhost";
LOG_CHANNEL=stack LOG_CHANNEL = "stack";
LOG_DEPRECATIONS_CHANNEL=null LOG_DEPRECATIONS_CHANNEL = "null";
LOG_LEVEL=debug LOG_LEVEL = "debug";
DB_CONNECTION=mysql DB_CONNECTION = "mysql";
DB_HOST=127.0.0.1 DB_HOST = "127.0.0.1";
DB_PORT=3306 DB_PORT = "3306";
DB_DATABASE=laravel DB_DATABASE = "laravel";
DB_USERNAME=root DB_USERNAME = "root";
DB_PASSWORD= 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
} }
''; '';
type = lib.types.submodule { type = lib.types.submodule {
@@ -201,11 +210,12 @@ in
}; };
users.groups.${cfg.group} = { }; users.groups.${cfg.group} = { };
services.phpfpm.pools.think-greaterchiangmai = { services.phpfpm.pools.think-gtcm = {
inherit (cfg) user group; inherit (cfg) user group;
phpPackage = php;
settings = { settings = {
"listen.owner" = config.services.nginx.user; "listen.owner" = cfg.user;
"listen.group" = config.services.nginx.group; "listen.group" = cfg.group;
"listen.mode" = "0600"; "listen.mode" = "0600";
"pm" = lib.mkDefault "dynamic"; "pm" = lib.mkDefault "dynamic";
"pm.max_children" = lib.mkDefault 10; "pm.max_children" = lib.mkDefault 10;
@@ -222,33 +232,117 @@ in
systemd.services.think-gtcm-setup = { systemd.services.think-gtcm-setup = {
description = "think.greaterchiangmai installation"; description = "think.greaterchiangmai installation";
requiredBy = [ "phpfpm-think-greaterchiangmai.service" ]; requiredBy = [ "phpfpm-think-gtcm.service" ];
before = [ "phpfpm-think-greaterchiangmai.service" ]; before = [ "phpfpm-think-gtcm.service" ];
requires = [ "mysql.service" ]; requires = [ "mysql.service" ];
after = [ "mysql.service" ]; after = [ "mysql.service" ];
path = [ config.services.phpfpm.phpPackage ];
serviceConfig = { serviceConfig = {
type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
User = cfg.user; User = cfg.user;
UMask = 77; UMask = 77;
WorkingDirectory = "${agorakit}"; WorkingDirectory = "${think-gtcm}";
RuntimeDirectory = "agorakit/cache"; RuntimeDirectory = "think-gtcm/cache";
RuntimeDirectoryMode = 700; 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 = { services.nginx = {
enable = true; enable = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
recommendedBrotliSettings = true;
recommendedProxySettings = true;
virtualHosts."${cfg.domain}" = { virtualHosts."${cfg.domain}" = {
root = "${cfg.package}/share/php/think-gtcm/public"; root = "${cfg.package}/share/php/think-gtcm/public";
locations."~ \\.php$".extraConfig = '' locations = {
fastcgi_pass unix:${config.services.phpfpm.pools.think-greaterchiangmai.socket}; "/" = {
fastcgi_index index.php; index = "index.php";
''; tryFiles = "$uri $uri/ /index.php?$query_string";
extraConfig = '' };
index index.php;
''; "~ \\.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}" = { # virtualHosts."${cfg.backendDomain}" = {
# root = "${cfg.packageBackend}/share/php/think-backend-gtcm/public"; # root = "${cfg.packageBackend}/share/php/think-backend-gtcm/public";