Commit eee846a4dc6bc83e294e2fc5472231d1faa4f750

Authored by nollieheel
1 parent 70b9bd40

Bump to v0.3.0.

Add support for multiple upstream servers in nginx config.
Add support for LetsEncrypt certificate configurations.
  1 +# 0.3.0
  2 +
  3 +Add support for multiple FastCGI ports.
  4 +Add support for Letsencrypt configuration.
  5 +
1 6 # 0.2.1
2 7
3 8 Add some defaults for php-fpm
... ...
... ... @@ -18,12 +18,6 @@ Ubuntu 14.04
18 18 <th>Default</th>
19 19 </tr>
20 20 <tr>
21   - <td><tt>['cfe-nginx-php-fpm']['php_fastcgi_socket']</tt></td>
22   - <td>String</td>
23   - <td>The socket used by PHP-FPM. Set to boolean false to disable PHP-FPM.</td>
24   - <td><tt>'127.0.0.1:9000'</tt></td>
25   - </tr>
26   - <tr>
27 21 <td><tt>['cfe-nginx-php-fpm']['postfix']['email_domain']</tt></td>
28 22 <td>String</td>
29 23 <td>Email domain to be used by Postfix.</td>
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Attribute:: default
5 5 #
... ... @@ -18,12 +18,30 @@
18 18 # limitations under the License.
19 19 #
20 20
  21 +# TODO defunct attribs
21 22 # The socket used PHP-FPM. If false, fastcgi is not used.
22 23 # Examples:
23 24 # '127.0.0.1:9000'
24 25 # '/var/run/php-fpm.sock'
25 26 # false
26   -default['cfe-nginx-php-fpm']['php_fastcgi_socket'] = '127.0.0.1:9000'
  27 +#default['cfe-nginx-php-fpm']['php_fastcgi_socket'] = '127.0.0.1:9000'
  28 +
  29 +# PHP-FPM sockets to be used. If unset, or set to string 'php-fpm-pools' (default),
  30 +# the recipe automatically gets this value from node['php-fpm']['pools'].
  31 +#default['cfe-nginx-php-fpm']['php_fastcgi_sockets'] = [
  32 +# {
  33 +# :name => 'example_socket',
  34 +# # Example values:
  35 +# # '127.0.0.1:9000'
  36 +# # '127.0.0.1:9001'
  37 +# # '/var/run/php-fpm.sock'
  38 +# :listen => '127.0.0.1:9000',
  39 +# # An optional array of comments for this socket
  40 +# :comments => []
  41 +# }
  42 +#]
  43 +
  44 +
