Getting Started with Laravel on Heroku
Last updated 15 November 2017
Table of Contents
- PHP (and ideally some Laravel) knowledge.
- A Heroku user account. Signup is free and instant.
- Familiarity with the getting Started with PHP on Heroku guide, with PHP, Composer and the Heroku CLI installed on your computer.
Creating a Laravel application
The application in this tutorial is based on the Laravel Installation guide. It’s worth a read before following the instructions in this article.
Installing a new Laravel project
composer create-project command is one of the ways you can bootstrap a new project based on the laravel/laravel standard application skeleton. The command below sets it up in a directory named
hello_laravel_heroku using the latest version of the framework.
After downloading an extensive number of dependencies and running a few hooks, Composer will have set up a fully functional project in the directory you specified, so you can
cd to it.
$ composer create-project laravel/laravel --prefer-dist hello_laravel_heroku Installing laravel/laravel (v5.1.11) - Installing laravel/laravel (v5.1.11) Downloading: 100% Created project in hello_laravel_heroku ... ... $ cd hello_laravel_heroku
Initializing a Git repository
It’s now time to initialize a Git repository and commit the current state:
$ git init Initialized empty Git repository in ~/hello_laravel_heroku/.git/ $ git add . $ git commit -m "new laravel project" [master (root-commit) 6ae139d] new laravel project 76 files changed, 5458 insertions(+) ...
Deploying to Heroku
To deploy your application to Heroku, you must first create a
Procfile, which tells Heroku what command to use to launch the web server with the correct settings. After you’ve done that, you’re going to create an application instance on Heroku, configure some Laravel environment variables, and then simply
git push to deploy your code!
By default, Heroku will launch an Apache web server together with PHP to serve applications from the root directory of the project.
However, your application’s document root is the
public/ subdirectory, so you need to create a
Procfile that configures the correct document root:
$ echo web: vendor/bin/heroku-php-apache2 public/ > Procfile $ git add . $ git commit -m "Procfile for Heroku" [master 1eb2be6] Procfile for Heroku 1 file changed, 1 insertion(+) create mode 100644 Procfile
Creating a new application on Heroku
To create a new Heroku application that you can push to, use the
heroku create command:
$ heroku create Creating mighty-hamlet-1982... done, stack is cedar-14 http://mighty-hamlet-1982.herokuapp.com/ | firstname.lastname@example.org:mighty-hamlet-1982.git Git remote heroku added
As you can see, a random name was automatically chosen for your application (in the example above, it’s
You are now almost ready to deploy the application. Follow the next section to ensure your Laravel app runs with the correct configuration.
Setting a Laravel encryption key
The application’s encryption key is used by Laravel to encrypt user sessions and other information. Its value will be read from the
APP_KEY environment variable.
As it must comply with the rules of the selected cipher in the configuration, the easiest way to generate a valid key is using the
php artisan key:generate --show command, which will print a key that you can copy and then paste into the next step.
You can simply set environment variables using the
heroku config command, so run a
heroku config:set as the last step before deploying your app for the first time:
$ heroku config:set APP_KEY=… Setting config vars and restarting mighty-hamlet-1982... done, v3 APP_KEY: ZEqur46KTEG91iWPhKGY42wtwi3rtkx2
… in the command above with the key you copied from the
php artisan key:generate --show command output.
Instead of manually replacing the
… placeholder in the command above, you can also run
heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show).
Pushing to Heroku
Next, it’s time to deploy to Heroku:
$ git push heroku master Counting objects: 4, done. Delta compression using up to 4 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (4/4), 379 bytes | 0 bytes/s, done. Total 4 (delta 3), reused 0 (delta 0) remote: Compressing source files... done. remote: Building source: remote: remote: -----> Fetching custom git buildpack... done remote: -----> PHP app detected remote: -----> Resolved 'composer.lock' requirement for PHP to version 5.6.14. remote: -----> Installing system packages... remote: - PHP 5.6.14 remote: - Apache 2.4.10 remote: - Nginx 1.6.0 remote: -----> Installing PHP extensions... remote: - mbstring (composer.lock; bundled) remote: - zend-opcache (automatic; bundled) remote: -----> Installing dependencies... remote: Composer version 1.0.0-alpha10 2015-04-14 21:18:51 remote: Loading composer repositories with package information remote: Installing dependencies from lock file ... remote: - Installing laravel/framework (v5.1.19) remote: Downloading: 100% remote: remote: Generating optimized autoload files remote: Generating optimized class loader remote: Compiling common classes remote: -----> Preparing runtime environment... remote: -----> Discovering process types remote: Procfile declares types -> web remote: remote: -----> Compressing... done, 74.5MB remote: -----> Launching... done, v5 remote: https://mighty-hamlet-1982.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To https://git.heroku.com/mighty-hamlet-1982.git 1eb2be6..1b70999 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 CLI to launch a new browser window, the application will respond.
$ heroku open Opening mighty-hamlet-1982... done
You should see a message in your browser that says “Laravel 5”.
Changing the log destination for production
By default, Laravel will log errors and messages into a directory on disk, which isn’t ideal, because Heroku uses an ephemeral filesystem and treats logs as streams of events across all running dynos.
In order to ensure that errors, should they arise, are visible in
heroku logs, the corresponding configuration in
config/app.php must be changed:
/* |-------------------------------------------------------------------------- | Logging Configuration |-------------------------------------------------------------------------- | | Here you may configure the log settings for your application. Out of | the box, Laravel uses the Monolog PHP logging library. This gives | you a variety of powerful log handlers / formatters to utilize. | | Available Settings: "single", "daily", "syslog", "errorlog" | */ 'log' => 'errorlog',
Do not forget to add, commit, and, if appropriate, push this change:
$ git add config/app.php $ git commit -m "use errorlog" [master 1b70999] use errorlog 1 file changed, 1 insertion(+), 1 deletion(-) $ git push heroku master
Trusting the Load Balancer
Heroku’s HTTP Routing routes each request through a layer of reverse proxies which are, among other things, responsible for load balancing and terminating SSL connections. This means that requests received by a dyno will have the last router’s IP address in the
REMOTE_ADDR environment variable, and the internal request will always be made using the HTTP protocol, even if the original request was made over HTTPS.
Like most common load balancers or reverse proxies, Heroku provides the original request information in
X-Forwarded-… headers (as documented here). Laravel uses components from the Symfony framework for HTTP request handling, and Symfony can easily be configured to trust such headers.
Since Heroku sends all requests to an application through a load balancer first, and that load balancer always sets the headers (making it impossible for a client to forge their values), you can configure Laravel to treat the current remote addresses (which is the Heroku router) as a trusted proxy.
You can use the
fideloper/proxy package to automate this procedure. After following the installation instructions, you will need to slightly adjust the
config/trustedproxy.php configuration file so that it trusts all proxy addresses.
It is very important to also prevent Laravel from trusting the
X-Forwarded-Host headers, because Heroku’s router does not set those, but Symfony’s Request component trusts them out of the box once a trusted proxy is set.
The final configuration file should look like this:
<?php return [ 'proxies' => '*', 'headers' => [ Illuminate\Http\Request::HEADER_FORWARDED => null, // not set on AWS or Heroku Illuminate\Http\Request::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', Illuminate\Http\Request::HEADER_CLIENT_HOST => null, // not set on AWS or Heroku Illuminate\Http\Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', Illuminate\Http\Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', ] ];
With this approaches, if you deploy your application to other environments, you must similarly ensure that all traffic arrives through a trusted source, or conditionally only set the trusted proxy when you detect Heroku as the environment your application is running in.
- Read the Heroku PHP Support Dev Center article to learn about available versions, extensions, features and behaviors.
- Review the instructions on customizing web server and runtime settings for PHP to learn more about configuring Apache, Nginx and PHP.
- Browse the PHP category on Dev Center for more resources.