summary refs log tree commit diff
path: root/gnu/services/web.scm
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/services/web.scm')
-rw-r--r--gnu/services/web.scm442
1 files changed, 350 insertions, 92 deletions
diff --git a/gnu/services/web.scm b/gnu/services/web.scm
index 9d713003c3..2371ddb6d0 100644
--- a/gnu/services/web.scm
+++ b/gnu/services/web.scm
@@ -4,6 +4,8 @@
 ;;; Copyright © 2016 ng0 <ng0@we.make.ritual.n0.is>
 ;;; Copyright © 2016, 2017 Julien Lepiller <julien@lepiller.eu>
 ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net>
+;;; Copyright © 2017 nee <nee-git@hidamari.blue>
+;;; Copyright © 2017 Clément Lassieur <clement@lassieur.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -26,8 +28,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 (<nginx-configuration>
@@ -38,13 +43,14 @@
             nginx-configuration-run-directory
             nginx-configuration-server-blocks
             nginx-configuration-upstream-blocks
+            nginx-configuration-server-names-hash-bucket-size
+            nginx-configuration-server-names-hash-bucket-max-size
             nginx-configuration-file
 
             <nginx-server-configuration>
             nginx-server-configuration
             nginx-server-configuration?
-            nginx-server-configuration-http-port
-            nginx-server-configuartion-https-port
+            nginx-server-configuration-listen
             nginx-server-configuration-server-name
             nginx-server-configuration-root
             nginx-server-configuration-locations
@@ -52,6 +58,7 @@
             nginx-server-configuration-ssl-certificate
             nginx-server-configuration-ssl-certificate-key
             nginx-server-configuration-server-tokens?
+            nginx-server-configuration-raw-content
 
             <nginx-upstream-configuration>
             nginx-upstream-configuration
@@ -76,7 +83,49 @@
 
             fcgiwrap-configuration
             fcgiwrap-configuration?
-            fcgiwrap-service-type))
+            fcgiwrap-service-type
+
+            <php-fpm-configuration>
+            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>
+            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>
+            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>
+            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:
 ;;;
