Deploying Laravel to DigitalOcean App Platform
Ryan Olson
Posted on November 10, 2020
STILL IN DRAFT, SHARING TO HELP SOMEONE WHO ASKED!!!
With the release of the DigitalOcean App Platform, I decided to see how it would work if I deployed one of my multi repo projects. After seeing all the tutorials online, the quirks people talk about and my own experiences, I decided to write this article. Understand I am not the only one who contributed to this. In fact, most people don't even know they helped me because of their own work over the last few years. With that being said, lets get into the deployment.
I also want to stress, this is my FIRST tutorial in over 15 years, so PLEASE feel free to start an open dialogue on how I can improve this for others. This and anything I do should be a living document that changes and improves based on the community.
What are we deploying?
So, I will be helping you deploy a Laravel API which will serve my VueJS frontend and a seperate VueJS admin panel I decoupled from my original Laravel around the start of my development. This should also work for a full featured Laravel project but I am a strong supporter of keeping front and backend's separate for the purposes of scaling.
Prerequisites
So, the first thing you will need is a Laravel project. If you need to know how to set up a basic project for this tutorial, I suggest you check out https://www.laravel.com/ and get into the docs. I am only here to help you deploy a functioning Laravel site with database and security. You will also need a DigitalOcean account and if you do not have one, then I STRONGLY suggest you use my link so I can get a few bucks into my account. Which in turn saves the pocket cash I have for LOTS of Nespresso capsules!
https://m.do.co/c/5dda8a62c7b5
Create your App Platform Project
So, now that we got all the fluff out of the way, lets get this going. The first thing you need to do is get into the app platform. If you do not have any apps deployed yet you will see this really cool screen. I love when things look and are simple... so let's click the button!
This process is quite simple and to be honest, deploying Laravel is as simple as selecting your github repo, selecting the branch, and deploying. We will make all the changes we require after. The things I want to bring to your attention are:
If you need or want the ability to have multiple instances (load balancing) of your project, you will need to select the pro version. Once you do, by default it will pick the $25/instance/month plan. I am fine with this but if you know your API is going to be quick and low memory, click the dropdown and select the $12
The other thing I want to bring to your attention is as you are doing the setup of your Laravel deployment, make sure you consider how this will be used. In my case, I am using Laravel as a complete backend API. My frontend is using VueJS (which I will put into a separate deployment guide). If you are planning on having a unified deployment of front and backend within Laravel, there might be things I am missing. This doesn't mean this guide WON'T help you, just make sure you take that into account.
Step 1:
In my case, I already have GitHub configured, if you do not, take a moment and connect your DO account to GitHub then you will be able to see all your repositories. Select the one you want and click next.
Step 2:
To me, this is where I am sold on App Platform. Name your deployment all in lowercase and select where you want to deploy this. Also, select the branch you want to deploy and decide if you want it to auto deploy each time you make a commit to your repo.
In a future article, I will discuss how you can create multiple deployments in multiple regions and route your users to the nearest one.
Step 3:
Once you get into the swing of things you are more than welcome to add all the variables you need here. To be honest, at the end of this article I am going to show you how to deploy using an "App Spec" with doctl, so for me, this isnt something I would ever use but this is where you could set any immediate variables you need during your deployment. You will notice that most of this is filled in for you and this is thanks to the Heroku system being utilized. Click next...
Step 4:
Finally, let's get this baby deploying! Remember above I told you if you want to have load balancing? Remember when I said the default is $25/month, well, here we are. For Laravel, you cannot deploy it as a static site. PHP is a server-side language so you gotta trust in the system. Whatever you pick here is going to define what you will have available for the future. If you want to select the basic $5 plan just to walk through this by all means go ahead. I do recommend that you put the time into selecting Pro and just changing the size to $12/month. Later in this article I am going to discuss scaling and balancing so it's a good idea to do this now.
Now, go get a cup of coffee/tea/water with or without lemon and let DO do the work for you!
Create a database (Postgresql)
Initially, when I started this, I was going to use MySQL. You forget after a while that Eloquent will allow you to use whatever DB you want as long as you write your code properly. This means when it comes to DO, I decided to use the DB they natively support.
First things first, let go to the COMPONENTS tab, and click on CREATE COMPONENT and select Database. DigitalOcean by default currently supports Postgresql so we can click development database. The big thing to remember here is we are only going to do development while we setup our system. Why waste the time doing all the fancy production things if there is a chance we might need to blow away everything and go back and start from scratch. This is also a good place to start because App Platform will do some of the lifting for us such as setting the environment variable for connecting to the database.
Step 1
Step 2
Step 3
Go grab another whatever you are drinking and let the database create and (re)deploy your app. At this time while you are sipping your drink of choice, the development database is being created, the connection string is being injected into the app as an environment variable called DATABASE_URL (which isn't that great because that's what Laravel wants)
Now for the fun part. Let's populate the database with all our tables using the following command
php artisan migrate
Once your deployment is done, jump down to "CREATE A WORKER".
Create a database (MySQL)
Create a worker
Configure Passport
I am going to be honest, this is the whole reason I wrote this document. While the answer was right in the code from Laravel, it is not clearly documented. I was able to find the solution and thanks to Freek Van der Herten (@freekmurze) from Spatie (@spatie_be), he proposed and was successfully merged to use environment variables for both the public and private keys. So, now that we know what we need to do, let's get to it and learn the little tricks.
First thing we are going to do is click on the console for our project. Truly, it doesn't matter which one you click on, worker or backend, but I do suggest using the backend one so you can test before you redeploy.
Now, let's do the magic. In your console, type:
php artisan passport:install
This will create the passport keys and database entries needed for all your authentication needs. It will also tell you the location of where your oauth private and public keys are.
Now, let's view the content of each key so we can get ready to store them. For each file, we are going to view the contents then save them as an environment variable. So you need the following 2 commands:
cat oauth-private.key
cat oauth-public.key
Configure Redis
The things that got me
Deploying Postgresql
Setting Database Connection
I do this EVERYTIME no matter how much I tell myself I will not do this. Even writing this, I did it which is how I got this screenshot. So, if you start deploying and you see this:
Remind yourself that you forgot to change the database driver. So, go back to COMPONENTS->YOUR DEPLOYMENT->ENVIRONMENT VARIABLES->EDIT and add the following
DB_CONNECTION=pgsql
This will cause a redeployment because we have to make sure its available to the app. So the container(s) need to be rebuilt. If you have a worker setup, you will need to add this onto the worker as well. Just do it right away, the first deployment will cancel and both will be built on the new one.
SSL Mode
Again, I do this EVERYTIME (seriously it drives me bonkers that I forget the simple things).
Setting PHP extensions
Scaling
One of the reasons I am in love with Laravel AND App Platform with Managed DB, is I can setup scaling ahead of time. What I do all the time is change the config/database.php file in Laravel to look like this. You can do this for both MySQL or PGSQL. Then, as opposed to using URL for my database, I setup all the env variables for each item below. The difference is I do not use HOST, I use DB_HOST_READ and _WRITE - I just set them to the same DB to start, but at any point I need to add read cluster, or I want to deploy to muliple regions, I can set the read DB's to the local Datacenter but allow the writes to go to the master.
'pgsql' => [
'driver' => 'pgsql',
'read' => [
'host' => [
env('DB_HOST_READ'),
],
],
'write' => [
'host' => [
env('DB_HOST_WRITE'),
],
],
'sticky' => true,
'url' => env('DATABASE_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '5432'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'prefix' => '',
'prefix_indexes' => true,
'schema' => 'public',
'sslmode' => env('DB_SSLMODE', 'prefer'),
],
doctl and you
Final Thoughts
References and Links
Things I used to get answers
https://atymic.dev/blog/laravel-on-digitalocean-apps/
https://github.com/laravel/passport/pull/683
Product Links
https://www.digitalocean.com/
https://www.laravel.com/
https://laravel.com/docs/master/passport
Shameless Plugs
Posted on November 10, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.