Running Laravel on DigitalOcean's App Platform

October 7, 2020

Today DigitalOcean App Platform entered general availability and they offer support for PHP/Laravel apps out of the box. Read on for a deep dive and explore the pros and cons of DigitalOcean's new app platform with me.

If you've used Heroku in the past you'll be right at home on the App Platform. It actually uses heroku buildbacks under the hood, making it super easy to get an app running with no or minimal configuration (or, so they say).

Just want the Review / TL;DR? Skip the Deep Dive and read the Review.

Deploying your first App

Head over the Apps tab on the DigitalOcean dashboard. You'll need to link your GitHub account (they don't support gitlab or any other providers currently). I like that you can give access to only the repos actually required, instead of granting account wide permissions like most other services.

linking with GitHub

Once you'd configured the GitHub integration you can start deploying your project. For the purposes of this demo, I scaffolded a Laravel 8 application with Intertia Jetstream, as it encompasses all of the moving parts in a normal Laravel app (Backend, plus building the javascript with Mix). I selected my demo app and hit Create.

Next up, we need to give the app a name and select the region. I've kept the default name (repo name) and selected New York. Currently, they offer 3 regions being New York, Amsterdam and Frankfurt.

This isn't ideal for me as these locations are all very far away from Australia, but I'm sure they'll launch more regions in the future. I've also selected the Auto Deploy Code Changes option for continuous deployment.

Creating the DigitalOcean App

On the next screen we can configure the service. It seems that we can't actually pick the buildpack here (was guessed from the repo code). We can also set environment variables (what you'd put in your .env normally).

Configuring the DigitalOcean App

I've also added a development managed database (Postgres is the only option). It's a bit pricey at $7/m for a 256mb dev instance and 1GB of disk. You can also link an existing Managed Database (supports both pgsql and mysql, from $15/m).

Linking a Database

Now we've got the app configured we're presented with the plan selection page. I've picked the $5/m 512MB option here. See the "Review" section below for my thoughts on the pricing. Total cost for our dev setup is $12/m.

Reviewing the DigitalOcean App

After hitting Launch Basic App the platform gets started building right away. For this app, it took about 10 minutes to provision the app containers and the database. You can watch a live tail of the build logs under the Deployments tab.

Building the App

Once the initial deployment finished I jumped on over to the automatically provisioned URL. My first deployment was 500ing because I forgot to set the database driver to pgsql, but after updating the environment variables (which automatically redeploys the app) the app was able to connect to the DB.

Updating the Env Vars

After that was finished, I jumped into the Console tab to run the migrations. This was super easy, so props to them for the awesome console.

Executing commands in the console

Whoohoo! We're live, and I can see the splash page. Bad news is we've got an issue. The build pack didn't build the javascript, so our InertiaJS app doesn't work.

I had a look through the docs, but it isn't immediately clear how to get the platform to build the javascript. I tried setting the Build Command to yarn install && yarn prod, but that didn't work because yarn isn't installed.

Update: Turns out I didn't commit the yarn.lock file (which is used to detect what build packs to load). It worked fine once I committed it. It would be good if the documentation around this was a bit better (someone from the DO team did reach out to me via twitter which was awesome but I still couldn't find it in the docs).

I guess this is also where we'd do stuff like running migrations, so it would probably make sense to extract these steps into a bash script and execute that instead.

Setting the build command

Onto the next issue! Our javascript and CSS is now built, but Laravel thinks we're running on http, so it's generating http urls, which our browser is refusing to load because the app is being served over https. I tried setting the APP_URL to be prefixed with https://, but this didn't solve the issue. I'm guessing this is due to the internal load balancer configuration.

HTTP error

To fix this, I change the AppServiceProvider to force HTTPS in production, which fixed the issue.

public function boot()
    {
        if ($this->app->environment('production')) {
            \URL::forceScheme('https');
        }
    }

Adding a Queue Worker

Another pretty common task is running a queue worker (either using queue:work or horizon). To do this, we need another separate worker container. Unfortunately this means an extra $5-12/m (depending on if you're on the basic or pro plans), since there's no way to reuse the existing resources.

From the Components tab, hit Create Component and select the Worker option. You'll need to select the git repository and pick a branch (this will be the same for Laravel apps) as well.

Add a worker

Next, you need to set the run command that will be executed. In this case, it's php artisan queue:work.

Configure a worker

It's worth noting that if one of your containers is on the Pro plan, every future container needs to be as well. This is pretty annoying since you may be happy with a small, cheap queue worker.

Pricing for a worker

Success, we're live 🎉

All in all, it took about an hour for this first exploratory deployment. If I was doing it again, it would probably take me around 15 minutes, which is super quick to get a fully featured app running in production (with horizontal scaling!).

On top of that, we also get Zero Downtime Deployments out of the box as well.

Review + Pros/Cons

At a high level, I really like DigitalOcean's App Platform, and it's awesome to have a Heroku alternative in the space. It's way, way cheaper than Heroku ($5/m vs $25/m for the base plan, more savings for the higher plans). It's easy to approach for beginners, but still suitable for advanced users.

Here's what I'd say an average service would require:

  • 2x 1GB Web Containers - $12m * 2 = $24/m
  • 1x 1GB Managed Database - $15/m
  • 1x 1GB Queue Worker Container - $12/m

At ~ $50/month, it's not super cheap but consider the savings in time (no need for devops, managing servers, etc) I think it's a pretty great deal.

Pros

  • Much cheaper than Heroku
  • Zero downtime deployments
  • Built in CI/CD
  • Built in Horizontal scaling (no autoscaling, but it's coming)
  • Awesome console for managing the app
  • Built in managed databases (though, a bit expensive)
  • Built in Cloudflare CDN

Cons

  • Tiny included outbound bandwidth (40gb on the Basic plans, 100GB on Professional plans)
  • Super expensive bandwidth overage (10c per GiB, that's more than AWS 😬, and they offer 1TB bandwith on $5/m droplets)
  • Documentation is a bit lacking (though, it's a very new offering)
  • No VPCs for isolating apps
  • No wildcard subdomains

Wrapping up

It's awesome to see competition, and nothing is perfect on launch. I'm excited to see the DigitalOcean App Platform improve, and hopefully they address some of the cons/concerns (which seem to be shared by a lot of people).

I hope you enjoyed this post and helped you to evaluate the App Platform for your projects.

If you have any questions, leave a comment below & I'll do my best to respond to them all.

Further reading

DigitalOcean App Platform Docs

DigitalOcean App Platform Pricing

App Platform Spec Docs