@ -3,13 +3,18 @@
let
inherit ( lib ) mkDefault mkEnableOption mkForce mkIf mkMerge mkOption types ;
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 = " w o r d p r e s s " ;
group = config . services . httpd . group ;
webserver = config . services . ${ cfg . webserver } ;
stateDir = hostName : " / v a r / l i b / w o r d p r e s s / ${ hostName } " ;
# Migrate config.services.wordpress.<hostName> to config.services.wordpress.sites.<hostName>
oldSites = filterAttrs ( o : _ : o != " s i t e s " && o != " w e b s e r v e r " ) ;
migrateOldAttrs = cfg : cfg // { sites = cfg . sites // oldSites cfg ; } ;
pkg = hostName : cfg : pkgs . stdenv . mkDerivation rec {
pname = " w o r d p r e s s - ${ hostName } " ;
version = src . version ;
@ -261,21 +266,48 @@ in
# interface
options = {
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 = " S p e c i f i c a t i o n o f o n e o r m o r e W o r d P r e s s s i t e s t o s e r v e " ;
} ;
options . webserver = mkOption {
type = types . enum [ " h t t p d " " n g i n x " ] ;
default = " h t t p d " ;
description = ''
Whether to use apache2 or nginx for virtual host management .
Further nginx configuration can be done by adapting <literal> services . nginx . virtualHosts . & lt ; name & gt ; < /literal > .
See < xref linkend = " o p t - s e r v i c e s . n g i n x . v i r t u a l H o s t s " / > for further information .
Further apache2 configuration can be done by adapting <literal> services . httpd . virtualHosts . & lt ; name & gt ; < /literal > .
See < xref linkend = " o p t - s e r v i c e s . h t t p d . v i r t u a l H o s t s " / > for further information .
'' ;
} ;
} ;
default = { } ;
description = " S p e c i f i c a t i o n o f o n e o r m o r e W o r d P r e s s s i t e s t o s e r v e v i a A p a c h e . " ;
description = " W o r d p r e s s c o n f i g u r a t i o n " ;
} ;
} ;
# implementation
config = mkIf ( eachSite != { } ) {
config = mkIf ( eachSite != { } ) ( mkMerge [ {
assertions = mapAttrsToList ( hostName : cfg :
{ assertion = cfg . database . createLocally -> cfg . database . user == user ;
message = " s e r v i c e s . w o r d p r e s s . ${ hostName } . d a t a b a s e . u s e r m u s t b e ${ user } i f t h e d a t a b a s e i s t o b e a u t o m a t i c a l l y p r o v i s i o n e d " ;
message = '' s e r v i c e s . w o r d p r e s s . s i t e s . " ${ hostName } " . d a t a b a s e . u s e r m u s t b e ${ user } i f t h e d a t a b a s e i s t o b e a u t o m a t i c a l l y p r o v i s i o n e d '' ;
}
) eachSite ;
warnings = mapAttrsToList ( hostName : _ : '' s e r v i c e s . w o r d p r e s s . " ${ hostName } " i s d e p r e c a t e d u s e s e r v i c e s . w o r d p r e s s . s i t e s . " ${ hostName } " '' ) ( oldSites cfg ) ;
services . mysql = mkIf ( any ( v : v . database . createLocally ) ( attrValues eachSite ) ) {
enable = true ;
package = mkDefault pkgs . mariadb ;
@ -289,14 +321,18 @@ in
services . phpfpm . pools = mapAttrs' ( hostName : cfg : (
nameValuePair " w o r d p r e s s - ${ hostName } " {
inherit user group ;
inherit user ;
group = webserver . group ;
settings = {
" l i s t e n . o w n e r " = config . services . httpd . user ;
" l i s t e n . g r o u p " = config . services . httpd . group ;
" l i s t e n . o w n e r " = webserver . user ;
" l i s t e n . g r o u p " = webserver . group ;
} // cfg . poolConfig ;
}
) ) eachSite ;
}
( mkIf ( cfg . webserver == " h t t p d " ) {
services . httpd = {
enable = true ;
extraModules = [ " p r o x y _ f c g i " ] ;
@ -332,11 +368,13 @@ in
'' ;
} ] ) eachSite ;
} ;
} )
{
systemd . tmpfiles . rules = flatten ( mapAttrsToList ( hostName : cfg : [
" d ' ${ stateDir hostName } ' 0 7 5 0 ${ user } ${ group } - - "
" d ' ${ cfg . uploadsDir } ' 0 7 5 0 ${ user } ${ group } - - "
" Z ' ${ cfg . uploadsDir } ' 0 7 5 0 ${ user } ${ group } - - "
" d ' ${ stateDir hostName } ' 0 7 5 0 ${ user } ${ webserver . group } - - "
" d ' ${ cfg . uploadsDir } ' 0 7 5 0 ${ user } ${ webserver . group } - - "
" Z ' ${ cfg . uploadsDir } ' 0 7 5 0 ${ user } ${ webserver . group } - - "
] ) eachSite ) ;
systemd . services = mkMerge [
@ -350,7 +388,7 @@ in
serviceConfig = {
Type = " o n e s h o t " ;
User = user ;
Group = group ;
Group = webserver . group ;
} ;
} ) ) eachSite )
@ -360,9 +398,65 @@ in
] ;
users . users . ${ user } = {
group = group ;
group = webserver . group ;
isSystemUser = true ;
} ;
}
} ;
( mkIf ( cfg . webserver == " n g i n x " ) {
services . nginx = {
enable = true ;
virtualHosts = mapAttrs ( hostName : cfg : {
serverName = mkDefault hostName ;
root = " ${ pkg hostName cfg } / s h a r e / w o r d p r e s s " ;
extraConfig = ''
index index . php ;
'' ;
locations = {
" / " = {
priority = 200 ;
extraConfig = ''
try_files $ uri $ uri / /index.php $ is_args $ args ;
'' ;
} ;
" ~ \\ . p h p $ " = {
priority = 500 ;
extraConfig = ''
fastcgi_split_path_info ^ ( . + \ . php ) ( /.+ ) $ ;
fastcgi_pass unix:$ { config . services . phpfpm . pools . " w o r d p r e s s - ${ hostName } " . socket } ;
fastcgi_index index . php ;
include " ${ config . services . nginx . package } / c o n f / f a s t c g i . c o n f " ;
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 1 6 k ;
fastcgi_buffers 4 1 6 k ;
fastcgi_connect_timeout 300 ;
fastcgi_send_timeout 300 ;
fastcgi_read_timeout 300 ;
'' ;
} ;
" ~ / \\ . " = {
priority = 800 ;
extraConfig = " d e n y a l l ; " ;
} ;
" ~ * / ( ? : u p l o a d s | f i l e s ) / . * \\ . p h p $ " = {
priority = 900 ;
extraConfig = " d e n y a l l ; " ;
} ;
" ~ * \\ . ( j s | c s s | p n g | j p g | j p e g | g i f | i c o ) $ " = {
priority = 1000 ;
extraConfig = ''
expires max ;
log_not_found off ;
'' ;
} ;
} ;
} ) eachSite ;
} ;
} )
] ) ;
}