Nginx and PHP-FPM, bash script for deleting old vhost’s

If you’re using my bash script to create new nginx vhosts (with php-fpm support) you may also require an easy way to remove old vhosts you no longer need (along with all the configs associated with the vhost). I’ve put together this very simple bash script to automate the process:

#!/bin/bash
# @author: Seb Dangerfield
# http://www.sebdangerfield.me.uk/ 
# Created:   02/12/2012
 
# Modify the following to match your system
NGINX_CONFIG='/etc/nginx/sites-available'
NGINX_SITES_ENABLED='/etc/nginx/sites-enabled'
PHP_INI_DIR='/etc/php5/fpm/pool.d'
NGINX_INIT='/etc/init.d/nginx'
PHP_FPM_INIT='/etc/init.d/php5-fpm'
# --------------END 
SED=`which sed`
CURRENT_DIR=`dirname $0`
 
if [ -z $1 ]; then
	echo "No domain name given"
	exit 1
fi
DOMAIN=$1
 
# check the domain is valid!
PATTERN="^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$";
if [[ "$DOMAIN" =~ $PATTERN ]]; then
	DOMAIN=`echo $DOMAIN | tr '[A-Z]' '[a-z]'`
	echo "Removing vhost for:" $DOMAIN
else
	echo "invalid domain name"
	exit 1 
fi
 
echo "What is the username for this site?"
read USERNAME
HOME_DIR=$USERNAME
 
# Remove the user and their home directory
userdel -rf $USERNAME
# Delete the users group from the system
groupdel $USERNAME
 
# Delete the virtual host config
rm -f $NGINX_CONFIG/$DOMAIN.conf
rm -f $NGINX_SITES_ENABLED/$DOMAIN.conf
 
# Delete the php-fpm config
FPMCONF="$PHP_INI_DIR/$DOMAIN.pool.conf"
rm -f $FPMCONF
 
$NGINX_INIT reload
$PHP_FPM_INIT restart
 
echo -e "\nSite removed for $DOMAIN"

How to use it:

Please note that because it deletes the users home directory all users files will be deleted, so if you want to keep a copy of the files as a backup do this before running the script.

Simply copy the script from above into a new file called something like remove_php_site.sh. If your not using Debian/Ubuntu or have modified the default directories and users for PHP and Nginx then you will need to change the paths and Nginx user at the top of the script to match your system. You will need to change the permissions on the remove_php_site.sh file to make it executable (if it isn’t already):

chmod u+x remove_php_site.sh

Then run the remove_php_site.sh script passing to it the domain name as the only parameter.

./remove_php_site.sh example.com

It will then prompt you for the linux username used for this site and once that has been provided it will delete all the files related to that site and restart Nginx and PHP-FPM.

NSS error -8023 using AWS SDK for PHP

Please note this fix should also work on Fedora, CentOS and Redhat linux distros if you are seeing the NSS error -8023 when using CURL and PHP.

At work we came up against this odd error message from Amazon Web Services(AWS) SDK for PHP when using the SDK in a forked process on the AWS built AMI:

PHP Fatal error:  Uncaught exception 'cURL_Exception' with message 'cURL resource: Resource id #50; cURL error: SSL connect error (cURL error code 35). See http://curl.haxx.se/libcurl/c/libcurl-errors.html for an explanation of error codes.' in /usr/share/pear/AWSSDKforPHP/lib/requestcore/requestcore.class.php:829

Stack trace:
#0 /usr/share/pear/AWSSDKforPHP/sdk.class.php(1035): RequestCore->send_request()
#1 /usr/share/pear/AWSSDKforPHP/services/swf.class.php(1305): CFRuntime->authenticate('TerminateWorkfl...', Array)
#2 ....php(189): AmazonSWF->terminate_workflow_execution(Array)
#3 ....php(83): daemon->checkSWFExecutions()
#4 ....php(350): daemon->run()
#5 {main}
  thrown in /usr/share/pear/AWSSDKforPHP/lib/requestcore/requestcore.class.php on line 829

Now, cURL error 35 means “A problem occurred somewhere in the SSL/TLS handshake. You really want the error buffer and read the message there as it pinpoints the problem slightly more. Could be certificates (file formats, paths, permissions), passwords, and others.” which is a bit vague and didn’t really help. After setting the CURLOPT_VERBOSE flag in the AWS SDK for PHP we were able to see the real error message:

NSS error -8023

Continue reading

Nginx and PHP-FPM, bash script for creating new vhost’s under separate fpm pools

