Migrate web-development projects to proper modules

Create proper modules for TYPO3 and static web projects.
Those modules are now used on all machines.
This replaces the old legacy functions used to setup projects.

That way multiple projects can easily be defined within one file.
This commit is contained in:
Daniel Siepmann 2024-06-22 16:57:15 +02:00
parent d1c2907097
commit d2d8551cf8
Signed by: Daniel Siepmann
GPG key ID: 33D6629915560EF4
31 changed files with 434 additions and 776 deletions

3
.gitattributes vendored
View file

@ -9,9 +9,6 @@ home/files/rclone.conf filter=git-crypt diff=git-crypt
home/files/typo3-configuration/client-specific/** filter=git-crypt diff=git-crypt
home/packages/custom/dmenu-scripts/customer-issue.sh filter=git-crypt diff=git-crypt
systems/hikari/files/hosts filter=git-crypt diff=git-crypt
systems/hikari/web-development/projects/customer.nix filter=git-crypt diff=git-crypt
systems/hikari3/files/hosts filter=git-crypt diff=git-crypt
systems/hikari3/web-development/projects/customer.nix filter=git-crypt diff=git-crypt
systems/hikari3/web-development/projects/customer/* filter=git-crypt diff=git-crypt
systems/hikari3/private/* filter=git-crypt diff=git-crypt
projects/** filter=git-crypt diff=git-crypt

View file

@ -11,7 +11,8 @@
./cachix.nix
./web-development
/home/daniels/.config/nixpkgs/systems/web-development/default.nix
./web-development/projects.nix
];
boot = {

View file

@ -1,123 +0,0 @@
{ pkgs, config, lib, ... }:
let
mysqlEnsurePermissionsForDevUser = builtins.listToAttrs (
map (databaseName: {
name = "${databaseName}.*";
value = "ALL PRIVILEGES";
})
config.custom.web-development.databases
);
in {
imports = [
./lib/mkcert.nix
./projects/private.nix
./projects/service-wrapper.nix
./projects/typo3.nix
];
options = {
custom.web-development = {
rootPath = lib.mkOption {
type = lib.types.path;
default = "/var/projects";
description = ''
The root folder where web development happens.
All Projects need to be placed within this folder.
'';
};
databases = lib.mkOption {
type = lib.types.listOf lib.types.nonEmptyStr;
default = [];
example = lib.literalExpression "[namespace_project namespace2_project1]";
description = ''
A list of all necessary databases.
Used to create the databases and grant permissions.
'';
};
};
};
config = {
services = {
httpd = {
enable = true;
user = "daniels";
adminAddr = "apache@hikari.localhost";
extraModules = [
"info"
"rewrite"
"proxy"
"proxy_fcgi"
];
virtualHosts."localhost".locations."/server-info" = {
extraConfig = ''
SetHandler server-info
Require local
'';
};
};
mysql = {
enable = true;
package = pkgs.mariadb;
ensureUsers = [
{
name = "daniels";
ensurePermissions = {
"*.*" = "ALL PRIVILEGES";
};
}
{
# INITIALLY once change dev user to be identified by password
# alter user dev@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD('dev');
name = "dev";
ensurePermissions = mysqlEnsurePermissionsForDevUser;
}
];
ensureDatabases = [
"testing" # Used by TYPO3 functional tests
"testing_at" # Used by TYPO3 Acceptance tests
] ++ config.custom.web-development.databases;
settings = {
mysqld = {
# sql_mode = "SRTICT_TRANS_TABLES;NO_ZERO_IN_DATE;NO_ZERO_DATE;ERROR_FOR_DIVISION_BY_ZERO;NO_ENGINE_SUBSTITUTION";
general_log = true;
general_log_file = "/var/lib/mysql/query.log";
# slow_query_log = true;
# slow_query_log_file = "/var/lib/mysql/slow_query.log";
# long_query_time = 1;
bind-address = "127.0.0.1";
};
};
};
};
systemd.tmpfiles.rules = [
# TODO: Improve handling of TYPO3 global configuration
# Current issue: The files are copied once.
# Changes are not reflected until reboot?
# I can edit the copied files, but need to keep files in sync.
"C ${config.custom.web-development.rootPath}/own/typo3-configuration - - - - ${config.users.users.daniels.home}/.config/nixpkgs/home/files/typo3-configuration"
];
};
}

View file

@ -1,30 +0,0 @@
{
config
, domain
, relativeDocumentRoot
}:
let
documentRoot = "${config.custom.web-development.rootPath}/${relativeDocumentRoot}";
in {
services = {
httpd.virtualHosts.${domain} = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domain}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domain}-key.pem";
inherit documentRoot;
extraConfig = ''
<Directory ${documentRoot}>
AllowOverride All
Require all granted
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
DirectoryIndex index.html Index.html
</Directory>
'';
};
};
}

View file

@ -1,121 +0,0 @@
{
config
, lib
, pkgs
, domain
, relativeDocumentRoot
, databaseName
, php
}:
let
documentRoot = "${config.custom.web-development.rootPath}/${relativeDocumentRoot}";
phpPackage = php.buildEnv {
extensions = { enabled, all }: enabled ++ (with all; [
xdebug
]);
extraConfig = ''
max_execution_time = 240
max_input_vars = 1500
xdebug.mode = debug
xdebug.max_nesting_level = 400
'';
};
in {
custom.web-development = {
databases = [databaseName];
};
services = {
httpd.virtualHosts.${domain} = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domain}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domain}-key.pem";
inherit documentRoot;
extraConfig = ''
<Directory ${documentRoot}>
AllowOverride None
Require all granted
DirectoryIndex index.php
RewriteEngine On
# Store the current location in an environment variable CWD to use
# mod_rewrite in .htaccess files without knowing the RewriteBase
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^.*$ - [E=CWD:%2]
# Rule for versioned static files, configured through:
# - $GLOBALS['TYPO3_CONF_VARS']['BE']['versionNumberInFilename']
# - $GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename']
# IMPORTANT: This rule has to be the very first RewriteCond in order to work!
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ %{ENV:CWD}$1.$3 [L]
# Access block for folders
RewriteRule _(?:recycler|temp)_/ - [F]
RewriteRule fileadmin/templates/.*\.(?:txt|ts)$ - [F]
RewriteRule ^(?:vendor|typo3_src|typo3temp/var) - [F]
RewriteRule (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/ - [F]
# Block access to all hidden files and directories with the exception of
# the visible content from within the `/.well-known/` hidden directory (RFC 5785).
RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule (?:^|/)\. - [F]
# Stop rewrite processing, if we are in any other known directory
# NOTE: Add your additional local storages here
RewriteRule ^(?:fileadmin/|typo3conf/|typo3temp/|uploads/) - [L]
# If the file/symlink/directory does not exist but is below /typo3/, redirect to the TYPO3 Backend entry point.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} ^/typo3/.*$
RewriteRule ^typo3/(.*)$ %{ENV:CWD}typo3/index.php [QSA,L]
# If the file/symlink/directory does not exist => Redirect to index.php.
# For httpd.conf, you need to prefix each '%{REQUEST_FILENAME}' with '%{DOCUMENT_ROOT}'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^.*$ %{ENV:CWD}index.php [QSA,L]
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:${config.services.phpfpm.pools."${domain}".socket}|fcgi://${domain}/"
</FilesMatch>
'';
};
phpfpm.pools.${domain} = {
inherit (config.services.httpd) user group;
inherit phpPackage;
settings = {
"listen.owner" = config.services.httpd.user;
"listen.group" = config.services.httpd.group;
"pm" = "ondemand";
"pm.max_children" = 15;
};
phpEnv = {
TYPO3_ADDITIONAL_CONFIGURATION = "/var/projects/own/typo3-configuration/AdditionalConfiguration.inc.php";
TYPO3_DATABASE = databaseName;
TYPO3_CONTEXT = "Development/dsiepmann";
IMAGEMAGICK_PATH = lib.makeBinPath [ pkgs.imagemagick ] + "/";
};
};
};
}

View file

@ -1,53 +0,0 @@
{ pkgs, lib, config, ... }:
let
certFolder = "/var/projects/own/mkcert";
domains = builtins.concatStringsSep " " (
map (domain: "\"${domain}\"") (
builtins.attrNames config.services.httpd.virtualHosts
)
);
custom-generate-certs = pkgs.writeShellApplication {
name = "custom-generate-certs";
runtimeInputs = [
pkgs.mkcert
];
text = ''
mkdir -p ${certFolder}
pushd ${certFolder}
declare -a domains=(${domains})
for domain in "''${domains[@]}"
do
CAROOT="${certFolder}" mkcert "$domain"
done
'';
};
in {
options = {
custom.web-development = {
certFolder = lib.mkOption {
type = lib.types.path;
default = "${config.custom.web-development.rootPath}/own/mkcert/";
};
};
};
config = {
# TODO: Run once before httpd service starts?
environment.systemPackages = [
custom-generate-certs
];
# NOTE: Disable until root certificate is generated, then add again
# Maybe check for file existense and throw proper error message?
security.pki.certificates = [
(builtins.readFile "${config.custom.web-development.certFolder}rootCA.pem")
];
};
}

View file

@ -0,0 +1,23 @@
{
pkgs
,config
,...
}:
{
config.custom.web-development = {
typo3 = {
"daniel-siepmann.own.localhost" = {
relativeDocumentRoot = "own/daniel-siepmann/project/public/";
databaseName = "own_danielsiepmann";
phpPackage = pkgs.php83;
};
};
static = {
"tea-docs.typo3.localhost" = {
relativeDocumentRoot = "stuff/typo3/extensions/tea/Documentation-GENERATED-temp/Result/project/0.0.0/";
};
};
};
}

View file

@ -1,13 +0,0 @@
{ pkgs, lib, config, ... }:
let
php = pkgs.php83;
in import ./../lib/create-typo3.nix {
inherit config lib pkgs php;
domain = "daniel-siepmann.own.localhost";
relativeDocumentRoot = "own/daniel-siepmann/project/public/";
databaseName = "own_danielsiepmann";
}

View file

@ -1,28 +0,0 @@
{ pkgs, lib, config, ... }:
let
domain = "mailhog.localhost";
in {
services = {
httpd.virtualHosts.${domain} = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domain}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domain}-key.pem";
extraConfig = ''
RequestHeader unset Authorization
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:8025/
ProxyPassReverse / http://localhost:8025/
# Mailhog specific
<LocationMatch /api/v2/websocket>
ProxyPass ws://localhost:8025/api/v2/websocket
</LocationMatch>
'';
};
};
}

View file

@ -1,8 +0,0 @@
{ lib, config, ... }:
import ./../lib/create-static.nix {
inherit config;
domain = "tea-docs.typo3.localhost";
relativeDocumentRoot = "typo3/tea/Documentation-GENERATED-temp/Result/project/0.0.0/";
}

View file

@ -3,7 +3,7 @@
# and in the NixOS manual (accessible by running nixos-help).
{
,config
config
,pkgs
,...
}:
@ -14,7 +14,9 @@
./cachix.nix
./web-development
/home/daniels/.config/nixpkgs/systems/web-development/default.nix
./web-development/projects.nix
./private/web-development-projects.nix
./private/borgbackups.nix
];

Binary file not shown.

View file

@ -1,168 +0,0 @@
{
pkgs
,config
,lib
,...
}:
let
mysqlEnsurePermissionsForDevUser = builtins.listToAttrs (
map (databaseName: {
name = "${databaseName}.*";
value = "ALL PRIVILEGES";
})
config.custom.web-development.databases
);
mysqlLogFile = "/var/lib/mysql/query.log";
in {
imports = [
./lib/mkcert.nix
./projects/service-wrapper.nix
./projects/typo3.nix
./projects/customer/itcc-steel.nix
./projects/customer/sa-frontend.nix
./projects/customer/sa-sa.nix
./projects/customer/reu-reu.nix
./projects/customer/wm-interdaf.nix
./projects/customer/wm-sozio.nix
];
options = {
custom.web-development = {
rootPath = lib.mkOption {
type = lib.types.path;
default = "/var/projects";
description = ''
The root folder where web development happens.
All Projects need to be placed within this folder.
'';
};
databases = lib.mkOption {
type = lib.types.listOf lib.types.nonEmptyStr;
default = [];
example = lib.literalExpression "[namespace_project namespace2_project1]";
description = ''
A list of all necessary databases.
Used to create the databases and grant permissions.
'';
};
};
};
config = {
services = {
httpd = {
enable = true;
user = "daniels";
adminAddr = "apache@hikari.localhost";
extraModules = [
"info"
"rewrite"
"proxy"
"proxy_fcgi"
];
virtualHosts."localhost".locations."/server-info" = {
extraConfig = ''
SetHandler server-info
Require local
'';
};
};
mysql = {
enable = true;
package = pkgs.mariadb;
ensureUsers = [
{
name = "daniels";
ensurePermissions = {
"*.*" = "ALL PRIVILEGES";
};
}
{
# INITIALLY once change dev user to be identified by password
# alter user dev@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD('dev');
name = "testing";
ensurePermissions = {
"*.*" = "ALL PRIVILEGES";
};
}
{
# INITIALLY once change dev user to be identified by password
# alter user dev@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD('dev');
name = "dev";
ensurePermissions = mysqlEnsurePermissionsForDevUser;
}
];
ensureDatabases = [
"testing" # Used by TYPO3 functional tests
"testing_at" # Used by TYPO3 Acceptance tests
] ++ config.custom.web-development.databases;
settings = {
mysqld = {
# sql_mode = "SRTICT_TRANS_TABLES;NO_ZERO_IN_DATE;NO_ZERO_DATE;ERROR_FOR_DIVISION_BY_ZERO;NO_ENGINE_SUBSTITUTION";
general_log = true;
general_log_file = mysqlLogFile;
# slow_query_log = true;
# slow_query_log_file = "/var/lib/mysql/slow_query.log";
# long_query_time = 1;
bind-address = "127.0.0.1";
};
};
};
logrotate = {
settings.mysql = {
files = mysqlLogFile;
su = "${config.services.mysql.user} ${config.services.mysql.user}";
frequency = "daily";
rotate = 2;
sharedscripts = true;
compress = true;
delaycompress = true;
postrotate = "systemctl restart mysql.service > /dev/null 2>/dev/null || true";
};
};
};
systemd = {
services = {
mysql.serviceConfig = {
# Allow group to access the folder,
# to allow users within group to tail log.
StateDirectoryMode = lib.mkForce "0710";
};
};
tmpfiles.rules = [
# TODO: Improve handling of TYPO3 global configuration
# Current issue: The files are copied once.
# Changes are not reflected until reboot?
# I can edit the copied files, but need to keep files in sync.
"C ${config.custom.web-development.rootPath}/own/typo3-configuration - - - - ${config.users.users.daniels.home}/.config/nixpkgs/home/files/typo3-configuration"
];
};
};
}

View file

@ -1,30 +0,0 @@
{
config
, domain
, relativeDocumentRoot
}:
let
documentRoot = "${config.custom.web-development.rootPath}/${relativeDocumentRoot}";
in {
services = {
httpd.virtualHosts.${domain} = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domain}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domain}-key.pem";
inherit documentRoot;
extraConfig = ''
<Directory ${documentRoot}>
AllowOverride All
Require all granted
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
DirectoryIndex index.html Index.html
</Directory>
'';
};
};
}

View file

@ -1,132 +0,0 @@
{
config
, lib
, pkgs
, domain
, relativeDocumentRoot
, databaseName
, php
}:
let
documentRoot = "${config.custom.web-development.rootPath}/${relativeDocumentRoot}";
phpPackage = php.buildEnv {
extensions = { enabled, all }: enabled ++ (with all; [
xdebug
]);
extraConfig = ''
max_execution_time = 240
max_input_vars = 1500
display_errors = 1
error_reporting = E_ALL
xdebug.mode = debug
xdebug.var_display_max_children = 2048
xdebug.var_display_max_depth = 5
xdebug.max_nesting_level = 400
'';
};
in {
custom.web-development = {
databases = [databaseName];
};
services = {
httpd.virtualHosts.${domain} = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domain}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domain}-key.pem";
inherit documentRoot;
extraConfig = ''
<Directory ${documentRoot}>
AllowOverride None
Require all granted
DirectoryIndex index.php
RewriteEngine On
# Store the current location in an environment variable CWD to use
# mod_rewrite in .htaccess files without knowing the RewriteBase
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^.*$ - [E=CWD:%2]
# Rule for versioned static files, configured through:
# - $GLOBALS['TYPO3_CONF_VARS']['BE']['versionNumberInFilename']
# - $GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename']
# IMPORTANT: This rule has to be the very first RewriteCond in order to work!
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ %{ENV:CWD}$1.$3 [L]
# Access block for folders
RewriteRule _(?:recycler|temp)_/ - [F]
RewriteRule fileadmin/templates/.*\.(?:txt|ts)$ - [F]
RewriteRule ^(?:vendor|typo3_src|typo3temp/var) - [F]
RewriteRule (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/ - [F]
# Block access to all hidden files and directories with the exception of
# the visible content from within the `/.well-known/` hidden directory (RFC 5785).
RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule (?:^|/)\. - [F]
# Stop rewrite processing, if we are in any other known directory
# NOTE: Add your additional local storages here
RewriteRule ^(?:fileadmin/|typo3conf/|typo3temp/|uploads/) - [L]
# If the file/symlink/directory does not exist but is below /typo3/, redirect to the TYPO3 Backend entry point.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} ^/typo3/.*$
RewriteRule ^typo3/(.*)$ %{ENV:CWD}typo3/index.php [QSA,L]
# If the file/symlink/directory does not exist => Redirect to index.php.
# For httpd.conf, you need to prefix each '%{REQUEST_FILENAME}' with '%{DOCUMENT_ROOT}'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^.*$ %{ENV:CWD}index.php [QSA,L]
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:${config.services.phpfpm.pools."${domain}".socket}|fcgi://${domain}/"
</FilesMatch>
'';
};
phpfpm.pools.${domain} = {
inherit (config.services.httpd) user group;
inherit phpPackage;
settings = {
"listen.owner" = config.services.httpd.user;
"listen.group" = config.services.httpd.group;
"pm" = "ondemand";
"pm.max_children" = 15;
};
phpEnv = {
TYPO3_ADDITIONAL_CONFIGURATION = "/var/projects/own/typo3-configuration/AdditionalConfiguration.inc.php";
TYPO3_DATABASE = databaseName;
TYPO3_CONTEXT = "Development/dsiepmann";
TYPO3_BASE = "https://${domain}/";
# Used via TYPO3 API, expose
IMAGEMAGICK_PATH = lib.makeBinPath [ pkgs.imagemagick ] + "/";
};
};
};
}

View file

@ -0,0 +1,23 @@
{
pkgs
,config
,...
}:
{
config.custom.web-development = {
typo3 = {
"daniel-siepmann.own.localhost" = {
relativeDocumentRoot = "own/daniel-siepmann/project/public/";
databaseName = "own_danielsiepmann";
phpPackage = pkgs.php83;
};
};
static = {
"tea-docs.typo3.localhost" = {
relativeDocumentRoot = "stuff/typo3/extensions/tea/Documentation-GENERATED-temp/Result/project/0.0.0/";
};
};
};
}

View file

@ -1,18 +0,0 @@
{
pkgs
,lib
,config
,...
}:
let
php = pkgs.php83;
in import ./../lib/create-typo3.nix {
inherit config lib pkgs php;
domain = "daniel-siepmann.own.localhost";
relativeDocumentRoot = "own/daniel-siepmann/project/public/";
databaseName = "own_danielsiepmann";
}

View file

@ -1,33 +0,0 @@
{
,pkgs
,lib
,config
,...
}:
let
domain = "mailhog.localhost";
in {
services = {
httpd.virtualHosts.${domain} = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domain}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domain}-key.pem";
extraConfig = ''
RequestHeader unset Authorization
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:8025/
ProxyPassReverse / http://localhost:8025/
# Mailhog specific
<LocationMatch /api/v2/websocket>
ProxyPass ws://localhost:8025/api/v2/websocket
</LocationMatch>
'';
};
};
}

View file

@ -1,12 +0,0 @@
{
,lib
,config
,...
}:
import ./../lib/create-static.nix {
inherit config;
domain = "tea-docs.typo3.localhost";
relativeDocumentRoot = "typo3/tea/Documentation-GENERATED-temp/Result/project/0.0.0/";
}

View file

@ -0,0 +1,182 @@
{
pkgs
,config
,lib
,...
}:
let
mysqlEnsurePermissionsForDevUser = builtins.listToAttrs (
map (databaseName: {
name = "${databaseName}.*";
value = "ALL PRIVILEGES";
})
config.custom.web-development.databases
);
mysqlLogFile = "/var/lib/mysql/query.log";
in {
imports = [
./mkcert.nix
./static.nix
./typo3.nix
];
options = {
custom.web-development = {
rootPath = lib.mkOption {
type = lib.types.path;
default = "/var/projects";
description = ''
The root folder where web development happens.
All Projects need to be placed within this folder.
'';
};
databases = lib.mkOption {
type = lib.types.listOf lib.types.nonEmptyStr;
default = [];
example = lib.literalExpression "[namespace_project namespace2_project1]";
description = ''
A list of all necessary databases.
Used to create the databases and grant permissions.
'';
};
};
};
config = {
services = {
httpd = {
enable = true;
user = "daniels";
adminAddr = "apache@hikari.localhost";
extraModules = [
"info"
"rewrite"
"proxy"
"proxy_fcgi"
];
virtualHosts = {
"localhost".locations."/server-info" = {
extraConfig = ''
SetHandler server-info
Require local
'';
};
"mailhog.localhost" = {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}mailhog.localhost.pem";
sslServerKey = "${config.custom.web-development.certFolder}mailhog.localhost-key.pem";
extraConfig = ''
RequestHeader unset Authorization
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://localhost:8025/
ProxyPassReverse / http://localhost:8025/
# Mailhog specific
<LocationMatch /api/v2/websocket>
ProxyPass ws://localhost:8025/api/v2/websocket
</LocationMatch>
'';
};
};
};
mysql = {
enable = true;
package = pkgs.mariadb;
ensureUsers = [
{
name = "daniels";
ensurePermissions = {
"*.*" = "ALL PRIVILEGES";
};
}
{
# INITIALLY once change dev user to be identified by password
# alter user dev@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD('dev');
name = "testing";
ensurePermissions = {
"*.*" = "ALL PRIVILEGES";
};
}
{
# INITIALLY once change dev user to be identified by password
# alter user dev@localhost IDENTIFIED VIA mysql_native_password USING PASSWORD('dev');
name = "dev";
ensurePermissions = mysqlEnsurePermissionsForDevUser;
}
];
ensureDatabases = [
"testing" # Used by TYPO3 functional tests
"testing_at" # Used by TYPO3 Acceptance tests
] ++ config.custom.web-development.databases;
settings = {
mysqld = {
# sql_mode = "SRTICT_TRANS_TABLES;NO_ZERO_IN_DATE;NO_ZERO_DATE;ERROR_FOR_DIVISION_BY_ZERO;NO_ENGINE_SUBSTITUTION";
general_log = true;
general_log_file = mysqlLogFile;
# slow_query_log = true;
# slow_query_log_file = "/var/lib/mysql/slow_query.log";
# long_query_time = 1;
bind-address = "127.0.0.1";
};
};
};
logrotate = {
settings.mysql = {
files = mysqlLogFile;
su = "${config.services.mysql.user} ${config.services.mysql.user}";
frequency = "daily";
rotate = 2;
sharedscripts = true;
compress = true;
delaycompress = true;
postrotate = "systemctl restart mysql.service > /dev/null 2>/dev/null || true";
};
};
};
systemd = {
services = {
mysql.serviceConfig = {
# Allow group to access the folder,
# to allow users within group to tail log.
StateDirectoryMode = lib.mkForce "0710";
};
};
tmpfiles.rules = [
# TODO: Improve handling of TYPO3 global configuration
# Current issue: The files are copied once.
# Changes are not reflected until reboot?
# I can edit the copied files, but need to keep files in sync.
"C ${config.custom.web-development.rootPath}/own/typo3-configuration - - - - ${config.users.users.daniels.home}/.config/nixpkgs/home/files/typo3-configuration"
];
};
};
}

View file

@ -1,4 +1,9 @@
{ pkgs, lib, config, ... }:
{
pkgs
,lib
,config
,...
}:
let
certFolder = "/var/projects/own/mkcert";

View file

@ -0,0 +1,45 @@
{
config
,lib
,pkgs
,...
}:
let
cfg = config.custom.web-development.static;
in {
options.custom.web-development.static = lib.mkOption {
default = {};
description = "Define a set of static projects.";
type = with lib.types; attrsOf (submodule {
options = {
relativeDocumentRoot = lib.mkOption {
type = str;
};
};
});
};
config.services.httpd.virtualHosts = builtins.mapAttrs (domainName: cfg:
let
documentRoot = "${config.custom.web-development.rootPath}/${cfg.relativeDocumentRoot}";
in {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domainName}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domainName}-key.pem";
inherit documentRoot;
extraConfig = ''
<Directory ${documentRoot}>
AllowOverride All
Require all granted
Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
DirectoryIndex index.html Index.html
</Directory>
'';
}
) cfg;
}

View file

@ -0,0 +1,149 @@
{
config
,lib
,pkgs
,...
}:
let
cfg = config.custom.web-development.typo3;
in {
options.custom.web-development.typo3 = lib.mkOption {
default = {};
description = "Define a set of TYPO3 projects.";
type = with lib.types; attrsOf (submodule {
options = {
relativeDocumentRoot = lib.mkOption {
type = str;
};
databaseName = lib.mkOption {
type = str;
};
phpPackage = lib.mkOption {
type = package;
};
};
});
};
config = {
services.phpfpm.pools = builtins.mapAttrs (domainName: cfg:
let
phpPackage = cfg.phpPackage.buildEnv {
extensions = { enabled, all }: enabled ++ (with all; [
xdebug
]);
extraConfig = ''
max_execution_time = 240
max_input_vars = 1500
display_errors = 1
error_reporting = E_ALL
xdebug.mode = debug
xdebug.var_display_max_children = 2048
xdebug.var_display_max_depth = 5
xdebug.max_nesting_level = 400
'';
};
in {
inherit (config.services.httpd) user group;
inherit phpPackage;
settings = {
"listen.owner" = config.services.httpd.user;
"listen.group" = config.services.httpd.group;
"pm" = "ondemand";
"pm.max_children" = 15;
};
phpEnv = {
TYPO3_ADDITIONAL_CONFIGURATION = "/var/projects/own/typo3-configuration/AdditionalConfiguration.inc.php";
TYPO3_DATABASE = cfg.databaseName;
TYPO3_CONTEXT = "Development/dsiepmann";
TYPO3_BASE = "https://${domainName}/";
# Used via TYPO3 API, expose
IMAGEMAGICK_PATH = lib.makeBinPath [ pkgs.imagemagick ] + "/";
};
}) cfg;
services.httpd.virtualHosts = builtins.mapAttrs (domainName: cfg:
let
documentRoot = "${config.custom.web-development.rootPath}/${cfg.relativeDocumentRoot}";
in {
forceSSL = true;
sslServerCert = "${config.custom.web-development.certFolder}${domainName}.pem";
sslServerKey = "${config.custom.web-development.certFolder}${domainName}-key.pem";
inherit documentRoot;
extraConfig = ''
<Directory ${documentRoot}>
AllowOverride None
Require all granted
DirectoryIndex index.php
RewriteEngine On
# Store the current location in an environment variable CWD to use
# mod_rewrite in .htaccess files without knowing the RewriteBase
RewriteCond $0#%{REQUEST_URI} ([^#]*)#(.*)\1$
RewriteRule ^.*$ - [E=CWD:%2]
# Rule for versioned static files, configured through:
# - $GLOBALS['TYPO3_CONF_VARS']['BE']['versionNumberInFilename']
# - $GLOBALS['TYPO3_CONF_VARS']['FE']['versionNumberInFilename']
# IMPORTANT: This rule has to be the very first RewriteCond in order to work!
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ %{ENV:CWD}$1.$3 [L]
# Access block for folders
RewriteRule _(?:recycler|temp)_/ - [F]
RewriteRule fileadmin/templates/.*\.(?:txt|ts)$ - [F]
RewriteRule ^(?:vendor|typo3_src|typo3temp/var) - [F]
RewriteRule (?:typo3conf/ext|typo3/sysext|typo3/ext)/[^/]+/(?:Configuration|Resources/Private|Tests?|Documentation|docs?)/ - [F]
# Block access to all hidden files and directories with the exception of
# the visible content from within the `/.well-known/` hidden directory (RFC 5785).
RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule (?:^|/)\. - [F]
# Stop rewrite processing, if we are in any other known directory
# NOTE: Add your additional local storages here
RewriteRule ^(?:fileadmin/|typo3conf/|typo3temp/|uploads/) - [L]
# If the file/symlink/directory does not exist but is below /typo3/, redirect to the TYPO3 Backend entry point.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_URI} ^/typo3/.*$
RewriteRule ^typo3/(.*)$ %{ENV:CWD}typo3/index.php [QSA,L]
# If the file/symlink/directory does not exist => Redirect to index.php.
# For httpd.conf, you need to prefix each '%{REQUEST_FILENAME}' with '%{DOCUMENT_ROOT}'.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^.*$ %{ENV:CWD}index.php [QSA,L]
</Directory>
<FilesMatch "\.php$">
SetHandler "proxy:unix:${config.services.phpfpm.pools."${domainName}".socket}|fcgi://${domainName}/"
</FilesMatch>
'';
}
) cfg;
custom.web-development = {
databases = lib.attrsets.mapAttrsToList(name: cfg: cfg.databaseName) cfg;
};
};
}