nixos/wordpress: nginx support
This commit is contained in:
parent
694f513cd1
commit
d4eca42de4
@ -546,6 +546,22 @@
|
|||||||
<literal>claws-mail-gtk2</literal> package.
|
<literal>claws-mail-gtk2</literal> package.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The wordpress module provides a new interface which allows to
|
||||||
|
use different webservers with the new option
|
||||||
|
<link xlink:href="options.html#opt-services.wordpress.webserver"><literal>services.wordpress.webserver</literal></link>.
|
||||||
|
Currently <literal>httpd</literal> and
|
||||||
|
<literal>nginx</literal> are supported. The definitions of
|
||||||
|
wordpress sites should now be set in
|
||||||
|
<link xlink:href="options.html#opt-services.wordpress.sites"><literal>services.wordpress.sites</literal></link>.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
Sites definitions that use the old interface are automatically
|
||||||
|
migrated in the new option. This backward compatibility will
|
||||||
|
be removed in 22.05.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
@ -135,3 +135,7 @@ In addition to numerous new and upgraded packages, this release has the followin
|
|||||||
- Sway: The terminal emulator `rxvt-unicode` is no longer installed by default via `programs.sway.extraPackages`. The current default configuration uses `alacritty` (and soon `foot`) so this is only an issue when using a customized configuration and not installing `rxvt-unicode` explicitly.
|
- Sway: The terminal emulator `rxvt-unicode` is no longer installed by default via `programs.sway.extraPackages`. The current default configuration uses `alacritty` (and soon `foot`) so this is only an issue when using a customized configuration and not installing `rxvt-unicode` explicitly.
|
||||||
|
|
||||||
- The `claws-mail` package now references the new GTK+ 3 release branch, major version 4. To use the GTK+ 2 releases, one can install the `claws-mail-gtk2` package.
|
- The `claws-mail` package now references the new GTK+ 3 release branch, major version 4. To use the GTK+ 2 releases, one can install the `claws-mail-gtk2` package.
|
||||||
|
|
||||||
|
- The wordpress module provides a new interface which allows to use different webservers with the new option [`services.wordpress.webserver`](options.html#opt-services.wordpress.webserver). Currently `httpd` and `nginx` are supported. The definitions of wordpress sites should now be set in [`services.wordpress.sites`](options.html#opt-services.wordpress.sites).
|
||||||
|
|
||||||
|
Sites definitions that use the old interface are automatically migrated in the new option. This backward compatibility will be removed in 22.05.
|
||||||
|
@ -3,13 +3,18 @@
|
|||||||
let
|
let
|
||||||
inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
|
inherit (lib) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types;
|
||||||
inherit (lib) any attrValues concatMapStringsSep flatten literalExample;
|
inherit (lib) any attrValues concatMapStringsSep flatten literalExample;
|
||||||
inherit (lib) mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString;
|
inherit (lib) filterAttrs mapAttrs mapAttrs' mapAttrsToList nameValuePair optional optionalAttrs optionalString;
|
||||||
|
|
||||||
eachSite = config.services.wordpress;
|
cfg = migrateOldAttrs config.services.wordpress;
|
||||||
|
eachSite = cfg.sites;
|
||||||
user = "wordpress";
|
user = "wordpress";
|
||||||
group = config.services.httpd.group;
|
webserver = config.services.${cfg.webserver};
|
||||||
stateDir = hostName: "/var/lib/wordpress/${hostName}";
|
stateDir = hostName: "/var/lib/wordpress/${hostName}";
|
||||||
|
|
||||||
|
# Migrate config.services.wordpress.<hostName> to config.services.wordpress.sites.<hostName>
|
||||||
|
oldSites = filterAttrs (o: _: o != "sites" && o != "webserver");
|
||||||
|
migrateOldAttrs = cfg: cfg // { sites = cfg.sites // oldSites cfg; };
|
||||||
|
|
||||||
pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
|
pkg = hostName: cfg: pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "wordpress-${hostName}";
|
pname = "wordpress-${hostName}";
|
||||||
version = src.version;
|
version = src.version;
|
||||||
@ -261,21 +266,48 @@ in
|
|||||||
# interface
|
# interface
|
||||||
options = {
|
options = {
|
||||||
services.wordpress = mkOption {
|
services.wordpress = mkOption {
|
||||||
type = types.attrsOf (types.submodule siteOpts);
|
type = types.submodule {
|
||||||
|
# Used to support old interface
|
||||||
|
freeformType = types.attrsOf (types.submodule siteOpts);
|
||||||
|
|
||||||
|
# New interface
|
||||||
|
options.sites = mkOption {
|
||||||
|
type = types.attrsOf (types.submodule siteOpts);
|
||||||
|
default = {};
|
||||||
|
description = "Specification of one or more WordPress sites to serve";
|
||||||
|
};
|
||||||
|
|
||||||
|
options.webserver = mkOption {
|
||||||
|
type = types.enum [ "httpd" "nginx" ];
|
||||||
|
default = "httpd";
|
||||||
|
description = ''
|
||||||
|
Whether to use apache2 or nginx for virtual host management.
|
||||||
|
|
||||||
|
Further nginx configuration can be done by adapting <literal>services.nginx.virtualHosts.<name></literal>.
|
||||||
|
See <xref linkend="opt-services.nginx.virtualHosts"/> for further information.
|
||||||
|
|
||||||
|
Further apache2 configuration can be done by adapting <literal>services.httpd.virtualHosts.<name></literal>.
|
||||||
|
See <xref linkend="opt-services.httpd.virtualHosts"/> for further information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
default = {};
|
default = {};
|
||||||
description = "Specification of one or more WordPress sites to serve via Apache.";
|
description = "Wordpress configuration";
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
config = mkIf (eachSite != {}) {
|
config = mkIf (eachSite != {}) (mkMerge [{
|
||||||
|
|
||||||
assertions = mapAttrsToList (hostName: cfg:
|
assertions = mapAttrsToList (hostName: cfg:
|
||||||
{ assertion = cfg.database.createLocally -> cfg.database.user == user;
|
{ assertion = cfg.database.createLocally -> cfg.database.user == user;
|
||||||
message = "services.wordpress.${hostName}.database.user must be ${user} if the database is to be automatically provisioned";
|
message = ''services.wordpress.sites."${hostName}".database.user must be ${user} if the database is to be automatically provisioned'';
|
||||||
}
|
}
|
||||||
) eachSite;
|
) eachSite;
|
||||||
|
|
||||||
|
warnings = mapAttrsToList (hostName: _: ''services.wordpress."${hostName}" is deprecated use services.wordpress.sites."${hostName}"'') (oldSites cfg);
|
||||||
|
|
||||||
services.mysql = mkIf (any (v: v.database.createLocally) (attrValues eachSite)) {
|
services.mysql = mkIf (any (v: v.database.createLocally) (attrValues eachSite)) {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = mkDefault pkgs.mariadb;
|
package = mkDefault pkgs.mariadb;
|
||||||
@ -289,14 +321,18 @@ in
|
|||||||
|
|
||||||
services.phpfpm.pools = mapAttrs' (hostName: cfg: (
|
services.phpfpm.pools = mapAttrs' (hostName: cfg: (
|
||||||
nameValuePair "wordpress-${hostName}" {
|
nameValuePair "wordpress-${hostName}" {
|
||||||
inherit user group;
|
inherit user;
|
||||||
|
group = webserver.group;
|
||||||
settings = {
|
settings = {
|
||||||
"listen.owner" = config.services.httpd.user;
|
"listen.owner" = webserver.user;
|
||||||
"listen.group" = config.services.httpd.group;
|
"listen.group" = webserver.group;
|
||||||
} // cfg.poolConfig;
|
} // cfg.poolConfig;
|
||||||
}
|
}
|
||||||
)) eachSite;
|
)) eachSite;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf (cfg.webserver == "httpd") {
|
||||||
services.httpd = {
|
services.httpd = {
|
||||||
enable = true;
|
enable = true;
|
||||||
extraModules = [ "proxy_fcgi" ];
|
extraModules = [ "proxy_fcgi" ];
|
||||||
@ -332,11 +368,13 @@ in
|
|||||||
'';
|
'';
|
||||||
} ]) eachSite;
|
} ]) eachSite;
|
||||||
};
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
{
|
||||||
systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
|
systemd.tmpfiles.rules = flatten (mapAttrsToList (hostName: cfg: [
|
||||||
"d '${stateDir hostName}' 0750 ${user} ${group} - -"
|
"d '${stateDir hostName}' 0750 ${user} ${webserver.group} - -"
|
||||||
"d '${cfg.uploadsDir}' 0750 ${user} ${group} - -"
|
"d '${cfg.uploadsDir}' 0750 ${user} ${webserver.group} - -"
|
||||||
"Z '${cfg.uploadsDir}' 0750 ${user} ${group} - -"
|
"Z '${cfg.uploadsDir}' 0750 ${user} ${webserver.group} - -"
|
||||||
]) eachSite);
|
]) eachSite);
|
||||||
|
|
||||||
systemd.services = mkMerge [
|
systemd.services = mkMerge [
|
||||||
@ -350,7 +388,7 @@ in
|
|||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
User = user;
|
User = user;
|
||||||
Group = group;
|
Group = webserver.group;
|
||||||
};
|
};
|
||||||
})) eachSite)
|
})) eachSite)
|
||||||
|
|
||||||
@ -360,9 +398,65 @@ in
|
|||||||
];
|
];
|
||||||
|
|
||||||
users.users.${user} = {
|
users.users.${user} = {
|
||||||
group = group;
|
group = webserver.group;
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
(mkIf (cfg.webserver == "nginx") {
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts = mapAttrs (hostName: cfg: {
|
||||||
|
serverName = mkDefault hostName;
|
||||||
|
root = "${pkg hostName cfg}/share/wordpress";
|
||||||
|
extraConfig = ''
|
||||||
|
index index.php;
|
||||||
|
'';
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
priority = 200;
|
||||||
|
extraConfig = ''
|
||||||
|
try_files $uri $uri/ /index.php$is_args$args;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"~ \\.php$" = {
|
||||||
|
priority = 500;
|
||||||
|
extraConfig = ''
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass unix:${config.services.phpfpm.pools."wordpress-${hostName}".socket};
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include "${config.services.nginx.package}/conf/fastcgi.conf";
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
|
||||||
|
# Mitigate https://httpoxy.org/ vulnerabilities
|
||||||
|
fastcgi_param HTTP_PROXY "";
|
||||||
|
fastcgi_intercept_errors off;
|
||||||
|
fastcgi_buffer_size 16k;
|
||||||
|
fastcgi_buffers 4 16k;
|
||||||
|
fastcgi_connect_timeout 300;
|
||||||
|
fastcgi_send_timeout 300;
|
||||||
|
fastcgi_read_timeout 300;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
"~ /\\." = {
|
||||||
|
priority = 800;
|
||||||
|
extraConfig = "deny all;";
|
||||||
|
};
|
||||||
|
"~* /(?:uploads|files)/.*\\.php$" = {
|
||||||
|
priority = 900;
|
||||||
|
extraConfig = "deny all;";
|
||||||
|
};
|
||||||
|
"~* \\.(js|css|png|jpg|jpeg|gif|ico)$" = {
|
||||||
|
priority = 1000;
|
||||||
|
extraConfig = ''
|
||||||
|
expires max;
|
||||||
|
log_not_found off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) eachSite;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
@ -10,48 +10,68 @@ import ./make-test-python.nix ({ pkgs, ... }:
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
machine =
|
nodes = {
|
||||||
{ ... }:
|
wp_httpd = { ... }: {
|
||||||
{ services.httpd.adminAddr = "webmaster@site.local";
|
services.httpd.adminAddr = "webmaster@site.local";
|
||||||
services.httpd.logPerVirtualHost = true;
|
services.httpd.logPerVirtualHost = true;
|
||||||
|
|
||||||
services.wordpress."site1.local" = {
|
services.wordpress = {
|
||||||
database.tablePrefix = "site1_";
|
# Test support for old interface
|
||||||
};
|
"site1.local" = {
|
||||||
|
database.tablePrefix = "site1_";
|
||||||
services.wordpress."site2.local" = {
|
};
|
||||||
database.tablePrefix = "site2_";
|
sites = {
|
||||||
|
"site2.local" = {
|
||||||
|
database.tablePrefix = "site2_";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
|
networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wp_nginx = { ... }: {
|
||||||
|
services.wordpress.webserver = "nginx";
|
||||||
|
services.wordpress.sites = {
|
||||||
|
"site1.local" = {
|
||||||
|
database.tablePrefix = "site1_";
|
||||||
|
};
|
||||||
|
"site2.local" = {
|
||||||
|
database.tablePrefix = "site2_";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||||
|
networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
testScript = ''
|
testScript = ''
|
||||||
import re
|
import re
|
||||||
|
|
||||||
start_all()
|
start_all()
|
||||||
|
|
||||||
machine.wait_for_unit("httpd")
|
wp_httpd.wait_for_unit("httpd")
|
||||||
|
wp_nginx.wait_for_unit("nginx")
|
||||||
machine.wait_for_unit("phpfpm-wordpress-site1.local")
|
|
||||||
machine.wait_for_unit("phpfpm-wordpress-site2.local")
|
|
||||||
|
|
||||||
site_names = ["site1.local", "site2.local"]
|
site_names = ["site1.local", "site2.local"]
|
||||||
|
|
||||||
with subtest("website returns welcome screen"):
|
for machine in (wp_httpd, wp_nginx):
|
||||||
for site_name in site_names:
|
for site_name in site_names:
|
||||||
assert "Welcome to the famous" in machine.succeed(f"curl -fL {site_name}")
|
machine.wait_for_unit(f"phpfpm-wordpress-{site_name}")
|
||||||
|
|
||||||
with subtest("wordpress-init went through"):
|
with subtest("website returns welcome screen"):
|
||||||
for site_name in site_names:
|
assert "Welcome to the famous" in machine.succeed(f"curl -L {site_name}")
|
||||||
info = machine.get_unit_info(f"wordpress-init-{site_name}")
|
|
||||||
assert info["Result"] == "success"
|
|
||||||
|
|
||||||
with subtest("secret keys are set"):
|
with subtest("wordpress-init went through"):
|
||||||
pattern = re.compile(r"^define.*NONCE_SALT.{64,};$", re.MULTILINE)
|
info = machine.get_unit_info(f"wordpress-init-{site_name}")
|
||||||
for site_name in site_names:
|
assert info["Result"] == "success"
|
||||||
assert pattern.search(
|
|
||||||
machine.succeed(f"cat /var/lib/wordpress/{site_name}/secret-keys.php")
|
with subtest("secret keys are set"):
|
||||||
)
|
pattern = re.compile(r"^define.*NONCE_SALT.{64,};$", re.MULTILINE)
|
||||||
|
assert pattern.search(
|
||||||
|
machine.succeed(f"cat /var/lib/wordpress/{site_name}/secret-keys.php")
|
||||||
|
)
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user