When working on my small home project on Symfony2, I needed to deploy it on staging for testing API from the outside. Sure, you need some hosting for this purpose: either have it already or buy it. Yet there is an alternative — the cloud services where you can host your site for free but with limited resources. There are a lot of such services now and they are competing with each other. Somehow I decided to try Heroku. I heard about it a long time ago and at that point it crossed my mind. I didn’t look on other services, this time I just wanted to try my luck with Heroku. Fortunately, Heroku still has a free web hosting option so I started to search all the information needed for Symfony2 application deployment.
Here’re some helpful links I came across:
- Deploying to Heroku Cloud (from Symfony Cookbook)
- Getting Started with PHP on Heroku
- Getting Started with Symfony2 on Heroku
A lot of things from these articles will be repeated in this post. But there are some missed or not fully disclosed points there, and I decided to fill this gap.
Preparing
For a start you need to create a Heroku account.
Then download Heroku Toolbelt for your platform. This tool allows to manage your applications via console. For example, to install Heroku on Debian/Ubuntu you only need to run this command:
$ wget-qO- https://toolbelt.heroku.com/install-ubuntu.sh |sh
Now you need to login into Heroku from console:
. Enter an email and password from your account.Enter your Heroku credentials. Email: test@examle.com Password (typing will be hidden): Authentication successful.
Run from you terminal
to check available commands for Heroku console. The list is not full, because aliases aren’t shown there. For example, command is the alias for .Creating a Heroku Application
You can create a new Heroku application in two ways:
- from console on your work computer
- from web-interface Heroku Dashboard
Creating an application from console
Heroku deploys PHP projects via Composer, so you need to have a valid composer.json and composer.lock in your project. If you just run
without any parameters, a new application will be created in your cloud. It doesn’t do anything now and should be configured. It will have a random name, for example . After application is created, you can change its name (if new name is available): . command is the alias for . However, it’s better to set a name when you create an application , but it should be available. You can run in a different directory and it will simply create a new application in your cloud. But we want to deploy our project, so this command should be run from the project directory where Git is initialized. In addition for creating the project checks if Git is initialized in a current directory, and, if so, it adds its remote repository.$ mkdir my-abracadabra $ cd my-abracadabra/ $ git init Initialized empty Git repository in/home/fresh/Desktop/my-abracadabra/.git/ $ heroku create my-abracadabra Creating my-abracadabra... done, stack is cedar-14 https://my-abracadabra.herokuapp.com/| https://git.heroku.com/my-abracadabra.git Git remote heroku added $ git remote-v heroku https://git.heroku.com/my-abracadabra.git (fetch) heroku https://git.heroku.com/my-abracadabra.git (push)
So you have two options: either you create a new project, initialize Git there and connect to Heroku, or you connect Heroku to the working project with initialized Git. Another case is when you’ve created an application on one computer and want to set it up at another. Or you’ve created an application through the web interface and just want to set it up at your terminal. In this case you just need to add remote Heroku repository to your local project. Address of repository may look like this
. For example, if the project is called my-abracadabra, then you need to execute:$ git remote add heroku https://git.heroku.com/my-abracadabra.git
or
$ heroku git:remote -a my-abracadabra
Creating an application from your dashboard
On this page https://dashboard.heroku.com/new you simply enter a valid name and select a server location to create a new application.
Application has been created, now you can continue configuring it via web interface.
Configuration of processes
In the root directory of the project you need to create a file called
and write the following text there:web: vendor/bin/heroku-php-apache2 web/
When deploying this command will tell Heroku that it should create a web-worker which will listen to HTTP-requests and the root directory of the site (in this case, Symfony) is located in
directory. Also in this command tell to run PHP on Apache web server. If you need Nginx, use this command:web: vendor/bin/heroku-php-nginx
You can also try to run the project on HHVM:
web: vendor/bin/heroku-hhvm-nginx
web: vendor/bin/heroku-hhvm-apache2
You can add another workers in this file, e.g. background worker for the cron tasks.
Preparing the environment for Symfony
It’s also important to know that during the deployment of PHP application Heroku runs composer with the following parameters:
$ composer install--no-dev--prefer-dist--optimize-autoloader--no-interaction
It means that everything that you have added to the
section of your composer.json file will not be installed.By default all console commands run in the dev environment. We need to switch Symfony in the production mode before composer runs its scripts because few important commands required to set up the application (clear cache, dump assets) are run there. You can do it via environment variable
and if it’s set, its value will indicate the environment for Symfony. We do it as follows:$ heroku config:set SYMFONY_ENV=prod
Command must be run only once before the first deployment.
And now deploy
Deployment on Heroku is done by pushing commits to the remote repository.
$ git push heroku master
After running this command in the console, you will see the whole process of deployment. If deployment was successful, then use command
to open your application in the browser. By default, the address of your application will be a subdomain to the herokuapp.com (for example, https://my-abracadabra.herokuapp.com/) but you can set up it to use your own domain.View logs
To view the logs from the console, you need to change a production config of Symfony a bit. In file
you have to replace with .monolog: handlers: nested: path: "php://stderr"
Now logs can be viewed with:
$ heroku logs --num10
or you can monitor logs online:
$ heroku logs --tail
Console commands for running Symfony2 on Heroku
To get access to the bash while you deploy Symfony2 on Heroku Cloud, run the command
.Then you can run available commands from the application:
$ heroku run bash Running `bash` attached to terminal... up, run.1516 ~ $ app/console doctrine:schema:validate [Mapping] OK - The mapping files are correct. [Database] FAIL - The database schema is not insync with the current mapping file. ~ $ app/console doctrine:schema:create ATTENTION: This operation should not be executed in a production environment. Creating database schema... Database schema created successfully! ~ $ exitexit
You don’t need to specify the environment via
, because it was set up through the environment variable.You can also run interactive PHP shell from the terminal:
$ heroku run "php -a" Running `php -a` attached to terminal... up, run.3436 Interactive shell php >echo"Hello World"; Hello World php >exit
Don’t forget to type
.Manage configuration settings
When we run
on the local machine and there are new parameters in the file that have not been installed locally yet, Symfony console will ask you to add these parameters in interactive mode. It can’t be done on Heroku, since composer is run with the option . Therefore, we need to set these parameters somehow. The most convenient way that offers Symfony and Heroku is to write them into environment variables, and PHP will read them out. You can do it with the following command:$ heroku config:set DATABASE_PASSWORD=secret_password Setting config vars and restarting my-abracadabra... done, v32 DATABASE_PASSWORD: secret_password $ heroku config:set DATABASE_USER=secret_user Setting config vars and restarting my-abracadabra... done, v33 DATABASE_USER: secret_user
To check what you have set, use:
$ heroku config === my-abracadabra Config Vars DATABASE_PASSWORD: secret_password DATABASE_USER: secret_user
You can also add, edit and delete parameters from your dashboard.
It can also be nicely done in the Incenteev/ParameterHandler. It is registered in Symfony out of the box, we don’t need to do anything, simply use its feature to map environment parameters into parameters of application.
file by using script{"extra":{"incenteev-parameters":{"env-map":{"my_first_param":"MY_FIRST_PARAM","my_second_param":"MY_SECOND_PARAM"}}}}
Find the
section in the composer.json file and change it to this:{"extra":{"symfony-app-dir":"app","symfony-web-dir":"web","incenteev-parameters":{"file":"app/config/parameters.yml","env-map":{"database_name":"SYMFONY__DATABASE_NAME","database_user":"SYMFONY__DATABASE_USER","database_host":"SYMFONY__DATABASE_HOST","database_password":"SYMFONY__DATABASE_PASSWORD"}}}}
Now we need to set the environment variables. In this case we need to specify the parameters of database.
Connecting a database to the project
To find a database (and any other tool you need) look on the add-ons page https://addons.heroku.com/. For each add-on you can find installation instructions.
Install PostgreSQL:
$ heroku addons:add heroku-postgresql Adding heroku-postgresql on my-abracadabra... done, v9 (free) Attached as HEROKU_POSTGRESQL_IVORY_URL Database has been created and is available ! This database is empty. If upgrading, you can transfer ! data from another database with pgbackups:restore. Use `heroku addons:docs heroku-postgresql` to view documentation.
MySQL is installed via add-on ClearDB MySQL Database:
$ heroku addons:add cleardb Adding cleardb on my-abracadabra... done, v10 (free) Use `heroku addons:docs cleardb` to view documentation.
When connecting add-on to the application, its connection settings are also stored in the environment variables:
$ heroku config === my-abracadabra Config Vars CLEARDB_DATABASE_URL: mysql://b9153ad7c7a263:a7f8d514@us-cdbr-iron-east-01.cleardb.net/heroku_ab3bbc34931b570?reconnect=true HEROKU_POSTGRESQL_IVORY_URL: postgres://ylcarfkdjbxouy:tEDQdicyUIcnCk7-xNn9SZZCHZ@ec2-107-20-229-112.compute-1.amazonaws.com:5432/db7sm6in86mtir
If we parse this URL, we'll get a host, a database name, a user and a password. To make this thing done automatically while deploy we have to write a script for composer and subscribe it to the event
. To do this, somewhere in the project (e.g. in the namespace ) create a new class:If we parse this URL, we’ll get a host, a database name, a user and a password. To do it automatically when deploying we have to write a script for composer and subscribe it to the event
. To do this somewhere in the project (e.g. in the namespace ) create a new class:<?phpnamespace AppBundle\Composer; use Composer\Script\Event; class HerokuEnvironment {/** * Populate Heroku environment * * @param Event $event Event */public static function populateEnvironment(Event $event){$url=getenv('CLEARDB_DATABASE_URL');// If MySQL is chosen// $url = getenv('HEROKU_POSTGRESQL_IVORY_URL'); If PostgreSQL is chosen if($url){$url=parse_url($url);putenv("SYMFONY__DATABASE_HOST={$url['host']}");putenv("SYMFONY__DATABASE_USER={$url['user']}");putenv("SYMFONY__DATABASE_PASSWORD={$url['pass']}"); $db=substr($url['path'],1);putenv("SYMFONY__DATABASE_NAME={$db}");} $io=$event->getIO();$io->write('CLEARDB_DATABASE_URL='.getenv('CLEARDB_DATABASE_URL'));}}
Now add this script in composer.json:
{"scripts":{"pre-install-cmd":["AppBundle\\Composer\\HerokuEnvironment::populateEnvironment"]}}
Now during our first deployment, composer will set database settings by itself.
Free version of PostgeSQL is limited to 10k records. Free ClearDB is limited to 5 megabytes.
Additional settings in composer.json
In the composer.json file in the
section you can pass additional environment settings for Heroku. For example:{"extra":{"heroku":{"framework":"symfony2","document-root":"web","php-config":["date.timezone=Europe/Kiev","display_errors=off","short_open_tag=off"]}}}
Script php
will show what you still need to set up for Symfony to work properly. PHP settings can be set in section. Also Symfony requires some PHP modules to be enabled. To tell Heroku to include them when a web-worker is created, you need to list them in the require section of composer.json.{"require":{"ext-intl":"*","ext-mbstring":"*"}}
Notifications about successful deployment
There is an add-on Deploy Hooks which allows to configure notifications sending after successful deployment:
$ heroku addons:add deployhooks:email \ >--recipient=me@example.com \ >--subject="My abracadabra application has been deployed" \ >--body="{{user}} has deployed my abracadabra to Heroku" Adding deployhooks:email on my-abracadabra... done, v11 (free) Use `heroku addons:docs deployhooks` to view documentation.
You can also configure other notification channels.
Connection with GitHub
If you keep your repository on Github, you can use your Heroku dashboard to connect it to automatic deployments after each commit to the master branch (or any other branch).
In this case, you will need to push only to GitHub. Heroku will catch it and redeploy production.
If you do not want to set up automatic deployment, then you have to push twice. Once to send the changes to your remote repository, the second time to send the changes to Heroku repository to create a new deployment:
$ git push origin master $ git push heroku master
File App.json And Symfony2 Deploying To Heroku Open Source Projects In One Click
Another sweet feature of Heroku. For example, if you are developing an open source project in your public repository on GitHub and want to allow users to see the application in action without the need to download and deploy locally. You can add all the necessary configs for deployment in your repository, add a standard Heroku button and deploy it in one click.
Configuration file for Heroku is called app.json. It should be put in the root directory of your project. Details about all configs options can be found here. Here’s an example file:
{"name":"Name will be shown during the creation of a new app","description":"Description will be shown during the creation of a new app","keywords":["something","to","describe","app"],"website":"https://homepage-of-project.com","success_url":"/homepage-or-smth","repository":"https://github.com/your-nickname/your-repository","logo":"http://exampe.com/this-image-will-be-shown-during-the-creation-of-new-app.webp","addons":["cleardb"],"env":{"SYMFONY_ENV":{"value":"prod"}},"scripts":{"postdeploy":"php app/console doctrine:migration:migrate"}}
You can set environment variables directly from config. For example, switch Symfony to production mode:
{"env":{"SYMFONY_ENV":{"value":"prod"}}}
If you need to execute few commands after deployment:
{"scripts":{"postdeploy":"php app/console doctrine:migration:migrate; ls -la; sleep 5"}}
I think everyone knows about the popular application TodoMVC, which is written as a tutorial for every JavaScript framework. Here is an excellent example of how you can deploy a web application Symfony Angular TodoMVC in one click. Here TodoMVC application is written using Symfony and Angular. Do not forget that you need to be registered on Heroku to be able to deploy it. Just find the button in the README of this repository and click it.
You will be redirected to your dashboard to create a new application from template. There is the parameter app.json from which application settings are pulled. It looks like this on the dashboard:
in the URL which has a path to the fileAll information from app.json, is displayed on this page: name, description, logo. As you can see here the add-on for PostgreSQL is defined by default thanks to the one config option:
{"addons":["heroku-postgresql:hobby-dev"]}
After you click on the “Deploy for Free”, the deployment will begin and in a few seconds you will get a working site. Provided that in the master branch you have a working code :) Here is more information about configuring one click deployment.
Add-ons for the popular tasks
If you need to add cron tasks there is an add-on Heroku Scheduler. Documentation describes how to work with it in details.
The Heroku platform itself doesn’t provide an email service. You will need external SMTP server for it. But in the list of available add-ons (Email/SMS category) you can find services which have already been integrated.
The Conclusion
This is the minimum you need to start working with Heroku. If you need additional tools not mentioned in this article, try to find them in the list of add-ons. Most popular tools should be there. Whether Heroku deserves to be a good enough production server? It is difficult to say for me now, because I don’t have much experience with it. But it is quite good as a staging with rapid deployment process. It is also suitable for open source projects that can be deployed in a single click.