@@ -87,10 +136,8 @@
 (define-record-type* <nginx-server-configuration>
   nginx-server-configuration make-nginx-server-configuration
   nginx-server-configuration?
-  (http-port           nginx-server-configuration-http-port
-                       (default 80))
-  (https-port          nginx-server-configuration-https-port
-                       (default 443))
+  (listen              nginx-server-configuration-listen
+                       (default '("80" "443 ssl")))
   (server-name         nginx-server-configuration-server-name
                        (default (list 'default)))
   (root                nginx-server-configuration-root
@@ -102,11 +149,13 @@
   (try-files           nginx-server-configuration-try-files
                        (default '()))
   (ssl-certificate     nginx-server-configuration-ssl-certificate
-                       (default "/etc/nginx/cert.pem"))
+                       (default #f))
   (ssl-certificate-key nginx-server-configuration-ssl-certificate-key
-                       (default "/etc/nginx/key.pem"))
+                       (default #f))
   (server-tokens?      nginx-server-configuration-server-tokens?
-                       (default #f)))
+                       (default #f))
+  (raw-content         nginx-server-configuration-raw-content
+                       (default '())))
 
 (define-record-type* <nginx-upstream-configuration>
   nginx-upstream-configuration make-nginx-upstream-configuration
@@ -141,6 +190,10 @@
                  (default '()))          ;list of <nginx-server-configuration>
   (upstream-blocks nginx-configuration-upstream-blocks
                    (default '()))      ;list of <nginx-upstream-configuration>
+  (server-names-hash-bucket-size nginx-configuration-server-names-hash-bucket-size
+                                 (default #f))
+  (server-names-hash-bucket-max-size nginx-configuration-server-names-hash-bucket-max-size
+                                     (default #f))
   (file          nginx-configuration-file         ;#f | string | file-like
                  (default #f)))
 
@@ -173,8 +226,7 @@ of index files."
       "      }\n"))))
 
 (define (emit-nginx-server-config server)
-  (let ((http-port (nginx-server-configuration-http-port server))
-        (https-port (nginx-server-configuration-https-port server))
+  (let ((listen (nginx-server-configuration-listen server))
         (server-name (nginx-server-configuration-server-name server))
         (ssl-certificate (nginx-server-configuration-ssl-certificate server))
         (ssl-certificate-key
@@ -183,7 +235,8 @@ of index files."
         (index (nginx-server-configuration-index server))
         (try-files (nginx-server-configuration-try-files server))
         (server-tokens? (nginx-server-configuration-server-tokens? server))
-        (locations (nginx-server-configuration-locations server)))
+        (locations (nginx-server-configuration-locations server))
+        (raw-content (nginx-server-configuration-raw-content server)))
     (define-syntax-parameter <> (syntax-rules ()))
     (define-syntax-rule (and/l x tail ...)
       (let ((x* x))
@@ -191,20 +244,9 @@ of index files."
             (syntax-parameterize ((<> (identifier-syntax x*)))
               (list tail ...))
             '())))
-    (for-each
-     (match-lambda
-      ((record-key . file)
-       (if (and file (not (file-exists? file)))
-           (error
-            (simple-format
-             #f
-             "~A in the nginx configuration for the server with name \"~A\" does not exist" record-key server-name)))))
-     `(("ssl-certificate"     . ,ssl-certificate)
-       ("ssl-certificate-key" . ,ssl-certificate-key)))
     (list
      "    server {\n"
-     (and/l http-port  "      listen " (number->string <>) ";\n")
-     (and/l https-port "      listen " (number->string <>) " ssl;\n")
+     (map (lambda (directive) (list "      listen " directive ";\n")) listen)
      "      server_name " (config-domain-strings server-name) ";\n"
      (and/l ssl-certificate     "      ssl_certificate " <> ";\n")
      (and/l ssl-certificate-key "      ssl_certificate_key " <> ";\n")
@@ -217,6 +259,7 @@ of index files."
      "\n"
      (map emit-nginx-location-config locations)
      "\n"
+     (map (lambda (x) (list "      " x "\n")) raw-content)
      "    }\n")))
 
 (define (emit-nginx-upstream-config upstream)
@@ -235,25 +278,43 @@ of index files."
         (cons head out)))
   (fold-right flatten1 '() lst))
 
-(define (default-nginx-config nginx log-directory run-directory server-list upstream-list)
-  (apply mixed-text-file "nginx.conf"
-         (flatten
-          "user nginx nginx;\n"
-          "pid " run-directory "/pid;\n"
-          "error_log " log-directory "/error.log info;\n"
-          "http {\n"
-          "    client_body_temp_path " run-directory "/client_body_temp;\n"
-          "    proxy_temp_path " run-directory "/proxy_temp;\n"
-          "    fastcgi_temp_path " run-directory "/fastcgi_temp;\n"
-          "    uwsgi_temp_path " run-directory "/uwsgi_temp;\n"
-          "    scgi_temp_path " run-directory "/scgi_temp;\n"
-          "    access_log " log-directory "/access.log;\n"
-          "    include " nginx "/share/nginx/conf/mime.types;\n"
-          "\n"
-          (map emit-nginx-upstream-config upstream-list)
-          (map emit-nginx-server-config server-list)
-          "}\n"
-          "events {}\n")))
+(define (default-nginx-config config)
+  (match-record config
+                <nginx-configuration>
+                (nginx log-directory run-directory
+                 server-blocks upstream-blocks
+                 server-names-hash-bucket-size
+                 server-names-hash-bucket-max-size)
+   (apply mixed-text-file "nginx.conf"
+          (flatten
+           "user nginx nginx;\n"
+           "pid " run-directory "/pid;\n"
+           "error_log " log-directory "/error.log info;\n"
+           "http {\n"
+           "    client_body_temp_path " run-directory "/client_body_temp;\n"
+           "    proxy_temp_path " run-directory "/proxy_temp;\n"
+           "    fastcgi_temp_path " run-directory "/fastcgi_temp;\n"
+           "    uwsgi_temp_path " run-directory "/uwsgi_temp;\n"
+           "    scgi_temp_path " run-directory "/scgi_temp;\n"
+           "    access_log " log-directory "/access.log;\n"
+           "    include " nginx "/share/nginx/conf/mime.types;\n"
+           (if server-names-hash-bucket-size
+               (string-append
+                "    server_names_hash_bucket_size "
+                (number->string server-names-hash-bucket-size)
+                ";\n")
+               "")
+           (if server-names-hash-bucket-max-size
+               (string-append
+                "    server_names_hash_bucket_max_size "
+                (number->string server-names-hash-bucket-max-size)
+                ";\n")
+               "")
+           "\n"
+           (map emit-nginx-upstream-config upstream-blocks)
+           (map emit-nginx-server-config server-blocks)
+           "}\n"
+           "events {}\n"))))
 
 (define %nginx-accounts
   (list (user-group (name "nginx") (system? #t))
@@ -265,55 +326,53 @@ of index files."
          (home-directory "/var/empty")
          (shell (file-append shadow "/sbin/nologin")))))
 
-(define nginx-activation
-  (match-lambda
-    (($ <nginx-configuration> nginx log-directory run-directory server-blocks
-                              upstream-blocks file)
-     #~(begin
-         (use-modules (guix build utils))
+(define (nginx-activation config)
+  (match-record config
+                <nginx-configuration>
+                (nginx log-directory run-directory file)
+   #~(begin
+       (use-modules (guix build utils))
 
-         (format #t "creating nginx log directory '~a'~%" #$log-directory)
-         (mkdir-p #$log-directory)
-         (format #t "creating nginx run directory '~a'~%" #$run-directory)
-         (mkdir-p #$run-directory)
-         (format #t "creating nginx temp directories '~a/{client_body,proxy,fastcgi,uwsgi,scgi}_temp'~%" #$run-directory)
-         (mkdir-p (string-append #$run-directory "/client_body_temp"))
-         (mkdir-p (string-append #$run-directory "/proxy_temp"))
-         (mkdir-p (string-append #$run-directory "/fastcgi_temp"))
-         (mkdir-p (string-append #$run-directory "/uwsgi_temp"))
-         (mkdir-p (string-append #$run-directory "/scgi_temp"))
-         ;; Start-up logs. Once configuration is loaded, nginx switches to
-         ;; log-directory.
-         (mkdir-p (string-append #$run-directory "/logs"))
-         ;; Check configuration file syntax.
-         (system* (string-append #$nginx "/sbin/nginx")
-                  "-c" #$(or file
-                             (default-nginx-config nginx log-directory
-                               run-directory server-blocks upstream-blocks))
-                  "-t")))))
-
-(define nginx-shepherd-service
-  (match-lambda
-    (($ <nginx-configuration> nginx log-directory run-directory server-blocks
-                              upstream-blocks file)
-     (let* ((nginx-binary (file-append nginx "/sbin/nginx"))
-            (nginx-action
-             (lambda args
-               #~(lambda _
-                   (zero?
-                    (system* #$nginx-binary "-c"
-                             #$(or file
-                                   (default-nginx-config nginx log-directory
-                                     run-directory server-blocks upstream-blocks))
-                             #$@args))))))
-
-       ;; TODO: Add 'reload' action.
-       (list (shepherd-service
-              (provision '(nginx))
-              (documentation "Run the nginx daemon.")
-              (requirement '(user-processes loopback))
-              (start (nginx-action "-p" run-directory))
-              (stop (nginx-action "-s" "stop"))))))))
+       (format #t "creating nginx log directory '~a'~%" #$log-directory)
+       (mkdir-p #$log-directory)
+       (format #t "creating nginx run directory '~a'~%" #$run-directory)
+       (mkdir-p #$run-directory)
+       (format #t "creating nginx temp directories '~a/{client_body,proxy,fastcgi,uwsgi,scgi}_temp'~%" #$run-directory)
+       (mkdir-p (string-append #$run-directory "/client_body_temp"))
+       (mkdir-p (string-append #$run-directory "/proxy_temp"))
+       (mkdir-p (string-append #$run-directory "/fastcgi_temp"))
+       (mkdir-p (string-append #$run-directory "/uwsgi_temp"))
+       (mkdir-p (string-append #$run-directory "/scgi_temp"))
+       ;; Start-up logs. Once configuration is loaded, nginx switches to
+       ;; log-directory.
+       (mkdir-p (string-append #$run-directory "/logs"))
+       ;; Check configuration file syntax.
+       (system* (string-append #$nginx "/sbin/nginx")
+                "-c" #$(or file
+                           (default-nginx-config config))
+                  "-t"))))
+
+(define (nginx-shepherd-service config)
+  (match-record config
+                <nginx-configuration>
+                (nginx file run-directory)
+   (let* ((nginx-binary (file-append nginx "/sbin/nginx"))
+          (nginx-action
+           (lambda args
+             #~(lambda _
+                 (zero?
+                  (system* #$nginx-binary "-c"
+                           #$(or file
+                                 (default-nginx-config config))
+                           #$@args))))))
+
+     ;; TODO: Add 'reload' action.
+     (list (shepherd-service
+            (provision '(nginx))
+            (documentation "Run the nginx daemon.")
+            (requirement '(user-processes loopback))
+            (start (nginx-action "-p" run-directory))
+            (stop (nginx-action "-s" "stop")))))))
 
 (define nginx-service-type
   (service-type (name 'nginx)
@@ -385,3 +444,202 @@ of index files."
 		       (service-extension account-service-type
                                           fcgiwrap-accounts)))
                 (default-value (fcgiwrap-configuration))))
+
+(define-record-type* <php-fpm-configuration> php-fpm-configuration
+  make-php-fpm-configuration
+  php-fpm-configuration?
+  (php              php-fpm-configuration-php ;<package>
+                    (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 "nginx"))
+  (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>
+  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>
+  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>
+  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-fpm-configuration> 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
+            (($ <php-fpm-dynamic-process-manager-configuration>
+                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"))
+
+            (($ <php-fpm-static-process-manager-configuration>
+                pm.max-children)
+             (list
+              "pm = static\n"
+              "pm.max_children =" (number->string pm.max-children) "\n"))
+
+            (($ <php-fpm-on-demand-process-manager-configuration>
+                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-fpm-configuration> 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")
+                        "--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
+    (($ <php-fpm-configuration> _ _ 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
+    "Run @command{php-fpm} to provide a fastcgi socket for calling php through
+a webserver.")
+   (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;")))))