Introduction
So, you've just built your beautiful Laravel application, it has authentication, localization, tests and all the fancy features that could possibly impress the recruiter and land you a job. However, it's only working on your machine. How do we solve this?
In this post, we’ll be looking into hosting a Laravel application (with a MySQL or MariaDB database included) on Heroku for free.
Deploying
💡 Notice: Replace items within brackets ([]
) with your desired information.
Creating Laravel application
If you don't have a Laravel app yet, the first thing we got to do is create a brand new one. To do this, first you need to have Composer installed on your machine. After installing composer you can run the following command to install the Laravel installer:
composer global require laravel/installer
And then you can create a new Laravel app:
laravel new [brand-new-app]
For more information about Laravel installation, check the Laravel Installation guide. It’s worth a read before following the instructions in this article.
Initializing git
To deploy to Heroku we'll be using Git. If you don't know how to use this, I recommend you watch the Git and GitHub Crash Course on freeCodeCamp. It's a very important tool for developers and you should know it.
Anyways, the first thing you gotta do is enter your project folder using the terminal and initialize a git repository:
git init
And then adding all the files and making a commit
git add .
git commit -m "Initial commit"
Alright, now your git repository is set.
Using the Heroku CLI
We'll use the Heroku CLI to deploy our app. You can find the installation guide here.
After you've installed the Heroku CLI, create a Heroku free account and run heroku login
in your terminal. Follow the instructions and after you've been successfully logged in, you can create your Heroku application (change brand-new-app
to your desired app name):
heroku create [brand-new-app]
Now you need to generate the APP_KEY
required by Laravel. You can do this by using the heroku config:set APP_KEY=$(php artisan --no-ansi key:generate --show)
command.
Creating a Procfile
By default, Heroku will launch an Apache web server together with PHP to serve applications from the root directory of the project.
However, our application’s document root is the public/
subdirectory, so we need to create a Procfile
that configures the correct document root. We can do this by manually creating a Procfile
file or using the terminal:
echo "web: vendor/bin/heroku-php-apache2 public/" > Procfile
Add the untracked files and commit your changes:
git add .
git commit -m "Procfile for Heroku"
Pushing to Heroku
Now you should be able to push your app to Heroku:
git push heroku master
To view your app, access https://[brand-new-app].herokuapp.com
or click the Open app
button located in the Heroku dashboard (https://dashboard.heroku.com/apps/[brand-new-app])
Avoiding Mixed Content error
If you use the asset()
helper function a lot, you'll probably notice that your hosted app isn't loading some assets files and is showing a Mixed Content
error in the console.
To fix this, open your applications' AppServiceProvider
at [brand-new-app]/app/Provider/AppServiceProvider.php
and, in the boot()
method, add:
if (config('app.env') === 'production') {
\URL::forceScheme('https');
}
And now create a APP_ENV
variable with a production
value using the Heroku CLI or on your app's settings (https://dashboard.heroku.com/apps/[brand-new-app]/settings > Config Vars > Reveal Config Vars).
heroku config:set APP_ENV="production"
Commit and push your new changes to Heroku
git commit -am "Adding URL::forceScheme('https') in production environments"
Now your project should load properly without errors
If the error persist, check if there are no links using HTTP instead of HTTPS.
Setting environment variables
The next thing we need to do is set our .env
variables in Heroku. We've already set the APP_ENV
and APP_KEY
variables, let's set the remaining ones. Again, you can do this by using the Heroku CLI or on your app's settings (https://dashboard.heroku.com/apps/[brand-new-app]/settings > Config Vars > Reveal Config Vars).
You can keep the database information (DB_CONNECTION
, DB_DATABASE
, DB_USERNAME
, etc) the same as the local configuration for know. We'll take care of that later.
Adding and configuring database
Now we have to add a database to our project.
Go to your application dashboard and click on resources (https://dashboard.heroku.com/apps/[brand-new-app]/resources). In the "Add-ons" input, type MySQL and choose ClearDB MySQL
. Select the "Ignite - Free" plan and click on "Submit Order Form".
Make sure you assigned your credit card to your Heroku account. If you didn't add it yet, click on your profile photo (top right corner) > Account settings > Billing > Add credit card. Don't worry, you won't be charged unless you choose a paid plan. As soon as you've added your card, repeat the step above.
As soon as you've added the ClearDB MySQL add-on, go to your terminal and type heroku config | grep CLEARDB_DATABASE_URL
It should display something like this:
CLEARDB_DATABASE_URL: mysql://uuuuuuuuuuuuuu:pppppppp@hh-hhhh-hhhh-hh.cleardb.com/heroku_ddddddddddddddd?reconnect=true
Everything after the @ symbol until the / is the DB_HOST
(hh-hhhh-hhhh-hh.cleardb.com). Everything after / until ? is DB_DATABASE
(heroku_ddddddddddddddd). The string after the // until : is the DB_USERNAME
(uuuuuuuuuuuuuu). The string between : and @ is the DB_PASSWORD
(pppppppp).
Don't show, tell or publish these credentials anywhere. These are your database information. That's why I censored it. In your case it should have real numbers and letters.
Now it's time to change your production database environment variables with the real ones provided by ClearDB. Go to your app settings (https://dashboard.heroku.com/apps/[brand-new-app]/settings), click "Reveal Config Vars" and change the database variables. It should be like this:
key | value |
---|---|
DB_HOST | hh-hhhh-hhhh-hh.cleardb.com |
DB_DATABASE | heroku_ddddddddddddddd |
DB_USERNAME | uuuuuuuuuuuuuu |
DB_PASSWORD | pppppppp |
Migrating database tables
Now it's time to run our migrations and create our database tables.
In your terminal, type heroku run php artisan migrate:fresh
. It will ask you if you really want to run this command, type yes
.
After running this command, there is a high chance that it will return this error:
It happens because, by default, Laravel uses the utf8mb4
character set. If the server is running a version of MySQL older than the 5.7.7 release or MariaDB older than the 10.2.2 release, you may need to manually configure the default string length generated by migrations.
Learn more at: https://laravel.com/docs/8.x/migrations#index-lengths-mysql-mariadb.
To fix this, add the code below to the boot()
method located in your app/Providers/AppServiceProvider.php
Schema::defaultStringLength(191);
Don't forget to import Schema at the top of the file:
use Illuminate\Support\Facades\Schema;
Your AppServiceProvider
should be like this at this point:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
if (config('app.env') === 'production') {
\URL::forceScheme('https');
}
Schema::defaultStringLength(191);
}
}
Commit your changes and push to Heroku again
git commit -am "Setting defaultStringLength to 191"
git push heroku master
Run the migrations again with heroku run php artisan migrate:fresh
and it should work.
Seeding the database
Let's learn how you can seed your database in case you need to.
In your terminal, type heroku run php artisan db:seed
. It will also ask you if you really want to run this command, type yes
.
💡 Notice: Heroku increments tables by 10, for example id's would appear like this: 1, 11, 21, 31
. Beware when using user IDs for reference in Seeds or Factories.
When you run this command, it might tell you that the Class 'Faker\Factory'
was not found. It happens because faker
is required as a dev dependency. To fix this, simply open your composer.json
file and move "fzaninotto/faker": "^1.9.1",
from require-dev
to require
.
And then run composer update
.
Commit your changes and push to Heroku one more time
git commit -am "Moving fzaninotto/faker from require-dev to require in composer.json"
git push heroku master
Seed the database again with heroku run php artisan db:seed
and it should work.
[BONUS] Storing uploaded files
In case you are working with file uploads in your Laravel application, there's one caveat you should be aware of: Heroku uses ephemeral filesystem. That means that any changes to the filesystem whilst the dyno is running only last until that dyno is shut down or restarted. Each dyno boots with a clean copy of the filesystem from the most recent deploy. In addition, under normal operations dynos will restart every day in a process known as "Cycling".
When this happens, your image or any other uploaded file will be completely deleted from your application and users will see nothing but the image alt
text.
Knowing this, it's recommended that you use a dedicated file storage service such as AWS S3.
You can learn more about this approach that Heroku uses here and here.
Conclusion
Congratulations! Now you have your Laravel application up and running. Now you can add it to your portfolio and show your work to people.
Heroku free plan has some limitations and maybe your app stop working in some days of the month (it usually goes back online when a new month starts). If you are feeling the need to upgrade, do it.
Improvements and/or corrections are welcome 😀.
Top comments (8)
Bro, i think this is one of the BEST laravels tutorials I have ever found on this site. Thank you, however I have a question regarding the faker, I get a "fakerphp/faker": "^1.9.1" instead of "fzaninotto/faker": "^1.9.1", is this the same thing but maybe you have another kind of faker??
I just saw that fakerphp/faker is really a fork of the archived
fzaninotto/faker
repository, as I suspected.Oops, sorry for the wait, I did not see your comment. So, looking at the official "fzaninotto/faker" GitHub repository, it seems like the project was archived. The creator has written a blog post about this. You can check it out here: marmelab.com/blog/2020/10/21/sunse...
Nice guide! Thank you! I was able to deploy my calendar appointments api. Here some tips:
Cheers!
Nice! Thank you for the tips :)
Topp dms
Great and clear walkthrough!
Will use this guide to deploy my app once it's tested.
Keep it up!🤙🤙
Thank you 😀.
I'll keep updating the article if needed. Feel free to suggest improvements if I've forgotten anything.