From d78ba26e322b4f12a20a94f5334d23ba2ea6d4d5 Mon Sep 17 00:00:00 2001
From: nee
Date: Mon, 9 Oct 2017 23:06:05 +0200
Subject: [PATCH 2/2] gnu: services: Add php-fpm.
* gnu/services/web.scm (,
): New record types.
(php-fpm-configuration?,
php-fpm-process-manager-configuration?,
php-fpm-service-type,
nginx-php-location): New procedures.
* doc/guix.texi (Web-Services): document php-fpm service.
---
doc/guix.texi | 93 +++++++++++++++++++++++++++
gnu/services/web.scm | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 264 insertions(+), 2 deletions(-)
diff --git a/doc/guix.texi b/doc/guix.texi
index f0a59a6b4..ed4336f64 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -14529,6 +14529,99 @@ capability also has to be configured on the front-end as well.
@end deftp
address@hidden php-fpm
+PHP-FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation
+with some additional features useful for sites of any size.
+
address@hidden {Scheme Variable} php-fpm-service-type
+A Service type for @code{php-fpm}.
address@hidden defvr
+
address@hidden {Data Type} php-fpm-configuration
+Data Type for php-fpm service configuration.
address@hidden @asis
address@hidden @code {socket} (default: @code{(string-append "/var/run/php" (version-major (package-version php)) "-fpm.sock")})
+The address on which to accept FastCGI requests. Valid syntaxes are:
address@hidden @asis
address@hidden @code{"ip.add.re.ss:port"}
+Listen on a TCP socket to a specific address on a specific port.
address@hidden @code{"port"}
+Listen on a TCP socket to all addresses on a specific port.
address@hidden @code{"/path/to/unix/socket"}
+Listen on a unix socket.
address@hidden table
+
address@hidden @code {user} (default: @code{php-fpm})
+User who will own the php worker processes.
address@hidden @code {group} (default: @code{php-fpm})
+Group of the worker processes.
address@hidden @code {socket-user} (default: @code{nginx})
+User who can speak to the php-fpm socket.
address@hidden @code {socket-group} (default: @code{nginx})
+Group that can speak to the php-fpm socket.
address@hidden @code {process-manager} (default: @code{(php-fpm-process-manager-configuration)})
+Detailed settings for the php-fpm process manager.
address@hidden @code {display-errors} (default @code{#f})
+Determines wether php errors and warning should be sent to clients
+and displayed in their browsers.
+This is useful for local php development, but a security risk for public sites,
+as error messages can reveal passwords and personal data.
address@hidden @code {workers-logfile} (default @code{(string-append "/var/log/php" (version-major (package-version php)) "-fpm.log")})
+This file will log the @code{stderr} outputs of php worker processes.
+Can be set to @code{#f} to disable logging.
address@hidden @code {file} (default @code{#f})
+An optional override of the whole configuration.
+You can use the @code{mixed-text-file} function or an absolute filepath for it.
address@hidden table
address@hidden deftp
+
address@hidden {Data type} php-fpm-process-manager-configuration
+Data Type for php-fpm worker process limits.
address@hidden @asis
address@hidden @code {type} (default: @code{"dynamic"})
address@hidden @asis
address@hidden @code{"dynamic"}
+Spare worker processes are kept around based on the set @code{php-fpm-process-manager-configuration} limits.
address@hidden @code{"static"}
+A static number of worker processes is created.
address@hidden @code{"ondemand"}
+Worker processes are only created on demand.
address@hidden table
address@hidden @code {max-children} (default: @code{5})
+Maximum of worker processes. Applies when the type is @code{"static"}, @code{"dynamic"}, or @code{"ondemand"}.
address@hidden @code {start-servers} (default: @code{2})
+How many worker processes should be started on start-up. Only applies when type is @code{"dynamic"}.
address@hidden @code {min-spare-servers} (default: @code{1})
+How many spare worker processes should be kept around at minimum. Only applies when type is @code{"dynamic"}.
address@hidden @code {max-spare-servers} (default: @code{3})
+How many spare worker processes should be kept around at maximum. Only applies when type is @code{"dynamic"}.
address@hidden @code {process-idle-timeout} (default: @code{10})
+The time in seconds after which a process with no requests is killed. Only applies when type is @code{"ondemand"}.
address@hidden table
address@hidden deftp
+
address@hidden {Scheme Variable} nginx-php-fpm-location
+A helper function to quickly add php to an @code{nginx-server-configuration}.
address@hidden defvr
+
+A simple services setup for nginx with php can look like this:
address@hidden
+(services (cons* (dhcp-client-service)
+ (service php-fpm-service-type
+ (php-fpm-configuration))
+ (service nginx-service-type
+ (nginx-server-configuration
+ (server-name '("example.com"))
+ (root "/srv/http/")
+ (locations
+ (list (nginx-php-location)))
+ (https-port #f)
+ (ssl-certificate #f)
+ (ssl-certificate-key #f)))
+ %base-services))
address@hidden example
+
+
@node DNS Services
@subsubsection DNS Services
@cindex DNS (domain name system)
diff --git a/gnu/services/web.scm b/gnu/services/web.scm
index 9d713003c..fd63b15bb 100644
--- a/gnu/services/web.scm
+++ b/gnu/services/web.scm
@@ -26,8 +26,11 @@
#:use-module (gnu system shadow)
#:use-module (gnu packages admin)
#:use-module (gnu packages web)
+ #:use-module (gnu packages php)
#:use-module (guix records)
#:use-module (guix gexp)
+ #:use-module ((guix utils) #:select (version-major))
+ #:use-module ((guix packages) #:select (package-version))
#:use-module (srfi srfi-1)
#:use-module (ice-9 match)
#:export (
@@ -76,7 +79,14 @@
fcgiwrap-configuration
fcgiwrap-configuration?
- fcgiwrap-service-type))
+ fcgiwrap-service-type
+
+ php-fpm-configuration
+ php-fpm-configuration?
+ php-fpm-process-manager-configuration
+ php-fpm-process-manager-configuration?
+ php-fpm-service-type
+ nginx-php-location))
;;; Commentary:
;;;
@@ -256,10 +266,12 @@ of index files."
"events {}\n")))
(define %nginx-accounts
- (list (user-group (name "nginx") (system? #t))
+ (list (user-group (name "www-data") (system? #t))
+ (user-group (name "nginx") (system? #t))
(user-account
(name "nginx")
(group "nginx")
+ (supplementary-groups '("www-data"))
(system? #t)
(comment "nginx server user")
(home-directory "/var/empty")
@@ -385,3 +397,160 @@ of index files."
(service-extension account-service-type
fcgiwrap-accounts)))
(default-value (fcgiwrap-configuration))))
+
+(define-record-type* php-fpm-configuration
+ make-php-fpm-configuration
+ php-fpm-configuration?
+ (php php-fpm-configuration-php ;
+ (default php))
+ (socket php-fpm-configuration-socket
+ (default (string-append "/var/run/php"
+ (version-major (package-version php))
+ "-fpm.sock")))
+ (user php-fpm-configuration-user
+ (default "php-fpm"))
+ (group php-fpm-configuration-group
+ (default "php-fpm"))
+ (socket-user php-fpm-configuration-socket-user
+ (default "nginx"))
+ (socket-group php-fpm-configuration-socket-group
+ (default "nginx"))
+ (process-manager php-fpm-configuration-process-manager
+ (default (php-fpm-process-manager-configuration)))
+ (display-errors php-fpm-configuration-display-errors
+ (default #f))
+ (workers-logfile php-fpm-configuration-workers-logfile
+ (default (string-append "/var/log/php"
+ (version-major (package-version php))
+ "-fpm.log")))
+ (file php-fpm-configuration-file ;#f | file-like
+ (default #f)))
+
+(define-record-type* php-fpm-process-manager-configuration
+ make-php-fpm-process-manager-configuration
+ php-fpm-process-manager-configuration?
+ (type php-fpm-process-manager-configuration-type
+ (default "dynamic"))
+ (max-children php-fpm-process-manager-configuration-max-children
+ (default 5))
+ (start-servers php-fpm-process-manager-configuration-start-servers
+ (default 2))
+ (min-spare-servers php-fpm-process-manager-configuration-min-spare-servers
+ (default 1))
+ (max-spare-servers php-fpm-process-manager-configuration-max-spare-servers
+ (default 3))
+ (process-idle-timeout php-fpm-process-manager-configuration-process-idle-timeout
+ (default 10)))
+
+(define php-fpm-accounts
+ (match-lambda
+ (($ php socket user group socket-user socket-group _ _ _ _)
+ (filter identity
+ (list
+ (user-group (name "www-data") (system? #t))
+ (and (equal? group "php-fpm")
+ (user-group
+ (name "php-fpm")
+ (system? #t)))
+ (and (equal? user "php-fpm")
+ (user-account
+ (name "php-fpm")
+ (group group)
+ (supplementary-groups '("www-data"))
+ (system? #t)
+ (comment "web services group")
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin")))))))))
+
+(define (default-php-fpm-config socket user group socket-user socket-group
+ pm display-errors workers-logfile)
+ (match
+ pm
+ (($ pm.type
+ pm.max-children
+ pm.start-servers
+ pm.min-spare-servers
+ pm.max-spare-servers
+ pm.process-idle-timeout)
+ (apply mixed-text-file "php-fpm.conf"
+ "[global]\n"
+ "[www]\n"
+ "user =" user "\n"
+ "group =" group "\n"
+ "listen =" socket "\n"
+ "listen.owner =" socket-user "\n"
+ "listen.group =" socket-group "\n"
+
+ "pm =" pm.type "\n"
+ "pm.max_children =" (number->string pm.max-children) "\n"
+ "pm.start_servers =" (number->string pm.start-servers) "\n"
+ "pm.min_spare_servers =" (number->string pm.min-spare-servers) "\n"
+ "pm.max_spare_servers =" (number->string pm.max-spare-servers) "\n"
+ "pm.process_idle_timeout =" (number->string pm.process-idle-timeout) "s\n"
+
+ "php_flag[display_errors] = " (if display-errors "on" "off") "\n"
+
+ (if workers-logfile
+ (list "catch_workers_output = yes\n"
+ "php_admin_value[error_log] =" workers-logfile "\n"
+ "php_admin_flag[log_errors] = on\n")
+ (list "catch_workers_output = no\n"))))))
+
+(define php-fpm-shepherd-service
+ (match-lambda
+ (($ php socket user group socket-user socket-group
+ pm display-errors workers-logfile file)
+ (list (shepherd-service
+ (provision '(php-fpm))
+ (documentation "Run the php-fpm daemon.")
+ (requirement '(networking))
+ (start #~(make-forkexec-constructor
+ '(#$(file-append php "/sbin/php-fpm")
+ "--nodaemonize" "-p" "/var" "--fpm-config"
+ #$(or file
+ (default-php-fpm-config socket user group
+ socket-user socket-group pm display-errors
+ workers-logfile)))))
+ (stop #~(make-kill-destructor)))))))
+
+(define php-fpm-activation
+ (match-lambda
+ (($ _ _ user _ _ _ _ _ workers-logfile _)
+ #~(begin
+ (use-modules (guix build utils))
+ (let ((user (getpwnam #$user))
+ (touch (lambda (file-name)
+ (call-with-output-file file-name (const #t)))))
+ ;; prepare writable logfile
+ (when #$workers-logfile
+ (when (not (file-exists? #$workers-logfile))
+ (touch #$workers-logfile))
+ (chown #$workers-logfile (passwd:uid user) (passwd:gid user))
+ (chmod #$workers-logfile #o660)))))))
+
+
+(define php-fpm-service-type
+ (service-type (name 'php-fpm)
+ (extensions
+ (list (service-extension shepherd-root-service-type
+ php-fpm-shepherd-service)
+ (service-extension activation-service-type
+ php-fpm-activation)
+ (service-extension account-service-type
+ php-fpm-accounts)))
+ (default-value (php-fpm-configuration))))
+
+(define* (nginx-php-location
+ #:key
+ (nginx-package nginx)
+ (socket (string-append "/var/run/php"
+ (version-major (package-version php))
+ "-fpm.sock")))
+ "Return a nginx-location-configuration that makes nginx run .php files."
+ (nginx-location-configuration
+ (uri "~ \\.php$")
+ (body (list
+ "fastcgi_split_path_info ^(.+\\.php)(/.+)$;"
+ (string-append "fastcgi_pass unix:" socket ";")
+ "fastcgi_index index.php;"
+ (list "include " nginx-package "/share/nginx/conf/fastcgi.conf;")))))
--
2.14.1