Edit on GitHub
Report issue
Page history

Run Symfony on App Engine standard environment

Author(s): @bshaffer ,   Published: 2019-02-01

Brent Shaffer | Developer Programs Engineer | Google

Contributed by Google employees.

In this tutorial, you learn how to deploy an app to the App Engine standard environment, using Symfony PHP components.

See PHP on Google Cloud for an overview of PHP itself and how to run PHP apps on Google Cloud.


  1. Create a project in the Cloud Console, and make note of your project ID.
  2. Enable billing for your project.
  3. Install the Cloud SDK.


This tutorial uses the Symfony Demo application. Run the following command to install it:

composer create-project symfony/symfony-demo:^1.5 $PROJECT_DIR


  1. Run the app with the following command:

    php bin/console server:run
  2. Visit http://localhost:8000 to see the Symfony Welcome page.


  1. Remove the scripts section from composer.json in the root of your project. You can do this manually or by running the following line of code in the root of your Symfony project:

    php -r "file_put_contents('composer.json', json_encode(array_diff_key(json_decode(file_get_contents('composer.json'), true), ['scripts' => 1]), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));"

    The composer scripts run on the Cloud Build server. This is a temporary fix to prevent errors prior to deployment.

  2. Copy the app.yaml file from this repository into the root of your project and replace YOUR_APP_SECRET with a new secret or the generated secret in .env:

    runtime: php72
      APP_ENV: prod
      # Declare the build and bundles directory as static assets to be served by the
      # App Engine CDN.
      - url: /build
        static_dir: public/build
      - url: /bundles
        static_dir: public/bundles
      # Declare any media files in the public directory as static assets as well.
      - url: /(.*\.(ico|txt|gif|png|jpg))$
        static_files: public/\1
        upload: public/.*\.(ico|txt|gif|png|jpg)$

    Read more about the env and secret parameters in Symfony's documentation.

  3. Override the cache and log directories so that they use /tmp in production. This is done by adding the functions getCacheDir and getLogDir to src/Kernel.php:

    class Kernel extends BaseKernel
        public function getCacheDir()
            if ($this->environment === 'prod') {
                return sys_get_temp_dir();
            return parent::getCacheDir();
        public function getLogDir()
            if ($this->environment === 'prod') {
                return sys_get_temp_dir();
            return parent::getLogDir();

    This is required because App Engine's file system is read-only.

  4. Deploy your application to App Engine:

    gcloud app deploy
  5. Visit http://YOUR_PROJECT_ID.appspot.com to see the Symfony demo landing page.

The homepage will load when you view your application, but browsing to any of the other demo pages will result in a 500 error. This is because you haven't set up a database yet. Let's do that now.

Connect to Cloud SQL with Doctrine

Next, connect your Symfony demo application with a Cloud SQL database. This tutorial uses the database name symfonydb and the username root, but you can use whatever you like.


  1. Follow the instructions to set up a Cloud SQL Second Generation instance for MySQL.

  2. Create a database for your Symfony application. Replace INSTANCE_NAME with the name of your instance:

    gcloud sql databases create symfonydb --instance=INSTANCE_NAME
  3. Enable the Cloud SQL APIs in your project.

  4. Follow the instructions to install and run the Cloud SQL proxy client on your local machine. The Cloud SQL proxy is used to connect to your Cloud SQL instance when running locally. This is so you can run database migrations locally to set up your production database.

    • Use the Cloud SDK from the command line to run the following command. Copy the connectionName value for the next step. Replace INSTANCE_NAME with the name of your instance:

      gcloud sql instances describe INSTANCE_NAME
    • Start the Cloud SQL proxy and replace INSTANCE_CONNECTION_NAME with the connection name you retrieved in the previous step:

      cloud_sql_proxy -instances=INSTANCE_CONNECTION_NAME=tcp:3306 &

      Include the -credential_file option when using the proxy, or authenticate with gcloud, to ensure proper authentication.


  1. Modify your Doctrine configuration in config/packages/doctrine.yml and change the parameters under doctrine.dbal to be the following:

    # Doctrine Configuration
            driver: pdo_mysql
            url: '%env(resolve:DATABASE_URL)%'
        # ORM configuration
        # ...
  2. Use the Symfony CLI to connect to your instance and create a database for the application. Be sure to replace DB_PASSWORD with the root password you configured:

    # create the database using doctrine
    DATABASE_URL="mysql://root:DB_PASSWORD@" \
        bin/console doctrine:schema:create
  3. Modify your app.yaml file with the following contents. Be sure to replace DB_PASSWORD and INSTANCE_CONNECTION_NAME with the values you created for your Cloud SQL instance:

    runtime: php72
      APP_ENV: prod
      # Add the DATABASE_URL environment variable
      DATABASE_URL: mysql://root:DB_PASSWORD@localhost?unix_socket=/cloudsql/INSTANCE_CONNECTION_NAME;dbname=symfonydb
    # URL handlers
    # ...


  1. Now you can run locally and verify the connection works as expected.

        php bin/console server:run
  2. Run the following command to deploy your application to App Engine:

    gcloud app deploy

Set up Logging and Error Reporting

Install the Google Cloud libraries for Logging and Error Reporting:

# Set the environment variable below to the local path to your symfony project
composer require google/cloud-logging google/cloud-error-reporting

Copy over App Engine files

For your Symfony application to integrate with Logging and Error Handling, you will need to copy over the monolog.yaml config file and the ExceptionSubscriber.php Exception Subscriber:

# clone the Google Cloud PHP samples repo somewhere
cd /path/to/php-samples
git clone https://github.com/GoogleCloudPlatform/php-docs-samples

# enter the directory for the symfony framework sample
cd appengine/php72/symfony-framework/

# copy monolog.yaml into your Symfony project
cp config/packages/prod/monolog.yaml \

# copy ExceptionSubscriber.php into your Symfony project
cp src/EventSubscriber/ExceptionSubscriber.php \

The files needed are as follows:

config/packages/prod/monolog.yaml: Adds Stackdriver Logging to your Monolog configuration.

src/EventSubscriber/ExceptionSubscriber.php: Event subscriber that sends exceptions to Stackdriver Error Reporting.

If you'd like to test the logging and error reporting, you can also copy over LoggingController.php, which exposes the routes /en/logging/notice and /en/logging/exception for ensuring your logs are being sent:

# copy LoggingController.php into your Symfony project
cp src/Controller/LoggingController.php \

src/Controller/LoggingController.php: Controller for testing logging and exceptions.

View application logs and errors

Once you've redeployed your application using gcloud app deploy, you'll be able to view Application logs in the Logging UI, and errors in the Error Reporting UI. If you copied over the LoggingController.php file, you can test this by pointing your browser to https://YOUR_PROJECT_ID.appspot.com/en/logging/notice and https://YOUR_PROJECT_ID.appspot.com/en/logging/exception

Send email messages

The recommended way to send email is to use a third-party mail system such as SendGrid, Mailgun, or Mailjet. Hosting your application on App Engine, most of these providers will offer you up to 30,000 emails per month, and you will be charged only if you send more. Using such a system, you can track your email delivery and benefit from all of the features of a real email broadcasting system.

  1. Install the mailer component:

    composer require symfony/mailer
  2. Specify which mail sytem to use:

    composer require symfony/mailgun-mailer

    This example uses Mailgun. To use a different mail provider, see the Symfony mailer documentation.

  3. Add environment variables to your .env file:

    # Will be provided by mailgun once your account will be created
    MAILGUN_KEY= xxxxxx
    # Should be your Mailgun MX record
    MAILGUN_DOMAIN= mg.yourdomain.com
    # Region is mandatory if you chose server outside the US otherwise your domain will not be found
  4. Create your account and first domain and add DNS records as described in the Mailgun documentation.

After following these steps, you can send email messages in Controller and Service:

// src/Controller/MailerController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;

class ExampleController extends AbstractController
     * @Route("/email")
    public function sendEmail(MailerInterface $mailer)
        $email = (new Email())
            ->subject('Time for Symfony Mailer!')
            ->text('Sending emails is fun again!');


Session management

To make sessions persist across multiple App Engine instances, you'll need to use a database. Symfony provides a way to handle this using PDO session storage.


  1. Modify your Framework configuration in config/packages/framework.yaml and change the parameters under session to be the following:

        handler_id: Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler
        cookie_secure: auto
        cookie_samesite: lax
        # Adjust the max lifetime to your need
        gc_maxlifetime: 36000
  2. Activate the service in config/services.yaml:

            - !service { class: PDO, factory: ['@database_connection', 'getWrappedConnection'] }
            # If you get transaction issues (e.g. after login) uncomment the line below
            # - { lock_mode: 1 }

Database update

Add the sessions table to your database by connecting to your database and executing the following query:

# MySQL Query
CREATE TABLE `sessions` (
    `sess_id` VARCHAR(128) NOT NULL PRIMARY KEY,
    `sess_data` BLOB NOT NULL,
    `sess_lifetime` INTEGER UNSIGNED NOT NULL
) COLLATE utf8mb4_bin, ENGINE = InnoDB;

You are now all set. The session will persist in the database and your users will remain authenticated.

Submit a tutorial

Share step-by-step guides

Submit a tutorial

Request a tutorial

Ask for community help

Submit a request

View tutorials

Search Google Cloud tutorials

View tutorials

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see our Site Policies. Java is a registered trademark of Oracle and/or its affiliates.