Feb 13th 2013
Posted by Traffic

Deploying Symfony 2 Apps on Heroku

We use Heroku to host some of our web apps – most frequently Facebook Apps. Heroku makes it very easy to scale your apps and it’s also very easy to setup a new project and deploy changes using Git. Facebook Apps tend to have a relatively short lifespan, and can get spikes in traffic that are unpredictable, so it’s a pretty good fit.

I usually use Silex for Facebook app development because it provides just the right amount of infrastructure to support what are generally quite simple sites with only 3 or 4 pages. Recently we needed to deploy a project on Heroku that used Symfony 2 and needed to do some image manipulation – neither of which will work straight out of the box on Heroku.

Outside of the functionality provided by a vanilla Heroku PHP instance, I needed to configure Heroku to do the following for every new instance:

  • Load Dependencies using composer
  • Enable manipulation of images (I chose to use ImageMagick for this using this bundle)
  • Enable APC caching
  • Change the web root

Heroku offers you two ways to tweak your server configuration:

  • You can use a Procfile to run some commands on deployment of an instance
  • You can use a Custom Build Pack to customise the server software and configuration before it’s deployed

Henri Bergius wrote this awesome blog post on creating a Heroku Custom Build Pack that installs dependencies using composer.

I used his build pack as a base, and added a few tweaks to get it to work with Symfony 2:

Create a new heroku project:

$ heroku apps:create project_name
$ git clone git@heroku.com:symfony-2-test.git
$ cd project_name

Create your Symfony 2 App – here’s one I prepared earlier:
https://github.com/bentraffic/symfony-2-test
To use my demo for your base you can type the following to pull the:
$ git pull git://github.com/bentraffic/symfony-2-test.git

Cool, now to add a custom build pack! I forked Henri Berguis’s bundle so I could make a couple of custom changes. so let’s add that custom buildpack to heroku (you do this by specifying a git repository).

$ heroku config:add BUILDPACK_URL=git://github.com/bentraffic/heroku-buildpack-php.git

This will do all the things that the PHP buildpack normally does (e.g. install php, apache, etc.) but additionally it will install your composer dependencies if you look at the compile bash script in the build pack you can see what’s going on.
https://github.com/bentraffic/heroku-buildpack-php/blob/master/bin/compile
Here  we look if we have a composer.json file, and if so we download a copy of composer and run composer install.
# check if we have Composer dependencies and vendors are not bundled
if [ -f www/composer.json ] && [ ! -d www/vendor ]; then
GIT_DIR_ORIG=$GIT_DIR
unset GIT_DIR
echo "-----> Installing Composer dependencies"
COMPOSER_URL="http://getcomposer.org/composer.phar"
curl --silent --max-time 60 --location "$COMPOSER_URL" > www/composer.phar
cd www
LD_LIBRARY_PATH=$BUILD_DIR/php/ext $BUILD_DIR/php/bin/php composer.phar install --prefer-source -v
cd $BUILD_DIR
rm www/composer.phar
export GIT_DIR=$GIT_DIR_ORGI
else
echo "Please check if you have a composer.json file in the root, and that your vendor directory is not committed"
fi

In order to get Symfony 2 dependencies to install using composer, I needed to add PHP to the PATH, so I added this line:

export set PATH=$PATH:$BUILD_DIR/php/bin

The next thing to do is to get the required PHP extensions installed – Symfony 2 works better with APC installed, and we need ImageMagick to do image manipulations. I got these from here.

I added them to ext/ in the root of my project. Next, I needed to tell PHP where to look for those extensions – to do this I edited the php.ini file in our buildpack, adding the following lines:

extension_dir = "/app/www/ext/"
extension=imagick.so
extension=apc.so

The last thing I needed to do was to change the webroot. You can do this by adding a file called “Procfile” to your web root. This can specify one or more commands to run on deployment of your instance.

The contents of the Procfile is as folows – this specifies a shell script to be run on deployment of an instance
web:    sh www/conf/web-boot.sh

The shell script we are running appends the contents of our vhost config file to the apache config, sets up error and log files and launches apache:

#append our custom vhost config to the httpd.conf file used by appache
echo "Include /app/www/conf/httpd/*.conf" >> /app/apache/conf/httpd.conf

#setup error log files and access log files
touch /app/apache/logs/error_log
touch /app/apache/logs/access_log
tail -F /app/apache/logs/error_log &
tail -F /app/apache/logs/access_log &
export LD_LIBRARY_PATH=/app/php/ext
export PHP_INI_SCAN_DIR=/app/www
echo “Launching apache”
exec /app/apache/bin/httpd -DNO_DETACH
#set file permissions for web dir
exec chmod -R 775 /app/www/web

And there we have it, a working symfony 2 project on Heroku.
http://symfony-2-test.herokuapp.com/