From db872151028194b618af4ed652ea6934f10ce7ab 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 | 137 +++++++++++++++++++++++++++-
gnu/services/web.scm | 248 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 382 insertions(+), 3 deletions(-)
diff --git a/doc/guix.texi b/doc/guix.texi
index f0a59a6b4..280ab9930 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -40,7 +40,8 @@ Copyright @copyright{} 2017 Christopher Allan address@hidden
Copyright @copyright{} 2017 Marius address@hidden
Copyright @copyright{} 2017 Hartmut address@hidden
Copyright @copyright{} 2017 Maxim address@hidden
-Copyright @copyright{} 2017 Tobias Geerinckx-Rice
+Copyright @copyright{} 2017 Tobias address@hidden
+Copyright @copyright{} 2017 nee
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -14529,6 +14530,140 @@ 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.
+
+These features include:
address@hidden @bullet
address@hidden Adaptive process spawning
address@hidden Basic statistics (ala Apache's mod_status)
address@hidden Advanced process management with graceful stop/start
address@hidden Ability to start workers with different uid/gid/chroot/environment
+and different php.ini (replaces safe_mode)
address@hidden Stdout & stderr logging
address@hidden Emergency restart in case of accidental opcode cache destruction
address@hidden Accelerated upload support
address@hidden Support for a "slowlog"
address@hidden Enhancements to FastCGI, such as fastcgi_finish_request() -
+a special function to finish request & flush all data while continuing to do
+something time-consuming (video converting, stats processing, etc.)
address@hidden itemize
+... and much more.
+
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{php-fpm})
+User who can speak to the php-fpm socket.
address@hidden @code {socket-group} (default: @code{php-fpm})
+Group that can speak to the php-fpm socket.
address@hidden @code {pid-file} (default: @code{(string-append "/var/log/php" (version-major (package-version php)) "-fpm.pid")})
+The process id of the php-fpm process is written to this file
+once the service has started.
address@hidden @code {log-file} (default: @code{(string-append "/var/log/php" (version-major (package-version php)) "-fpm.log")})
+Log for the php-fpm master process.
address@hidden @code {process-manager} (default: @code{(php-fpm-dynamic-process-manager-configuration)})
+Detailed settings for the php-fpm process manager.
+Must be either:
address@hidden @asis
address@hidden @code{}
address@hidden @code{}
address@hidden @code{}
address@hidden table
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.www.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-dynamic-process-manager-configuration
+Data Type for the @code{dynamic} php-fpm process manager.
+With the @code{dynamic} process manager spare worker processes are kept around
+based on it's configured limits.
address@hidden @asis
address@hidden @code {max-children} (default: @code{5})
+Maximum of worker processes.
address@hidden @code {start-servers} (default: @code{2})
+How many worker processes should be started on start-up.
address@hidden @code {min-spare-servers} (default: @code{1})
+How many spare worker processes should be kept around at minimum.
address@hidden @code {max-spare-servers} (default: @code{3})
+How many spare worker processes should be kept around at maximum.
address@hidden table
address@hidden deftp
+
address@hidden {Data type} php-fpm-static-process-manager-configuration
+Data Type for the @code{static} php-fpm process manager.
+With the @code{static} process manager an unchanging number
+of worker processes is created.
address@hidden @asis
address@hidden @code {max-children} (default: @code{5})
+Maximum of worker processes.
address@hidden table
address@hidden deftp
+
address@hidden {Data type} php-fpm-on-demand-process-manager-configuration
+Data Type for the @code{on-demand} php-fpm process manager.
+With the @code{on-demand} process manager worker processes are only created
+as requests arrive.
address@hidden @asis
address@hidden @code {max-children} (default: @code{5})
+Maximum of worker processes.
address@hidden @code {process-idle-timeout} (default: @code{10})
+The time in seconds after which a process with no requests is killed.
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)
+ (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..ef51f4a55 100644
--- a/gnu/services/web.scm
+++ b/gnu/services/web.scm
@@ -4,6 +4,7 @@
;;; Copyright © 2016 ng0
;;; Copyright © 2016, 2017 Julien Lepiller
;;; Copyright © 2017 Christopher Baines
+;;; Copyright © 2017 nee
;;;
;;; This file is part of GNU Guix.
;;;
@@ -26,8 +27,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 +80,49 @@
fcgiwrap-configuration
fcgiwrap-configuration?
- fcgiwrap-service-type))
+ fcgiwrap-service-type
+
+
+ php-fpm-configuration
+ make-php-fpm-configuration
+ php-fpm-configuration?
+ php-fpm-configuration-php
+ php-fpm-configuration-socket
+ php-fpm-configuration-user
+ php-fpm-configuration-group
+ php-fpm-configuration-socket-user
+ php-fpm-configuration-socket-group
+ php-fpm-configuration-pid-file
+ php-fpm-configuration-log-file
+ php-fpm-configuration-process-manager
+ php-fpm-configuration-display-errors
+ php-fpm-configuration-workers-log-file
+ php-fpm-configuration-file
+
+
+ php-fpm-dynamic-process-manager-configuration
+ make-php-fpm-dynamic-process-manager-configuration
+ php-fpm-dynamic-process-manager-configuration?
+ php-fpm-dynamic-process-manager-configuration-max-children
+ php-fpm-dynamic-process-manager-configuration-start-servers
+ php-fpm-dynamic-process-manager-configuration-min-spare-servers
+ php-fpm-dynamic-process-manager-configuration-max-spare-servers
+
+
+ php-fpm-static-process-manager-configuration
+ make-php-fpm-static-process-manager-configuration
+ php-fpm-static-process-manager-configuration?
+ php-fpm-static-process-manager-configuration-max-children
+
+
+ php-fpm-on-demand-process-manager-configuration
+ make-php-fpm-on-demand-process-manager-configuration
+ php-fpm-on-demand-process-manager-configuration?
+ php-fpm-on-demand-process-manager-configuration-max-children
+ php-fpm-on-demand-process-manager-configuration-process-idle-timeout
+
+ php-fpm-service-type
+ nginx-php-location))
;;; Commentary:
;;;
@@ -256,10 +302,12 @@ of index files."
"events {}\n")))
(define %nginx-accounts
- (list (user-group (name "nginx") (system? #t))
+ (list (user-group (name "php-fpm") (system? #t))
+ (user-group (name "nginx") (system? #t))
(user-account
(name "nginx")
(group "nginx")
+ (supplementary-groups '("php-fpm"))
(system? #t)
(comment "nginx server user")
(home-directory "/var/empty")
@@ -385,3 +433,199 @@ 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 "php-fpm"))
+ (socket-group php-fpm-configuration-socket-group
+ (default "php-fpm"))
+ (pid-file php-fpm-configuration-pid-file
+ (default (string-append "/var/run/php"
+ (version-major (package-version php))
+ "-fpm.pid")))
+ (log-file php-fpm-configuration-log-file
+ (default (string-append "/var/log/php"
+ (version-major (package-version php))
+ "-fpm.log")))
+ (process-manager php-fpm-configuration-process-manager
+ (default (php-fpm-dynamic-process-manager-configuration)))
+ (display-errors php-fpm-configuration-display-errors
+ (default #f))
+ (workers-log-file php-fpm-configuration-workers-log-file
+ (default (string-append "/var/log/php"
+ (version-major (package-version php))
+ "-fpm.www.log")))
+ (file php-fpm-configuration-file ;#f | file-like
+ (default #f)))
+
+(define-record-type*
+ php-fpm-dynamic-process-manager-configuration
+ make-php-fpm-dynamic-process-manager-configuration
+ php-fpm-dynamic-process-manager-configuration?
+ (max-children php-fpm-dynamic-process-manager-configuration-max-children
+ (default 5))
+ (start-servers php-fpm-dynamic-process-manager-configuration-start-servers
+ (default 2))
+ (min-spare-servers php-fpm-dynamic-process-manager-configuration-min-spare-servers
+ (default 1))
+ (max-spare-servers php-fpm-dynamic-process-manager-configuration-max-spare-servers
+ (default 3)))
+
+(define-record-type*
+ php-fpm-static-process-manager-configuration
+ make-php-fpm-static-process-manager-configuration
+ php-fpm-static-process-manager-configuration?
+ (max-children php-fpm-static-process-manager-configuration-max-children
+ (default 5)))
+
+(define-record-type*
+ php-fpm-on-demand-process-manager-configuration
+ make-php-fpm-on-demand-process-manager-configuration
+ php-fpm-on-demand-process-manager-configuration?
+ (max-children php-fpm-on-demand-process-manager-configuration-max-children
+ (default 5))
+ (process-idle-timeout php-fpm-on-demand-process-manager-configuration-process-idle-timeout
+ (default 10)))
+
+(define php-fpm-accounts
+ (match-lambda
+ (($ php socket user group socket-user socket-group _ _ _ _ _ _)
+ (list
+ (user-group (name "php-fpm") (system? #t))
+ (user-group
+ (name group)
+ (system? #t))
+ (user-account
+ (name user)
+ (group group)
+ (supplementary-groups '("php-fpm"))
+ (system? #t)
+ (comment "php-fpm daemon user")
+ (home-directory "/var/empty")
+ (shell (file-append shadow "/sbin/nologin")))))))
+
+(define (default-php-fpm-config socket user group socket-user socket-group
+ pid-file log-file pm display-errors workers-log-file)
+ (apply mixed-text-file "php-fpm.conf"
+ (flatten
+ "[global]\n"
+ "pid =" pid-file "\n"
+ "error_log =" log-file "\n"
+ "[www]\n"
+ "user =" user "\n"
+ "group =" group "\n"
+ "listen =" socket "\n"
+ "listen.owner =" socket-user "\n"
+ "listen.group =" socket-group "\n"
+
+ (match pm
+ (($
+ pm.max-children
+ pm.start-servers
+ pm.min-spare-servers
+ pm.max-spare-servers)
+ (list
+ "pm = dynamic\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.max-children)
+ (list
+ "pm = static\n"
+ "pm.max_children =" (number->string pm.max-children) "\n"))
+
+ (($
+ pm.max-children
+ pm.process-idle-timeout)
+ (list
+ "pm = ondemand\n"
+ "pm.max_children =" (number->string pm.max-children) "\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-log-file
+ (list "catch_workers_output = yes\n"
+ "php_admin_value[error_log] =" workers-log-file "\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
+ pid-file log-file pm display-errors workers-log-file 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 pid-file log-file
+ pm display-errors workers-log-file)))
+ #:pid-file #$pid-file))
+ (stop #~(make-kill-destructor)))))))
+
+(define php-fpm-activation
+ (match-lambda
+ (($ _ _ user _ _ _ _ log-file _ _ workers-log-file _)
+ #~(begin
+ (use-modules (guix build utils))
+ (let* ((user (getpwnam #$user))
+ (touch (lambda (file-name)
+ (call-with-output-file file-name (const #t))))
+ (init-log-file
+ (lambda (file-name)
+ (when #$workers-log-file
+ (when (not (file-exists? file-name))
+ (touch file-name))
+ (chown file-name (passwd:uid user) (passwd:gid user))
+ (chmod file-name #o660)))))
+ (init-log-file #$log-file)
+ (init-log-file #$workers-log-file))))))
+
+
+(define php-fpm-service-type
+ (service-type (name 'php-fpm)
+ (description "The php-fpm service-type.")
+ (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