aboutsummaryrefslogtreecommitdiffstats
path: root/posts/apache_php_fpm.md
diff options
context:
space:
mode:
Diffstat (limited to 'posts/apache_php_fpm.md')
-rw-r--r--posts/apache_php_fpm.md204
1 files changed, 204 insertions, 0 deletions
diff --git a/posts/apache_php_fpm.md b/posts/apache_php_fpm.md
new file mode 100644
index 0000000..38fb4ea
--- /dev/null
+++ b/posts/apache_php_fpm.md
@@ -0,0 +1,204 @@
+---
+title: Apache and PHP-FPM
+published: 2015-11-01
+modified: 2015-11-02
+---
+
+There is lots of crappy information out there about deploying PHP with Apache,
+or nginx. It is really hard to distill what is really a safe configuration and
+what works. Combining this with a safe TLS configuration nears the
+impossible.
+
+### PHP-FPM
+
+Configuring PHP-FPM is not that difficult, actually, one could keep the
+defaults and that will work pretty well.
+
+```
+$ sudo dnf -y install php-fpm
+```
+
+I only change the configuration not to use a socket, but listen on TCP
+instead. There are some more tweaks you can perform, but to get it working
+reasonably well that is not needed yet.
+
+```
+$ sudo sed -i "s|listen = /run/php-fpm/www.sock|listen = [::]:9000|" /etc/php-fpm.d/www.conf
+$ sudo sed -i "s/listen.allowed_clients = 127.0.0.1/listen.allowed_clients = 127.0.0.1,::1/" /etc/php-fpm.d/www.conf
+```
+
+You possibly have to update the `listen.allowed_clients` if you use a
+separate VM or container for the web server.
+
+Do not forget to enable and start PHP-FPM.
+
+```
+$ sudo systemctl enable php-fpm
+$ sudo systemctl start php-fpm
+```
+
+That should be all for PHP-FPM.
+
+### Apache
+
+We start simple, with a HTTP server serving a PHP application using PHP-FPM.
+
+```
+<VirtualHost www.example.org:80>
+ ServerName www.example.org
+
+ ErrorLog logs/www.example.org_error_log
+ TransferLog logs/www.example.org_access_log
+ CustomLog logs/www.example.org_combined_log combined
+ LogLevel warn
+
+ DocumentRoot /usr/share/my-php-app/web
+
+ <Directory "/usr/share/my-php-app/web">
+ Options -MultiViews
+
+ #Require local
+ Require all granted
+
+ AllowOverride none
+ </Directory>
+
+ # Pass through the "Authorization" header
+ SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
+
+ # Some request are handled by Apache directly
+ ProxyPass "/css/" !
+ ProxyPass "/img/" !
+ ProxyPass "/js/" !
+ ProxyPassMatch "^/robots.txt$" !
+ ProxyPassMatch "^/favicon.ico$" !
+
+ # The rest goes to PHP-FPM...
+ ProxyPass "/" fcgi://[::1]:9000/usr/share/php-my-app/web/index.php/
+</VirtualHost>
+```
+
+### Apache TLS
+Basically, this means that we remove the current contents of the
+`VirtualHost` block and use it to rewrite to HTTPS instead and move
+the PHP-FPM stuff to the new TLS `VirtualHost`.
+
+```
+<VirtualHost www.example.org:80>
+ ServerName www.example.org
+
+ ErrorLog logs/www.example.org_error_log
+ TransferLog logs/www.example.org_access_log
+ CustomLog logs/www.example.org_combined_log combined
+ LogLevel warn
+
+ RewriteEngine On
+ RewriteCond %{HTTPS} !=on
+ RewriteCond %{ENV:HTTPS} !=on
+ RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
+</VirtualHost>
+```
+Now, we create a new TLS `VirtualHost` that contains the stuff from
+the previous section and some extra TLS configuration options.
+
+```
+<VirtualHost www.example.org:443>
+ ServerName www.example.org
+
+ ErrorLog logs/www.example.org_ssl_error_log
+ TransferLog logs/www.example.org_ssl_access_log
+ CustomLog logs/www.example.org_ssl_combined_log combined
+ LogLevel warn
+
+ DocumentRoot /usr/share/php-my-app/web
+
+ SSLEngine on
+ SSLCertificateFile /etc/pki/tls/certs/www.example.org.crt
+ #SSLCertificateChainFile /etc/pki/tls/certs/www.example.org-chain.crt
+ SSLCertificateKeyFile /etc/pki/tls/private/www.example.org.key
+
+ SSLProtocol all -SSLv3 -TLSv1
+ SSLCipherSuite 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
+ SSLHonorCipherOrder on
+ SSLCompression off
+
+ # OCSP Stapling, only in httpd 2.3.3 and later
+ SSLUseStapling on
+ SSLStaplingResponderTimeout 5
+ SSLStaplingReturnResponderErrors off
+
+ # HSTS (mod_headers is required) (15768000 seconds = 6 months)
+ Header always set Strict-Transport-Security "max-age=15768000"
+
+ <Directory "/usr/share/php-my-app/web">
+ Options -MultiViews
+
+ Require all granted
+ AllowOverride none
+ </Directory>
+
+ # Pass through the "Authorization" header
+ SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
+
+ # Some request are handled by Apache directly
+ ProxyPass "/css/" !
+ ProxyPass "/img/" !
+ ProxyPass "/js/" !
+ ProxyPassMatch "^/robots.txt$" !
+ ProxyPassMatch "^/favicon.ico$" !
+
+ # The rest goes to PHP-FPM...
+ ProxyPass "/" fcgi://[::1]:9000/usr/share/php-my-app/web/index.php/
+</VirtualHost>
+```
+
+Now we still need to generate the key and certificate and optionally have them
+signed by some CA. The following commands make this very easy:
+
+```
+# Generate the private key
+$ sudo openssl genrsa -out /etc/pki/tls/private/www.example.org.key 2048
+$ sudo chmod 600 /etc/pki/tls/private/www.example.org.key
+
+# Create the CSR (optionally, send this to CA to have signed)
+$ sudo openssl req -subj "/CN=www.example.org" -sha256 -new -key /etc/pki/tls/private/www.example.org.key -out www.example.org.csr
+
+# Create the (self signed) certificate and install it
+$ sudo openssl req -subj "/CN=www.example.org" -sha256 -new -x509 -key /etc/pki/tls/private/www.example.org.key -out /etc/pki/tls/certs/www.example.org.crt
+```
+
+If you want to have the certificate signed by a CA, use the CSR generated
+above and send it to the CA. Once you get a certificate back, overwrite the
+self signed certificate in `/etc/pki/tls/certs/www.example.org.crt`
+and make sure to also configure the `SSLCertificateChainFile`.
+
+Next you can just place the two `VirtualHost` sections above in one
+file, put it in `/etc/httpd/conf.d/www.example.org.conf` and enable
+and start Apache.
+
+```
+$ sudo systemctl enable httpd
+$ sudo systemctl start httpd
+```
+
+### Unanswered Questions
+
+This stuff is so complex that there are still some issues that I do not know
+how to solve. Hopefully this list will become smaller over time.
+
+- The URL passed to PHP-FPM is still "URL encoded", for example `%20` is not
+ converted back to `SPACE`;
+- Should we actually have the `RewriteCond` rules in the HTTP `VirtualHost`
+ section? It MUST always be rewritten?
+
+### Resources
+
+These resources are a MUST. Make sure to take note of everything that is
+mentioned there! Do not trust what I write here without thinking for yourself
+and making sure you understand everything.
+
+- [PHP: The Right Way](http://www.phptherightway.com/#servers_and_deployment) (Servers and Deployment)
+- [Mozilla SSL Configuration Generator](https://mozilla.github.io/server-side-tls/ssl-config-generator/)
+- [SSL Server Test](https://www.ssllabs.com/ssltest/) (Qualys)
+- [SSL Decoder](https://ssldecoder.org/) (Remy van Elst)
+- [Earlier blog post on HTTPS](https.html)