27 45
28 46 # Setting 'update_cacert' to true will get the latest cacert from
29 47 # http://curl.haxx.se/ca/cacert.pem and use that as CAFile for postfix.
... ... @@ -51,35 +69,64 @@ default['cfe-nginx-php-fpm']['nginx']['restriction_file']['static_types'] = %w{
51 69
52 70 default['cfe-nginx-php-fpm']['nginx']['sites'] = [
53 71 #{
  72 + # Name of server. Mandatory.
  73 + #
54 74 #:server_name => 'example.com',
  75 +
  76 + # Server aliases in an array. Default: []
  77 + #
55 78 #:aliases => ['www.example.com'],
  79 +
  80 + # Location of document root. If not given, the root directive
  81 + # will not be included in the config. Default: nil
  82 + #
56 83 #:doc_root => '/var/www/example.com',
  84 +
  85 + # Index, if applicable, of the site. Default: nil
  86 + #
57 87 #:index => 'index.php',
58 88
59   - # Access log options as one long string. Default: false
  89 + # Access log options as one long string. Default: nil
  90 + #
60 91 #:access_log_options => '<some options>',
61 92
62 93 # Whether to include a default virtual server named '_' or not.
63 94 # If there is more than one server given in this 'sites' array,
64   - # 'catch_all' value will always be overriden to 'false'.
65   - # Default: true
  95 + # :catch_all value will always be overriden to false. Default: true
  96 + #
66 97 #:catch_all => true,
67 98
68   - # Necessary values for SSL/TLS setup. Default: :ssl => false
  99 + # Necessary values for SSL/TLS setup. Default: nil
  100 + #
69 101 #:ssl => {
70   - # :cert => '[contents of chain cert here]',
71   - # :key => '[contents of cert private key here]',
72   - # :dh_modulus => 2048,
73   - # :self_signed => false,
74   - # :hsts_max_age => '15758000',
75   - # :hsts_include_subdomains => true
  102 + # # Subvalues and their defaults:
  103 + #
  104 + # # If LetsEncrypt is used, set to true.
  105 + # # le_sub_dir defaults to the server name.
  106 + # #
  107 + # :letsencrypt => false,
  108 + # :le_base_dir => '/etc/letsencrypt/live',
  109 + # :le_sub_dir => '<server_name>',
  110 + #
  111 + # # If not using LetsEncrypt, specify cert and key here.
  112 + # # If using LetsEncrypt, these attributes are not used:
  113 + # #
  114 + # :cert => '<contents of chain cert here>',
  115 + # :key => '<contents of cert private key here>',
  116 + #
  117 + # :self_signed => false,
  118 + # :cipher_suite => 'medium', # or 'modern'
  119 + # :dh_modulus => 4096,
  120 + # :hsts_max_age => '15758000',
  121 + # :hsts_subdomains => true
76 122 #},
77 123
78   - # Necessary values for Basic Auth setup. Default: :auth => false
  124 + # Necessary values for Basic Auth setup. Default: nil
  125 + #
79 126 #:auth => {
80 127 # :msg => 'Restricted Area. Please authenticate.',
81 128 # :users => {
82   - # 'example_user' => 'secretpassword123'
  129 + # 'example_user' => '<password>'
83 130 # }
84 131 #},
85 132
... ... @@ -87,31 +134,63 @@ default['cfe-nginx-php-fpm']['nginx']['sites'] = [
87 134 # the 'server' declaration. Default: []
88 135 #:init_statements => [],
89 136
  137 + # Additional headers to insert into the server responses.
  138 + # If the site uses HTTPS, the header 'Strict-Transport-Security' will
  139 + # always be included. Default:
  140 + # {
  141 + # 'X-Frame-Options' => 'SAMEORIGIN',
  142 + # 'X-Content-Type-Options' => 'nosniff',
  143 + # 'X-XSS-Protection' => '"1; mode=block"',
  144 + # 'X-Permitted-Cross-Domain-Policies' => 'none'
  145 + # }
  146 + #
  147 + #:add_headers => {},
  148 +
90 149 # An array of strings that will be included as statements in the main
91   - # nginx config file for this server. Default: []
92   - #:custom_statements => [],
  150 + # nginx config file for this server, before the first 'include'
  151 + # directive. Default: []
  152 + #
  153 + #:server_statements_1 => [],
  154 +
  155 + # An array of strings that will be included as statements in the main
  156 + # nginx config file for this server, after the last 'include'
  157 + # directive. Default: []
  158 + #
  159 + #:server_statements_2 => [],
93 160
94 161 # Enumerates the different site types this server supports.
95   - # Possible elements of :types are (only :type is mandatory):
96   - # {
97   - # :type => 'basic',
98   - # :subpath => ''
99   - # }
100   - # {
101   - # :type => 'wordpress',
102   - # :subpath => '',
103   - # :fastcgi_intercept_errors => false,
104   - # :loginpage_statements => [] # An array of strings to be
105   - # # written on the config for the
106   - # # /wp-login.php and /wp-admin pages.
107   - # }
108   - # {
109   - # :type => 'webserver',
110   - # :subpath => '',
111   - # :upstream_name => 'example',
112   - # :upstream_ip => '127.0.0.1',
113   - # :upstream_port => '8080',
114   - # }
  162 + # Each type element of this array is a hash containing different attributes.
  163 + #
  164 + # Mandatory attributes are:
  165 + # :type => One of: 'basic' (basic PHP site)
  166 + # 'wordpress' (standard Wordpress site)
  167 + # 'webserver' (proxy webserver)
  168 + # :upstream_servers => An array containing upstream server endpoints.
  169 + # Unix socket example: ['/var/run/php-fpm.sock']
  170 + # Tcp port example: ['127.0.0.1:9000']
  171 + #
  172 + # Optional attributes are:
  173 + # :subpath => A string of the form: 'news/blog'.
  174 + # Indicates what subpath of the site this type applies.
  175 + # Default: '', which means this site type applies
  176 + # to the root directory of the site.
  177 + # :upstream_name => The auto-generated config's upstream name can
  178 + # be customized through this attribute.
  179 + # Default: (an auto-generated string)
  180 + # :add_statements => Additional statements to put in the config file.
  181 + # Default: []
  182 + #
  183 + # Unique attributes for each type are indicated below:
  184 + # Basic PHP Site (:type => 'basic'):
  185 + # :fastcgi_intercept_errors => Optional. Default: false
  186 + # Standard Wordpress Site (:type => 'wordpress'):
  187 + # :fastcgi_intercept_errors => Optional. Default: false
  188 + # :loginpage_statements => An array of strings to be put on the
  189 + # config for the /wp-login.php
  190 + # and /wp-admin pages. Default: []
  191 + # Proxy Webserver (:type => 'webserver'):
  192 + # (none)
  193 + #
115 194 #:types => []
116 195 #}
117 196 ]
... ... @@ -132,12 +211,14 @@ default['php-fpm']['pools'] = [
132 211 # Most likely, just use one pool for all PHP needs.
133 212 # (But there are exceptions, of course)
134 213 {
  214 + # Required attributes:
135 215 :name => 'example_pool',
136 216 :enable => true,
  217 + :listen => '127.0.0.1:9000',
  218 + #:listen => '/var/run/php-fpm.sock',
137 219
138   - # Default value is: node['cfe-nginx-php-fpm']['php_fastcgi_socket']
139   - #:listen => node['cfe-nginx-php-fpm']['php_fastcgi_socket'],
140   -
  220 + # Optional attributes with their defaults:
  221 + #
141 222 # Default is same as Nginx user and group
142 223 #:user => node['nginx']['user'],
143 224 #:group => node['nginx']['group'],
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Definition:: php_ext
5 5 #
... ...
... ... @@ -4,7 +4,7 @@ maintainer_email 'sysadmin@chromedia.com'
4 4 license 'Apache License'
5 5 description 'Simplifies setup of Nginx+PHP-FPM in Chromedia.'
6 6 long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7   -version '0.2.1'
  7 +version '0.3.0'
8 8
9 9 {
10 10 'php-fpm' => '0.7.5',
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Recipe:: default
5 5 #
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Recipe:: mariadb_client
5 5 #
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Recipe:: nginx
5 5 #
... ... @@ -30,216 +30,4 @@ node.default['cfe-nginx-php-fpm']['nginx']['priv_dir'] =
30 30 # Begin server configuration
31 31
32 32 include_recipe 'nginx'
33   -
34   -attribs = node['cfe-nginx-php-fpm']['nginx']
35   -inc_dir = attribs['inc_dir']
36   -priv_dir = attribs['priv_dir']
37   -
38   -[ inc_dir, priv_dir ].each do |ndir|
39   - directory ndir do
40   - recursive true
41   - end
42   -end
43   -
44   -# The restrictions.conf file containing default rules for virtual servers.
45   -path_rest = "#{inc_dir}/restrictions.conf"
46   -template path_rest do
47   - action :create_if_missing
48   - mode 0644
49   - variables(
50   - :log_robots => attribs['restriction_file']['log_robots'],
51   - :log_hidden => attribs['restriction_file']['log_hidden'],
52   - :log_static => attribs['restriction_file']['log_static'],
53   - :static_types => attribs['restriction_file']['static_types']
54   - )
55   -end
56   -
57   -# Some basic "include" files for PHP
58   -path_bpf = "#{inc_dir}/inc_basic_php_fastcgi"
59   -template path_bpf do
60   - action :create_if_missing
61   - mode 0644
62   - variables(
63   - :socket => node['cfe-nginx-php-fpm']['php_fastcgi_socket']
64   - )
65   - only_if { node['cfe-nginx-php-fpm']['php_fastcgi_socket'] }
66   -end
67   -
68   -catch_all_def_false = attribs['sites'].length > 1
69   -
70   -attribs['sites'].each do |site|
71   -
72   - if site.is_a?(Array)
73   - site_sname = site[0]
74   - site = site[1]
75   - else
76   - site_sname = site[:server_name]
77   - end
78   -
79   - site_index = site[:index] || 'index.php'
80   - site_aliases = site[:aliases] || []
81   - site_doc_root = site[:doc_root] || ''
82   - site_ssl = site[:ssl] || false
83   - site_auth = site[:auth] || false
84   - site_alo = site[:access_log_options] || false
85   - site_cs = site[:custom_statements] || []
86   - site_ins = site[:init_statements] || []
87   -
88   - site_types = ( site[:types] || [] ).uniq { |e| e[:type] }
89   -
90   - temp_catch_all = site.has_key?(:catch_all) ? site[:catch_all] : true
91   - site_catch_all = catch_all_def_false ? false : temp_catch_all
92   -
93   - path_crt = "#{priv_dir}/#{site_sname}.crt"
94   - path_key = "#{priv_dir}/#{site_sname}.key"
95   - path_pass = "#{priv_dir}/#{site_sname}.htpasswd"
96   - path_dhparam = "#{priv_dir}/#{site_sname}.dhparam"
97   -
98   - # If TLS/SSL is enabled, create necessary files
99   - if site_ssl
100   - if site_ssl[:cert].nil?
101   - Chef::Log.error('Missing SSL certificate')
102   - raise 'Missing SSL certificate'
103   - end
104   -
105   - if site_ssl[:key].nil?
106   - Chef::Log.error('Missing SSL key file')
107   - raise 'Missing SSL key file'
108   - end
109   -
110   - file path_crt do
111   - mode 0644
112   - content site_ssl[:cert]
113   - sensitive true
114   - action :create_if_missing
115   - end
116   -
117   - file path_key do
118   - mode 0644
119   - content site_ssl[:key]
120   - sensitive true
121   - action :create_if_missing
122   - end
123   -
124   - dh_modulus = site_ssl[:dh_modulus] || 2048
125   - execute "openssl dhparam -out #{path_dhparam} #{dh_modulus}" do
126   - not_if { ::File.exist?(path_dhparam) }
127   - end
128   - end
129   -
130   - # If basic auth is enabled, create htaccess file
131   - if site_auth
132   - site_auth[:users].each do |auser, apass|
133   - execute "Generate #{path_pass}" do
134   - command "printf \"#{auser}:"\
135   - "$( openssl passwd -apr1 '#{apass}' )"\
136   - "\\n\" >> #{path_pass}"
137   - action :run
138   - sensitive true
139   - not_if { ::File.exist?(path_pass) }
140   - end
141   - end
142   - end
143   -
144   - site_includes = []
145   - upstreams = []
146   -
147   - # Create necessary include files for each type of this site
148   - site_types.each do |stype|
149   - stype_subp = stype[:subpath] ? stype[:subpath].gsub(/^\/+|\/$|\s/, '') : ''
150   - stype_subp = stype_subp.length > 0 ? "#{stype_subp}/" : stype_subp
151   -
152   - case stype[:type]
153   - # BASIC PHP SITE
154   - when 'basic'
155   - template "#{inc_dir}/inc_type_basic_#{site_sname}" do
156   - source 'inc_type_basic.erb'
157   - mode 0644
158   - action :create_if_missing
159   - variables(
160   - :index => site_index,
161   - :subpath => stype_subp,
162   - :basic_php_fastcgi => path_bpf
163   - )
164   - end
165   - site_includes.push("#{inc_dir}/inc_type_basic_#{site_sname}")
166   -
167   - # STANDARD WORDPRESS SITE
168   - when 'wordpress'
169   - template "#{inc_dir}/inc_type_wordpress_#{site_sname}" do
170   - source 'inc_type_wordpress.erb'
171   - mode 0644
172   - action :create_if_missing
173   - variables(
174   - :index => site_index,
175   - :subpath => stype_subp,
176   - :basic_php_fastcgi => path_bpf,
177   - :loginpage_statements => stype[:loginpage_statements] || [],
178   - :fastcgi_intercept_errors => stype[:fastcgi_intercept_errors] || false
179   - )
180   - end
181   - site_includes.push("#{inc_dir}/inc_type_wordpress_#{site_sname}")
182   -
183   - # BASIC PROXIED WEBSERVER
184   - when 'webserver'
185   - upstream_name = stype[:upstream_name] || 'webserver'
186   - template "#{inc_dir}/inc_type_webserver_#{site_sname}" do
187   - source 'inc_type_webserver.erb'
188   - mode 0644
189   - action :create_if_missing
190   - variables(
191   - :subpath => stype_subp,
192   - :upstream_name => upstream_name
193   - )
194   - end
195   - site_ins.push("map $http_upgrade $connection_upgrade {\n"\
196   - " default upgrade;\n"\
197   - " '' close;\n"\
198   - "}")
199   - upstreams.push( {
200   - :name => upstream_name,
201   - :ip => stype[:upstream_ip] || '127.0.0.1',
202   - :port => stype[:upstream_port] || '8080'
203   - } )
204   - site_includes.push("#{inc_dir}/inc_type_webserver_#{site_sname}")
205   -
206   - else
207   - Chef::Log.error("Unknown site type: #{stype[:type]}")
208   - raise 'Unknown site type'
209   - end
210   - end
211   -
212   - # Create the main config file for this site
213   - template "#{node['nginx']['dir']}/sites-available/#{site_sname}" do
214   - source 'nginx_site.conf.erb'
215   - action :create_if_missing
216   - mode 0644
217   - notifies :restart, 'service[nginx]'
218   - variables(
219   - :server_name => site_sname,
220   - :aliases => site_aliases,
221   - :doc_root => site_doc_root,
222   - :index => site_index,
223   - :ssl => site_ssl,
224   - :auth => site_auth,
225   -
226   - :access_log_options => site_alo,
227   - :catch_all => site_catch_all,
228   -
229   - :path_crt => path_crt,
230   - :path_key => path_key,
231   - :path_pass => path_pass,
232   - :path_dhparam => path_dhparam,
233   - :path_rest => path_rest,
234   -
235   - :upstreams => upstreams,
236   - :includes => site_includes,
237   - :init_statements => site_ins,
238   - :custom_statements => site_cs
239   - )
240   - end
241   -
242   - nginx_site site_sname do
243   - enable true
244   - end
245   -end
  33 +include_recipe "#{cookbook_name}::nginx_configure"
... ...
  1 +#
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
  3 +# Cookbook Name:: cfe-nginx-php-fpm
  4 +# Recipe:: nginx_configure
  5 +#
  6 +# Copyright 2016, Chromedia Far East, Inc.
  7 +#
  8 +# Licensed under the Apache License, Version 2.0 (the "License");
  9 +# you may not use this file except in compliance with the License.
  10 +# You may obtain a copy of the License at
  11 +#
  12 +# http://www.apache.org/licenses/LICENSE-2.0
  13 +#
  14 +# Unless required by applicable law or agreed to in writing, software
  15 +# distributed under the License is distributed on an "AS IS" BASIS,
  16 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17 +# See the License for the specific language governing permissions and
  18 +# limitations under the License.
  19 +#
  20 +
  21 +# Create necessary directories
  22 +inc_dir = node['cfe-nginx-php-fpm']['nginx']['inc_dir']
  23 +priv_dir = node['cfe-nginx-php-fpm']['nginx']['priv_dir']
  24 +
  25 +[ inc_dir, priv_dir ].each do |ndir|
  26 + directory ndir do
  27 + recursive true
  28 + end
  29 +end
  30 +
  31 +# The restrictions file containing default rules for virtual servers.
  32 +path_rest = "#{inc_dir}/inc_restrictions"
  33 +restfa = node['cfe-nginx-php-fpm']['nginx']['restriction_file']
  34 +template path_rest do
  35 + action :create_if_missing
  36 + mode 0644
  37 + variables(
  38 + :log_robots => restfa['log_robots'],
  39 + :log_hidden => restfa['log_hidden'],
  40 + :log_static => restfa['log_static'],
  41 + :static_types => restfa['static_types']
  42 + )
  43 +end
  44 +
  45 +# Generate config files for each virtual server.
  46 +catch_all_def_false = node['cfe-nginx-php-fpm']['nginx']['sites'].length > 1
  47 +
  48 +node['cfe-nginx-php-fpm']['nginx']['sites'].each do |site|
  49 +
  50 + if site.is_a?(Array)
  51 + site_sname = site[0]
  52 + site = site[1]
  53 + else
  54 + site_sname = site[:server_name]
  55 + end
  56 +
  57 + # Assign default values to attributes
  58 + site_index = site[:index] || nil
  59 + site_aliases = site[:aliases] || []
  60 + site_doc_root = site[:doc_root] || nil
  61 + site_alo = site[:access_log_options] || nil
  62 + site_ssl = site[:ssl] || nil
  63 + site_auth = site[:auth] || nil
  64 + site_ins = site[:init_statements] || []
  65 + site_ss1 = site[:server_statements_1] || []
  66 + site_ss2 = site[:server_statements_2] || []
  67 +
  68 + temp_catch_all = site.has_key?(:catch_all) ? site[:catch_all] : true
  69 + site_catch_all = catch_all_def_false ? false : temp_catch_all
  70 + site_types = ( site[:types] || [] ).uniq { |e| e[:type] }
  71 + site_aheads = site[:add_headers] || {
  72 + 'X-Frame-Options' => 'SAMEORIGIN',
  73 + 'X-Content-Type-Options' => 'nosniff',
  74 + 'X-XSS-Protection' => '"1; mode=block"',
  75 + 'X-Permitted-Cross-Domain-Policies' => 'none'
  76 + }
  77 +
  78 + # If TLS/SSL is enabled, configure it:
  79 + if site_ssl
  80 + if site_ssl[:letsencrypt]
  81 + le_base_dir = site_ssl[:le_base_dir] || '/etc/letsencrypt/live'
  82 + le_sub_dir = site_ssl[:le_sub_dir] || site_sname
  83 + path_crt = "#{le_base_dir}/#{le_sub_dir}/fullchain.pem"
  84 + path_key = "#{le_base_dir}/#{le_sub_dir}/privkey.pem"
  85 +
  86 + else
  87 + path_crt = "#{priv_dir}/#{site_sname}.crt"
  88 + path_key = "#{priv_dir}/#{site_sname}.key"
  89 +
  90 + if site_ssl[:cert].nil?
  91 + Chef::Log.error('Missing SSL certificate')
  92 + raise 'Missing SSL certificate'
  93 + end
  94 +
  95 + if site_ssl[:key].nil?
  96 + Chef::Log.error('Missing SSL key file')
  97 + raise 'Missing SSL key file'
  98 + end
  99 +
  100 + file path_crt do
  101 + mode 0644
  102 + content site_ssl[:cert]
  103 + sensitive true
  104 + action :create_if_missing
  105 + end
  106 +
  107 + file path_key do
  108 + mode 0644
  109 + content site_ssl[:key]
  110 + sensitive true
  111 + action :create_if_missing
  112 + end
  113 + end
  114 +
  115 + # Configure a high modulus DH param
  116 + path_dhparam = "#{priv_dir}/#{site_sname}.dhparam"
  117 + dh_modulus = site_ssl[:dh_modulus] || 4096
  118 + execute "openssl dhparam -out #{path_dhparam} #{dh_modulus}" do
  119 + not_if { ::File.exist?(path_dhparam) }
  120 + end
  121 +
  122 + else
  123 + path_crt = ''
  124 + path_key = ''
  125 + path_dhparam = ''
  126 + end
  127 +
  128 + # If basic auth is enabled, create htpasswd file
  129 + if site_auth
  130 + path_pass = "#{priv_dir}/#{site_sname}.htpasswd"
  131 + site_auth[:users].each do |auser, apass|
  132 + execute "Generate #{path_pass}" do
  133 + command "printf \"#{auser}:"\
  134 + "$( openssl passwd -apr1 '#{apass}' )"\
  135 + "\\n\" >> #{path_pass}"
  136 + action :run
  137 + sensitive true
  138 + not_if { ::File.exist?(path_pass) }
  139 + end
  140 + end
  141 + else
  142 + path_pass = ''
  143 + end
  144 +
  145 + site_includes = [path_rest]
  146 + upstreams = []
  147 + # upstreams element:
  148 + # {
  149 + # :name => 'string',
  150 + # :servers => [
  151 + # '127.0.0.1:9000',
  152 + # '/var/run/php-fpm.sock'
  153 + # ]
  154 + # }
  155 +
  156 + # Create necessary include files for each type of this site
  157 + site_types.each do |stype|
  158 + stype_subp = stype[:subpath] ? stype[:subpath].gsub(/^\/+|\/+$|\s/, '') : ''
  159 + stype_subp = stype_subp.length > 0 ? "#{stype_subp}/" : stype_subp
  160 + stype_ads = stype[:add_statements] || []
  161 + stype_ups = stype[:upstream_name] ||
  162 + "#{stype[:type]}_#{site_sname.gsub('.', '_')}"
  163 +
  164 + upstreams.push( {
  165 + :name => stype_ups,
  166 + :servers => stype[:upstream_servers] || []
  167 + } )
  168 +
  169 + case stype[:type]
  170 + # BASIC PHP SITE
  171 + when 'basic'
  172 + stype_intererror = stype.has_key?(:fastcgi_intercept_errors) ?
  173 + stype[:fastcgi_intercept_errors] : false
  174 +
  175 + template "#{inc_dir}/inc_type_basic_#{site_sname}" do
  176 + source 'inc_type_basic.erb'
  177 + mode 0644
  178 + action :create_if_missing
  179 + variables(
  180 + :index => site_index,
  181 + :subpath => stype_subp,
  182 + :upstream_name => stype_ups,
  183 + :add_statements => stype_ads,
  184 + :fastcgi_intercept_errors => stype_intererror
  185 + )
  186 + end
  187 + site_includes.push("#{inc_dir}/inc_type_basic_#{site_sname}")
  188 +
  189 + # STANDARD WORDPRESS SITE
  190 + when 'wordpress'
  191 + stype_intererror = stype.has_key?(:fastcgi_intercept_errors) ?
  192 + stype[:fastcgi_intercept_errors] : false
  193 +
  194 + template "#{inc_dir}/inc_type_wordpress_#{site_sname}" do
  195 + source 'inc_type_wordpress.erb'
  196 + mode 0644
  197 + action :create_if_missing
  198 + variables(
  199 + :index => site_index,
  200 + :subpath => stype_subp,
  201 + :upstream_name => stype_ups,
  202 + :add_statements => stype_ads,
  203 + :loginpage_statements => stype[:loginpage_statements] || [],
  204 + :fastcgi_intercept_errors => stype_intererror
  205 + )
  206 + end
  207 + site_includes.push("#{inc_dir}/inc_type_wordpress_#{site_sname}")
  208 +
  209 + # REVERSE PROXY WEBSERVER
  210 + when 'webserver'
  211 + template "#{inc_dir}/inc_type_webserver_#{site_sname}" do
  212 + source 'inc_type_webserver.erb'
  213 + mode 0644
  214 + action :create_if_missing
  215 + variables(
  216 + :subpath => stype_subp,
  217 + :upstream_name => stype_ups,
  218 + :add_statements => stype_ads
  219 + )
  220 + end
  221 + site_ins.push("map $http_upgrade $connection_upgrade {\n"\
  222 + " default upgrade;\n"\
  223 + " '' close;\n"\
  224 + "}")
  225 + site_includes.push("#{inc_dir}/inc_type_webserver_#{site_sname}")
  226 +
  227 + else
  228 + Chef::Log.error("Unknown site type: #{stype[:type]}")
  229 + raise 'Unknown site type'
  230 + end
  231 + end
  232 +
  233 + # Create the main config file for this site
  234 + template "#{node['nginx']['dir']}/sites-available/#{site_sname}" do
  235 + source 'nginx_site.conf.erb'
  236 + action :create_if_missing
  237 + mode 0644
  238 + notifies :restart, 'service[nginx]', :delayed
  239 + variables(
  240 + :server_name => site_sname,
  241 + :aliases => site_aliases,
  242 + :doc_root => site_doc_root,
  243 + :index => site_index,
  244 + :ssl => site_ssl,
  245 + :auth => site_auth,
  246 +
  247 + :access_log_options => site_alo,
  248 + :catch_all => site_catch_all,
  249 +
  250 + :path_crt => path_crt,
  251 + :path_key => path_key,
  252 + :path_pass => path_pass,
  253 + :path_dhparam => path_dhparam,
  254 +
  255 + :upstreams => upstreams,
  256 + :includes => site_includes,
  257 + :init_statements => site_ins,
  258 + :add_headers => site_aheads,
  259 + :server_statements_1 => site_ss1,
  260 + :server_statements_2 => site_ss2,
  261 +
  262 + :log_dir => node['nginx']['log_dir']
  263 + )
  264 + end
  265 +
  266 + nginx_site site_sname do
  267 + enable true
  268 + end
  269 +end
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Recipe:: php-fpm
5 5 #
... ... @@ -53,8 +53,6 @@ if node['php-fpm']['pools']
53 53 pool2['php_options'] = def_php_opts unless pool['php_options']
54 54 pool2['user'] = node['nginx']['user'] unless pool['user']
55 55 pool2['group'] = node['nginx']['user'] unless pool['group']
56   - pool2['listen'] =
57   - node['cfe-nginx-php-fpm']['php_fastcgi_socket'] unless pool['listen']
58 56
59 57 node.default['php-fpm']['pools'][key] = pool2
60 58 end
... ...
1 1 #
2   -# Author:: Earth U (<sysadmin@chromedia.com>)
  2 +# Author:: Earth U (<sysadmin @ chromedia.com>)
3 3 # Cookbook Name:: cfe-nginx-php-fpm
4 4 # Recipe:: postfix
5 5 #
... ...
1   -# Generated by Chef
2   -#
3   -
4   -# No need to enable this if PHP and Nginx share the same filesystem
5   -#fastcgi_index index.php;
6   -
7   -# You should have "cgi.fix_pathinfo = 0;" in php.ini
8   -fastcgi_split_path_info ^(.+\.php)(/.+)$;
9   -include fastcgi_params;
10   -fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
11   -
12   -<% socket = @socket[0] == '/' ? "unix:#{@socket}" : @socket -%>
13   -fastcgi_pass <%= socket %>;
templates/default/inc_restrictions.erb renamed from templates/default/restrictions.conf.erb
... ... @@ -2,18 +2,33 @@
2 2 #
3 3 # A basic PHP site config.
4 4
5   -# Pass all .php files onto a php-fpm/php-fcgi server.
  5 +<% @add_statements.each do |ads| -%>
  6 +<%= ads %>
  7 +
  8 +<% end -%>
  9 +# Pass all .php files onto a PHP-FPM fastcgi server.
6 10 #location ~ [^/]\.php(/|$) {
7 11 # Customized location directive to account for URL subpathing:
8 12 location ~ ^/<%= @subpath %>.+\.php(/|$) {
9 13 try_files $uri =404;
10 14
11   - # Enable only if implementing custom error pages
12   - #fastcgi_intercept_errors on;
  15 + # No need to enable this if PHP and Nginx share the same filesystem
  16 + #fastcgi_index index.php;
  17 +
  18 +<% if @fastcgi_intercept_errors -%>
  19 + # Enable if implementing custom error pages
  20 + fastcgi_intercept_errors on;
  21 +
  22 +<% end -%>
  23 + # You should have "cgi.fix_pathinfo = 0;" in php.ini
  24 + fastcgi_split_path_info ^(.+\.php)(/.+)$;
  25 + include fastcgi_params;
  26 + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
13 27
14   - include <%= @basic_php_fastcgi %>;
  28 + fastcgi_pass <%= @upstream_name %>;
15 29 }
16 30
17 31 location ~ ^/<%= @subpath %> {
18   - try_files $uri $uri/ /<%= @subpath %><%= @index %>?$args;
  32 +<% str = @fastcgi_intercept_errors ? '=404' : "/#{@subpath}#{@index}?$args" -%>
  33 + try_files $uri $uri/ <%= str %>;
19 34 }
... ...
... ... @@ -6,6 +6,10 @@ if ($http_user_agent ~ "MSIE") {
6 6 return 303 https://browser-update.org/update.html;
7 7 }
8 8
  9 +<% @add_statements.each do |ads| -%>
  10 +<%= ads %>
  11 +
  12 +<% end -%>
9 13 location ~ ^/<%= @subpath %> {
10 14 proxy_pass http://<%= @upstream_name %>;
11 15 proxy_http_version 1.1;
... ...
... ... @@ -6,6 +6,10 @@
6 6 # Add trailing slash to */wp-admin requests.
7 7 rewrite /<%= @subpath %>wp-admin$ $scheme://$host$uri/ permanent;
8 8
  9 +<% @add_statements.each do |ads| -%>
  10 +<%= ads %>
  11 +
  12 +<% end -%>
9 13 # Deny access to any files with a .php extension in the uploads directory
10 14 # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
11 15 location ~* /<%= @subpath %>(.+/)*(?:uploads|files)/.*\.php$ {
... ... @@ -26,7 +30,12 @@ location ~ ^/<%= @subpath %>(wp-admin|wp-login\.php) {
26 30 fastcgi_intercept_errors on;
27 31
28 32 <% end -%>
29   - include <%= @basic_php_fastcgi %>;
  33 + # You should have "cgi.fix_pathinfo = 0;" in php.ini
  34 + fastcgi_split_path_info ^(.+\.php)(/.+)$;
  35 + include fastcgi_params;
  36 + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  37 +
  38 + fastcgi_pass <%= @upstream_name %>;
30 39 }
31 40 }
32 41
... ... @@ -40,9 +49,15 @@ location ~ ^/<%= @subpath %>.+\.php(/|$) {
40 49 fastcgi_intercept_errors on;
41 50
42 51 <% end -%>
43   - include <%= @basic_php_fastcgi %>;
  52 + # You should have "cgi.fix_pathinfo = 0;" in php.ini
  53 + fastcgi_split_path_info ^(.+\.php)(/.+)$;
  54 + include fastcgi_params;
  55 + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  56 +
  57 + fastcgi_pass <%= @upstream_name %>;
44 58 }
45 59
46 60 location ~ ^/<%= @subpath %> {
47   - try_files $uri $uri/ /<%= @subpath %><%= @index %>?$args;
  61 +<% str = @fastcgi_intercept_errors ? '=404' : "/#{@subpath}#{@index}?$args" -%>
  62 + try_files $uri $uri/ <%= str %>;
48 63 }
... ...
1 1 # Generated by Chef
2 2 #
3   -<%
4   -@init_statements.each do |ins|
5   --%>
6   -<%= ins %>
7   -
8   -<%
9   -end
10 3
11   -@upstreams.each do |us|
12   --%>
  4 +<% ## -%>
  5 +<% ## Initial directives -%>
  6 +<% ## -%>
  7 +<% @init_statements.each do |ins| -%>
  8 +<%= ins %>
  9 +<% end -%>
  10 +<% ## -%>
  11 +<% ## List upstreams -%>
  12 +<% ## Example @upstreams element: -%>
  13 +<% ## { -%>
  14 +<% ## :name => 'string', -%>
  15 +<% ## :servers => [ -%>
  16 +<% ## '127.0.0.1:9000', -%>
  17 +<% ## '/var/run/php-fpm.sock' -%>
  18 +<% ## ] -%>
  19 +<% ## } -%>
  20 +<% ## -%>
  21 +<% @upstreams.each do |us| -%>
  22 +<% us_servers = us[:servers].inject([]) do |acc, serv| -%>
  23 +<% acc << ( serv[0] == '/' ? "unix:#{serv}" : serv ) -%>
  24 +<% acc -%>
  25 +<% end -%>
13 26 upstream <%= us[:name] %> {
14   - server <%= us[:ip] %>:<%= us[:port] %>;
  27 +<% us_servers.each do |serv| -%>
  28 + server <%= serv %>;
  29 +<% end -%>
15 30 }
16 31
17   -<%
18   -end
19   -
20   -servers = [@server_name]
21   -@aliases.each do |aname|
22   - servers << aname
23   -end
24   -servers.uniq!
25   -
26   -if @catch_all
27   --%>
  32 +<% end -%>
  33 +<% ## -%>
  34 +<% ## Server block for default nameless server -%>
  35 +<% ## -%>
  36 +<% if @catch_all -%>
28 37 server {
29 38 listen 80 default_server;
30 39 server_name _;
31 40 return 444;
32 41 }
33 42
34   -<%
35   -end
36   -if @ssl
37   - if @catch_all
38   --%>
  43 +<% end -%>
  44 +<% ## -%>
  45 +<% ## Main server block -%>
  46 +<% ## -%>
  47 +<% servers = @aliases.inject([@server_name]) do |acc, elem| -%>
  48 +<% acc << elem -%>
  49 +<% end -%>
  50 +<% servers.uniq! -%>
  51 +<% if @ssl -%>
  52 +<% if @catch_all -%>
39 53 server {
40 54 listen 443 default_server;
41 55 server_name _;
42 56 return 444;
43 57 }
44 58
45   -<%
46   - end
47   --%>
  59 +<% end -%>
48 60 server {
49 61 listen 80;
50 62 server_name <%= servers.join(' ') %>;
... ... @@ -57,53 +69,66 @@ server {
57 69 ssl_certificate <%= @path_crt %>;
58 70 ssl_certificate_key <%= @path_key %>;
59 71 <% unless @ssl[:self_signed] -%>
  72 +<% if @ssl[:cipher_suite] == 'modern' -%>
60 73
61 74 # Modern cipher suite:
62   - #ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK;
  75 + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK;
  76 +<% else -%>
  77 +
63 78 # Medium compatibility cipher suite (compatible with IE7 WinXP):
64 79 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;
  80 +<% end -%>
65 81 ssl_prefer_server_ciphers on;
66 82 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
67 83 ssl_session_cache shared:SSL:10m;
68 84 ssl_dhparam <%= @path_dhparam %>;
69 85 <% end -%>
70   -
71   -<%
72   - hsts = "max-age=#{@ssl[:hsts_max_age]};"
73   - hsts << 'includeSubDomains;' if @ssl[:hsts_include_subdomains]
74   --%>
  86 +<% hage = @ssl[:hsts_max_age] || '15758000' -%>
  87 +<% hsub = @ssl.has_key?(:hsts_subdomains) ? @ssl[:hsts_subdomains] : true -%>
  88 +<% hsts = "max-age=#{hage};" -%>
  89 +<% hsts << 'includeSubDomains;' if hsub -%>
75 90 add_header Strict-Transport-Security "<%= hsts %>";
76   -<%
77   -else
78   --%>
  91 +<% else -%>
79 92 server {
80 93 listen 80;
81 94
82   -<%
83   -end
84   --%>
85   - add_header X-Frame-Options SAMEORIGIN;
86   - add_header X-Content-Type-Options nosniff;
  95 +<% end -%>
  96 +<% @add_headers.each do |header, value| -%>
  97 + add_header <%= header %> <%= value %>;
  98 +<% end -%>
  99 +
  100 + # Add CSP headers here:
  101 + # [https://www.owasp.org/index.php/Content_Security_Policy]
  102 + # [http://www.html5rocks.com/en/tutorials/security/content-security-policy/]
  103 + #
  104 + #add_header Content-Security-Policy "default-src 'self'";
  105 + #add_header X-Content-Security-Policy "default-src 'self'";
87 106
88 107 server_name <%= servers.join(' ') %>;
89   -
  108 +<% if @doc_root -%>
90 109 root <%= @doc_root %>;
  110 +<% end -%>
  111 +<% if @index -%>
91 112 index <%= @index %>;
  113 +<% end -%>
92 114
93 115 <% if @auth -%>
94 116 auth_basic "<%= @auth[:msg] %>";
95 117 auth_basic_user_file <%= @path_pass %>;
96 118
97 119 <% end -%>
98   - access_log <%= node['nginx']['log_dir'] %>/<%= @server_name %>.access.log<% if @access_log_options %> <%= @access_log_options %><% end %>;
99   - error_log <%= node['nginx']['log_dir'] %>/<%= @server_name %>.error.log;
  120 + access_log <%= @log_dir %>/<%= @server_name %>.access.log<% if @access_log_options %> <%= @access_log_options %><% end %>;
  121 + error_log <%= @log_dir %>/<%= @server_name %>.error.log;
  122 +
  123 +<% @server_statements_1.each do |s1| -%>
  124 + <%= sm %>
  125 +<% end -%>
100 126
101   - include <%= @path_rest %>;
102 127 <% @includes.each do |inc| -%>
103 128 include <%= inc %>;
104 129 <% end -%>
105 130
106   -<% @custom_statements.each do |sm| -%>
107   - <%= sm %>
  131 +<% @server_statements_2.each do |s2| -%>
  132 + <%= s2 %>
108 133 <% end -%>
109 134 }
... ...