Deploying to Heroku Cloud
Warning: You are browsing the documentation for Symfony 2.x, which is no longer maintained.
Consider upgrading your projects to Symfony 7.1.
This step by step article describes how to deploy a Symfony web application to the Heroku cloud platform. Its contents are based on the original article published by Heroku.
Setting up
To set up a new Heroku website, first sign up with Heroku or sign in with your credentials. Then download and install the Heroku Toolbelt on your local computer.
You can also check out the getting Started with PHP on Heroku guide to gain more familiarity with the specifics of working with PHP applications on Heroku.
Preparing your Application
Deploying a Symfony application to Heroku doesn't require any change in its code, but it requires some minor tweaks to its configuration.
By default, the Symfony app will log into your application's app/log/
directory. This is not ideal as Heroku uses an ephemeral file system. On
Heroku, the best way to handle logging is using Logplex. And the best way to
send log data to Logplex is by writing to STDERR
or STDOUT
. Luckily,
Symfony uses the excellent Monolog library for logging. So, a new log
destination is just a change to a config file away.
Open the app/config/config_prod.yml
file, locate the
monolog/handlers/nested
section (or create it if it doesn't exist yet) and
change the value of path
from
"%kernel.logs_dir%/%kernel.environment%.log"
to "php://stderr"
:
1 2 3 4 5 6 7 8
# app/config/config_prod.yml
monolog:
# ...
handlers:
# ...
nested:
# ...
path: 'php://stderr'
Once the application is deployed, run heroku logs --tail
to keep the
stream of logs from Heroku open in your terminal.
Creating a new Application on Heroku
To create a new Heroku application that you can push to, use the CLI create
command:
1 2 3 4 5
$ heroku create
Creating mighty-hamlet-1981 in organization heroku... done, stack is cedar
http://mighty-hamlet-1981.herokuapp.com/ | git@heroku.com:mighty-hamlet-1981.git
Git remote heroku added
You are now ready to deploy the application as explained in the next section.
Deploying your Application on Heroku
Before your first deploy, you need to do just three more things, which are explained below:
1) Create a Procfile
By default, Heroku will launch an Apache web server together with PHP to serve applications. However, two special circumstances apply to Symfony applications:
- The document root is in the
web/
directory and not in the root directory of the application; - The Composer
bin-dir
, where vendor binaries (and thus Heroku's own boot scripts) are placed, isbin/
, and not the defaultvendor/bin
.
Note
Vendor binaries are usually installed to vendor/bin
by Composer, but
sometimes (e.g. when running a Symfony Standard Edition project!), the
location will be different. If in doubt, you can always run
composer config bin-dir
to figure out the right location.
Create a new file called Procfile
(without any extension) at the root
directory of the application and add just the following content:
1
web: bin/heroku-php-apache2 web/
Note
If you prefer to use Nginx, which is also available on Heroku, you can create a configuration file for it and point to it from your Procfile as described in the Heroku documentation:
1
web: bin/heroku-php-nginx -C nginx_app.conf web/
If you prefer working on the command console, execute the following commands to
create the Procfile
file and to add it to the repository:
1 2 3 4 5
$ echo "web: bin/heroku-php-apache2 web/" > Procfile
$ git add .
$ git commit -m "Procfile for Apache and PHP"
[master 35075db] Procfile for Apache and PHP
1 file changed, 1 insertion(+)
2) Set the Environment to prod
During a deployment, Heroku runs composer install --no-dev
to install all the
dependencies your application requires. However, typical post-install-commands
in composer.json
, e.g. to install assets or clear (or pre-warm) caches, run
using Symfony's dev
environment by default.
This is clearly not what you want - the app runs in "production" (even if you
use it just for an experiment, or as a staging environment), and so any build
steps should use the same prod
environment as well.
Thankfully, the solution to this problem is very simple: Symfony will pick up an
environment variable named SYMFONY_ENV
and use that environment if nothing
else is explicitly set. As Heroku exposes all config vars as environment
variables, you can issue a single command to prepare your app for a deployment:
1
$ heroku config:set SYMFONY_ENV=prod
Caution
Be aware that dependencies from composer.json
listed in the require-dev
section are never installed during a deploy on Heroku. This may cause problems
if your Symfony environment relies on such packages. The solution is to move these
packages from require-dev
to the require
section.
3) Push your Code to Heroku
Next up, it's finally time to deploy your application to Heroku. If you are doing this for the very first time, you may see a message such as the following:
1 2 3
The authenticity of host 'heroku.com (50.19.85.132)' can't be established.
RSA key fingerprint is 8b:48:5e:67:0e:c9:16:47:32:f2:87:0c:1f:c8:60:ad.
Are you sure you want to continue connecting (yes/no)?
In this case, you need to confirm by typing yes
and hitting <Enter>
key
- ideally after you've verified that the RSA key fingerprint is correct.
Then, deploy your application executing this command:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
$ git push heroku master
Initializing repository, done.
Counting objects: 130, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (107/107), done.
Writing objects: 100% (130/130), 70.88 KiB | 0 bytes/s, done.
Total 130 (delta 17), reused 0 (delta 0)
-----> PHP app detected
-----> Setting up runtime environment...
- PHP 5.5.12
- Apache 2.4.9
- Nginx 1.4.6
-----> Installing PHP extensions:
- opcache (automatic; bundled, using 'ext-opcache.ini')
-----> Installing dependencies...
Composer version 64ac32fca9e64eb38e50abfadc6eb6f2d0470039 2014-05-24 20:57:50
Loading composer repositories with package information
Installing dependencies from lock file
- ...
Generating optimized autoload files
Creating the "app/config/parameters.yml" file
Clearing the cache for the dev environment with debug true
Installing assets using the hard copy option
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution
-----> Building runtime environment...
-----> Discovering process types
Procfile declares types -> web
-----> Compressing... done, 61.5MB
-----> Launching... done, v3
http://mighty-hamlet-1981.herokuapp.com/ deployed to Heroku
To git@heroku.com:mighty-hamlet-1981.git
* [new branch] master -> master
And that's it! If you now open your browser, either by manually pointing
it to the URL heroku create
gave you, or by using the Heroku Toolbelt, the
application will respond:
1 2
$ heroku open
Opening mighty-hamlet-1981... done
You should be seeing your Symfony application in your browser.
Caution
If you take your first steps on Heroku using a fresh installation of
the Symfony Standard Edition, you may run into a 404 page not found error.
This is because the route for /
is defined by the AcmeDemoBundle, but the
AcmeDemoBundle is only loaded in the dev environment (check out your
AppKernel
class). Try opening /app/example
from the AppBundle.
Custom Compile Steps
If you wish to execute additional custom commands during a build, you can leverage
Heroku's custom compile steps. Imagine you want to remove the dev
front controller
from your production environment on Heroku in order to avoid a potential vulnerability.
Adding a command to remove web/app_dev.php
to Composer's post-install-commands would
work, but it also removes the controller in your local development environment on each
composer install
or composer update
respectively. Instead, you can add a
custom Composer command named compile
(this key name is a Heroku convention) to the
scripts
section of your composer.json
. The listed commands hook into Heroku's deploy
process:
1 2 3 4 5 6 7
{
"scripts": {
"compile": [
"rm web/app_dev.php"
]
}
}
This is also very useful to build assets on the production system, e.g. with Assetic:
1 2 3 4 5 6 7
{
"scripts": {
"compile": [
"app/console assetic:dump"
]
}
}
Node.js Dependencies
Building assets may depend on node packages, e.g. uglifyjs
or uglifycss
for asset minification. Installing node packages during the deploy requires a node
installation. But currently, Heroku compiles your app using the PHP buildpack, which
is auto-detected by the presence of a composer.json
file, and does not include a
node installation. Because the Node.js buildpack has a higher precedence than the PHP
buildpack (see Heroku buildpacks), adding a package.json
listing your node
dependencies makes Heroku opt for the Node.js buildpack instead:
1 2 3 4 5 6 7 8 9 10
{
"name": "myApp",
"engines": {
"node": "0.12.x"
},
"dependencies": {
"uglifycss": "*",
"uglify-js": "*"
}
}
With the next deploy, Heroku compiles your app using the Node.js buildpack and
your npm packages become installed. On the other hand, your composer.json
is
now ignored. To compile your app with both buildpacks, Node.js and PHP, you need
to use both buildpacks. To override buildpack auto-detection, you
need to explicitly set the buildpack:
1 2 3 4 5 6 7 8
$ heroku buildpacks:set heroku/nodejs
Buildpack set. Next release on your-application will use heroku/nodejs.
Run git push heroku master to create a new release using this buildpack.
$ heroku buildpacks:set heroku/php --index 2
Buildpack set. Next release on your-application will use:
1. heroku/nodejs
2. heroku/php
Run git push heroku master to create a new release using these buildpacks.
With the next deploy, you can benefit from both buildpacks. This setup also enables your Heroku environment to make use of node based automatic build tools like Grunt or gulp.