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:
Heroku offers you two ways to tweak your server configuration:
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 email@example.com:symfony-2-test.git
$ cd project_name
Create your Symfony 2 App – here’s one I prepared earlier:
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.
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
echo "-----> Installing Composer dependencies"
curl --silent --max-time 60 --location "$COMPOSER_URL" > www/composer.phar
LD_LIBRARY_PATH=$BUILD_DIR/php/ext $BUILD_DIR/php/bin/php composer.phar install --prefer-source -v
echo "Please check if you have a composer.json file in the root, and that your vendor directory is not committed"
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/"
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
tail -F /app/apache/logs/error_log &
tail -F /app/apache/logs/access_log &
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.