Using worker pools in PHP-FPM can allow you to easily separate out and isolate virtual hosts that make use of PHP. PHP-FPM allows you to run multiple pools of processes all spawned from the master one and each pool can run as a different user and/or group. Each pool can be further isolated by running in a chroot environment and by overriding the default php.ini values on a per pool basis.

Running PHP for each vhost under a different user/group can help to stop a vulnerability in one site potentially exposing another vhost, it can also stop one malicious owner of a vhost from been able to use PHP to access the files of another site owned by someone else on the same server (in a shared hosting environment).

The process of setting up the web server config and a new PHP-FPM pool for each new vhost on a server can become a rather time consuming and boring process. However as this process follows a fairly standard set of steps it can be easily scripted.

Continue reading

“501 5.0.0 Invalid domain name” trying to send email

Had this error appear today when trying to send an email using Swift Mailer (on an nginx powered box using PHP FastCGI). It turned out to be caused by the CGI parameter SERVER_NAME, the site was running on a wildcard domain under nginx and as a result the SERVER_NAME param contained the wildcard symbol. (e.g. *.test.example.com) However the SMTP server didn’t like this (and quite rightly so), this is where the Invalid domain name bit comes from.

Adding the following line to my nginx server config for that virtual host fixed the problem.

fastcgi_param SERVER_NAME $host;

The above line just sets the SERVER_NAME parameter to be the same as the host header for the current request. The only problem with this is if the host header in the request is not set then this value can still fall back to the original $server_name one (see nginx manual for more info). However this seemed to fix the problem for me, and I don’t think it should cause any problems as the site is not available directly via an IP address, so host header will always be required.

Reading User Data and Metadata on EC2

When creating a new Linux EC2 instance on AWS you’re able to pass extra data to the server to be used late in the boot sequence. This can be in the form of a simple bash script, or the URL(s) of a number of scripts. Or the data could simple by a list of parameters you need that instance to know. Full details on the sorts of things you can pass via the “User Data” parameter can be found on Ubuntu Website or details for the AWS build AMI can be found here. (Not all images can be passed User Data, but the standard ones by Amazon can be along with a range of community ones.)

Now if you pass a script or the URL to a script as User Data to your new instance then this will get run for you, and you don’t need to worry about it. However if you pass it a list of parameters (for example you may pass it the Endpoint URI for your RDS instance so the DB settings for your apps can be set up correctly) you need to know how to read the User Data. Along with reading the User Data you may also want to read in Metadata about your new instance, such as its AMI-ID or the public hostname of your instance. Reading the Metadata is done by querying a simple API:

The base URI of all the query’s is: http://169.254.169.254/

Continue reading

Nginx Configuration for Symfony

Recently when setting up a Symfony project on an Nginx powered server I found the Example configuration script found on the Nginx wiki for Symfony didn’t fully work as expected.

  1. If you added a slash to the end of the url when requesting backend.php or frontend_dev.php or similar caused the page not be found, even though under Apache this works fine and goes to the correct place. Which seemed to be caused by the script_name server param.
  2. GET parameters were not getting passed to Symfony. Caused by the arguments been removed during the try_files request.

So I modified the example config to produce the following, which as far as I can tell works exactly the same as the default .htaccess file does under Apache.

Continue reading

Using a non-integer primary key with Symfony’s Admin Generator

When Symfony creates an Admin module automatically its default routing setup only allows it to work with an integer based primary key. This means you can’t use a unique varchar column as your primary key, for example. There is however an easy way to solve this and tell Symfony to match other characters in its routing module. All you need to do is update your routing.yml file adding the requirements parameter like so:

user_languages:
 class: sfPropelRouteCollection    
 options:
   model:                user_languages
   module:               user_languages
   prefix_path:          /languages
   column:               iso
   with_wildcard_routes: true
 requirements:  { id: "[a-zA-Z]+" }

The above pattern will match any number of characters, and won’t worry about the case. However you could make this pattern match anything you wanted, the string must be a valid regular expression pattern the same as you would use for preg_match and similar.

Update to sdInteractiveChartPlugin for Symfony PHP

sdInteractiveChartPlugin has been updated to version to 0.3 to fix two little issues:

  • Symfonys sfOutputEscaperArrayDecorator objects can now be passed directly to the charting plugin and it will correctly format the values from the object.
  • Added support for automatically loading the Javascript files over https if the page request is over SSL.

More info and the download for the plugin can be found here:

http://www.symfony-project.org/plugins/sdInteractiveChartPlugin/0_3_0