Deploying Symfony on Scalingo
Detection
When a PHP application is deployed, Scalingo automatically detect the most well known frameworks, including Symfony.
During the deployment process you’ll see the following output, mentioning that the framework has correctly been detected.
-----> Detected Symfony App
...
-----> Setting up Symfony App
Configuration
The standard way to define environment-dependent variables in Symfony is to
modify the app/config/parameters.yml
file that is generated by Composer and
usually excluded from Git (without that it wouldn’t be safe to store
credentials in it). This method to define environment variables is very
specific to Symfony, and has been thought to be compatible with shared
hostings, where you drag and drop your files on a FTP server, without the
possibility to set normal environment variables.
With Scalingo, it’s exactly the opposite: you can’t modify the parameters.yml
file unless you add it to Git. But as we explained before, it’s a very bad
practice! The good method, as specified in the 12
factors, is to define environment variables.
You now have to choose between two solutions to make your Symfony configuration compatible with environment variables:
Keeping parameters.yml
in dev, using environment variables on Scalingo
Luckily,
Incenteev/ParameterHandler
(the package in charge of managing your parameters) supports environment
parameters. Go to the Scalingo dashboard, and add the needed environment
variables, ideally respecting the UPPERCASE_SNAKE_CASE. Then, edit your
composer.json
file and add a extra.incenteev-parameters
key that describes
the mapping between Symfony parameters and the environment variables:
{
"extra": {
"incenteev-parameters": {
"env-map": {
"database_host": "DATABASE_HOST",
"database_port": "DATABASE_PORT"
}
}
}
}
Now, your application will use the environment variables (when defined), and
the parameters.yml
file.
Get rid of parameters.yml
, only use environment variables
For sure, this will make your configuration cleaner. But parameters.yml
has
the advantage of being easy to edit, and the parameters.yml.dist
provides a
template and configuration reference which is valuable when working in team.
For instance, when a coworker enters composer install
, the CLI will ask him
for the missing values, so he gets notified of parameters changes.
In order to only work with environment variables, let’s remove Incenteev/ParameterHandler:
- Delete the line
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
in yourcomposer.json
; - Delete ParameterHandler’s configuration in
composer.json
underextra.incenteev-parameters
key ; - Run
composer remove incenteev/composer-parameter-handler
.
Now, you’ll find that Symfony provides a native support for environement variables, but when Incenteev/ParameterHandler is installed (it is, by default), they are overwritten by it, since it is loaded at higher level in the framework.
So, if you have a %some.awesome.parameter%
in your config, define the
SYMFONY__SOME__AWESOME_PARAMETER
variable in Scalingo’s dashboard.
It’s now up to you to define your environment variables in your development environment.
Reverse Proxy
Applications on Scalingo are deployed behind a reverse proxy. You need to
instruct Symfony to use the information in the X-Forwarded-*
HTTP headers. The
instructions to do so are available in Symfony
documentation. You basically need to update the public/index.php
file to include:
Request::setTrustedProxies(
// trust *all* requests
['127.0.0.1', $request->server->get('REMOTE_ADDR')],
Request::HEADER_X_FORWARDED_ALL
);
Log Files
By default, we are getting the logs written on stdout and send them to our log aggregator system. The PHP logging does not work the same way (since the standard output is what is sent back to the browser), and Symfony is using its own log files.
These files are named var/logs/dev.log
and var/logs/prod.log
(app
instead
of var
in Symfony 2 applications) by default. The logs stored in those files
are visible in the Logs section of the dashboard.
Cache Warmup
Towards the end of the deployment process, you will see the following output:
Warming up cache
It means that we are preparing the cache of your application, to avoid making
it at runtime and loosing performance. Under the hood, the following command is
executed (replace app
with bin
in Symfony 3):
app/console cache:warmup --env=prod --no-debug
By default, this command executes the default cache warmers that the framework provides. You can add your own cache warmers: learn more about Symfony’s cache warmup here.
Asset Management with AssetMapper
Managing assets in a Symfony apps only requires a handful of PHP packages. Refer to the Symfony documentation for comprehensive instructions on how to install AssetMapper.
Applying Database Migration
During the lifetime of your application, you may need to update the schema of your database. When using Symfony, these actions are handled using the Doctrine ORM. This Symfony documentation page explains how to use Doctrine with your application.
On Scalingo you can teach the platform to apply your database migration automatically during the deployment using a postdeploy hook. Here is the content of the Procfile to apply Doctrine migration to your application:
postdeploy: php bin/console doctrine:migrations:migrate
Note that the postdeploy hook execution time should not exceed 20 minutes. Therefore it should not be used for complex database migration on very large database. In that case you’d better use our CLI to perform such administrative tasks.
Symfony Messenger
Handling Symfony Messenger queues requires you to start another process in your application. Add the following line to the Procfile
of your application:
worker: php bin/console messenger:consume async
After deploying your application, you must scale the newly created type of
containers worker
at least to 1.
Custom Nginx Configuration
You may want to customize the Nginx behaviour for a specific path. The use case for instance is to protect with a password the access to a specific path. In this case one should update the composer.json
to include:
"extra": {
"paas" : {
"nginx-includes": ["./nginx.conf"]
}
}
And add a nginx.conf
at the root of your repository containing:
location ^~ /my/protected/path {
auth_basic Restricted;
auth_basic_user_file /app/.htpasswd;
try_files $uri /index.php =404;
fastcgi_pass php;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
Known Issues
Disable DebugBundle
on Scalingo
When deploying a Symfony app on Scalingo, you may see the following error:
PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "DebugBundle" from namespace "Symfony\Bundle\DebugBundle".
Did you forget a "use" statement for another namespace? in /app/src/Kernel.php:42
This is because your application is deployed in production mode on Scalingo.
Hence, the DebugBundle
dependency is not installed by Composer during the
build. In order to let Symfony know to only use DebugBundle
in development and
test environment, you should update the file config/bundles.php
:
Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true],