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