{ config, lib, pkgs, ... }: with import <stockholm/lib>; let cfg = config.lass.wordpress; out = { options.lass.wordpress = api; config = imp; }; api = mkOption { type = with types; attrsOf (submodule ({ config, ... }: { options = { domain = mkOption { type = str; default = config._module.args.name; }; dbUser = mkOption { type = str; default = replaceStrings ["."] ["_"] config.domain; }; dbName = mkOption { type = str; default = replaceStrings ["."] ["_"] config.domain; }; folder = mkOption { type = str; default = "/srv/http/${config.domain}"; }; auto = mkOption { type = bool; default = false; }; charset = mkOption { type = str; default = "utf8mb4"; }; collate = mkOption { type = str; default = ""; }; debug = mkOption { type = bool; default = false; }; multiSite = mkOption { type = attrsOf str; default = {}; example = { "0" = "bla.testsite.de"; "1" = "test.testsite.de"; }; }; ssl = mkOption { type = with types; submodule ({ options = { enable = mkEnableOption "ssl"; certificate = mkOption { type = str; }; certificate_key = mkOption { type = str; }; ciphers = mkOption { type = str; default = "AES128+EECDH:AES128+EDH"; }; }; }); }; }; })); default = {}; }; user = config.services.nginx.user; group = config.services.nginx.group; imp = { #services.nginx.appendConfig = mkIf (cfg.multiSite != {}) '' # map $http_host $blogid { # ${concatStringsSep "\n" (mapAttrsToList (n: v: indent "v n;") multiSite)} # } #''; krebs.nginx.servers = flip mapAttrs cfg ( name: { domain, folder, multiSite, ssl, ... }: { server-names = [ "${domain}" "www.${domain}" ]; #(mkIf (multiSite != {}) #) locations = (if (multiSite != {}) then [ (nameValuePair "~ ^/files/(.*)$" '' try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1 ; '') (nameValuePair "^~ /blogs.dir" '' internal; alias ${folder}/wp-content/blogs.dir ; access_log off; log_not_found off; expires max; '') ] else [] ) ++ [ (nameValuePair "/" '' try_files $uri $uri/ /index.php?$args; '') (nameValuePair "~ \.php$" '' fastcgi_pass unix:${folder}/phpfpm.pool; include ${pkgs.nginx}/conf/fastcgi.conf; '') (nameValuePair "~ /\\." '' deny all; '') #Directives to send expires headers and turn off 404 error logging. (nameValuePair "~* ^.+\.(xml|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$" '' access_log off; log_not_found off; expires max; '') ]; extraConfig = '' root ${folder}/; index index.php; access_log /tmp/nginx_acc.log; error_log /tmp/nginx_err.log; error_page 404 /404.html; error_page 500 502 503 504 /50x.html; ${if ssl.enable then '' ssl_certificate ${ssl.certificate}; ssl_certificate_key ${ssl.certificate_key}; '' else ""} ''; listen = (if ssl.enable then [ "80" "443 ssl" ] else "80" ); }); services.phpfpm.poolConfigs = flip mapAttrs cfg (name: { domain, folder, ... }: '' listen = ${folder}/phpfpm.pool user = ${user} group = ${group} pm = dynamic pm.max_children = 5 pm.start_servers = 2 pm.min_spare_servers = 1 pm.max_spare_servers = 3 listen.owner = ${user} listen.group = ${group} php_admin_value[error_log] = 'stderr' php_admin_flag[log_errors] = on catch_workers_output = yes ''); systemd.services = flip mapAttrs' cfg (name: { domain, folder, charset, collate, dbName, dbUser, debug, multiSite, ... }: { name = "wordpressInit-${name}"; value = { path = [ pkgs.mysql pkgs.su pkgs.gawk pkgs.jq ]; requiredBy = [ "nginx.service" ]; serviceConfig = let php.define = name: value: "define(${php.newdoc name}, ${php.newdoc value});"; php.toString = x: "'${x}'"; php.newdoc = s: let b = "EOF${builtins.hashString "sha256" s}"; in ''<<<'${b}' ${s} ${b} ''; in { Type = "oneshot"; ExecStart = pkgs.writeScript "wordpressInit" '' #!/bin/sh set -euf wp_secrets=${shell.escape "${toString <secrets>}/${domain}/wp-secrets"} db_password=$(cat ${shell.escape "${toString <secrets>}/${domain}/sql-db-pw"}) get_secret() { echo "define('$1', $(jq -r ."$1" "$wp_secrets" | to_php_string));" } to_php_string() { echo "base64_decode('$(base64)')" } { cat ${toString <secrets/mysql_rootPassword>} password=$(cat ${shell.escape (toString (<secrets/mysql_rootPassword>))}) # TODO passwordhash=$(su nobody2 -c mysql <<< "SELECT PASSWORD($(toSqlString <<< "$password"));") # TODO as package pkgs.sqlHashPassword # TODO not using mysql # SET SESSION sql_mode = 'NO_BACKSLASH_ESCAPES'; passwordhash=$(su nobody2 -c 'mysql -u nobody --silent' <<< "SELECT PASSWORD('$db_password');") user=${shell.escape dbUser}@localhost database=${shell.escape dbName} cat << EOF CREATE DATABASE IF NOT EXISTS $database; GRANT USAGE ON *.* TO $user IDENTIFIED BY PASSWORD '$passwordhash'; GRANT ALL PRIVILEGES ON $database.* TO $user; FLUSH PRIVILEGES; EOF } | mysql -u root -p # TODO nix2php for wp-config.php cat > ${folder}/wp-config.php << EOF <?php define('DB_PASSWORD', '$db_password'); define('DB_HOST', 'localhost'); ${concatStringsSep "\n" (mapAttrsToList (name: value: "define('${name}', $(printf '%s' ${shell.escape value} | to_php_string));" ) { DB_NAME = dbName; DB_USER = dbUser; DB_CHARSET = charset; DB_COLLATE = collate; })} ${concatMapStringsSep "\n" (key: "$(get_secret ${shell.escape key})") [ "AUTH_KEY" "SECURE_AUTH_KEY" "LOGGED_IN_KEY" "NONCE_KEY" "AUTH_SALT" "SECURE_AUTH_SALT" "LOGGED_IN_SALT" "NONCE_SALT" ]} \$table_prefix = 'wp_'; ${if (multiSite != {}) then "define('WP_ALLOW_MULTISITE', true);" else "" } define('WP_DEBUG', ${toJSON debug}); if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); /** Sets up WordPress vars and included files. */ require_once(ABSPATH . 'wp-settings.php'); EOF ''; }; }; }); users.users.nobody2 = mkDefault { uid = mkDefault (genid "nobody2"); useDefaultShell = mkDefault true; }; }; indent = replaceChars ["\n"] ["\n "]; in out