Deploying a site to Laravel Forge

By

Learn how to deploy a Laravel app with Laravel Forge and DigitalOcean: create a server, connect GitHub, set env vars, and run the deploy script.

~~~

It’s all fun and all, but now we want to deploy the application on a real server, on the Internet, so people can use it.

There are many different ways to deploy a Laravel application. A Laravel 13 app deploys the same way as earlier majors: Git repo, server env, then a deploy script that installs PHP deps and builds front-end assets.

Probably the best one is using Laravel Forge, the official deployment platform, combined with DigitalOcean.

When it comes to servers, and unless you like managing servers and you’re actually an expert, I am a fan of investing some money and saving time instead.

Forge in particular is official, made by the core team of Laravel, lots and lots of people use it (they claim over 500,000 sites are powered by Forge), and we can trust that to work as expected.

Forge does not provide a server to you. But it’s a service that connects to DigitalOcean and other VPS - virtual private server - providers like Hetzner, AWS, Vultr and more and it creates a server for you on that platform.

You could directly use a VPS, of course. Follow a tutorial, set everything up, invest hours into basically doing what Forge can do with a few simple steps. It’s a matter of convenience.

And in the long run, Forge can upgrade PHP for example with a simple click. If that’s left to you to manage, it’s more complicated.

Anyway, pick your poison. Spend time and effort, or spend some money and focus on your app.

How much money? Forge still starts around $12/month on the Hobby plan (check current pricing). Plans change over time, so confirm on their site before you subscribe.

Go to https://forge.laravel.com/ and sign up (or start a trial if they offer one):

Laravel Forge homepage with Start a free trial button highlighted

Once you’re in, connect Forge to GitHub so it can pull your code:

Forge dashboard with Connect to GitHub button

GitHub authorization screen for Laravel Forge

Now it’s time to connect to a server provider.

Server provider selection screen with DigitalOcean option

I pick DigitalOcean.

If you’re unsure, sign up for DigitalOcean with my referral link and you get $200 in credit for 60 days, so you can try it out for free. This is an affiliate link: if you sign up through it and then spend $25, I get $25 in DigitalOcean credit.

I click the link to create an API token and I generate one

DigitalOcean API token creation page

Generated DigitalOcean API token ready to copy

and finally I copy the code to Forge.

I now have access to the servers dashboard

Laravel Forge servers dashboard with connected DigitalOcean

Here’s where you need to create the subscription if you haven’t already. I picked the Hobby plan when I wrote this:

Laravel Forge subscription plans with Hobby plan highlighted

Now back to the servers page, create a new server:

Create new server button on Laravel Forge servers page

Pick an app-style server (Forge’s default for Laravel apps). It ships with Nginx, PHP, and a database ready for Laravel.

Pick a region near you, and pick a modest server size, so you can save on server costs until someone actually uses your app (you can always upgrade the server later via the DigitalOcean panel).

In the advanced options you can set the OS, database, and PHP version. For Laravel 13 you want a current PHP 8.x line:

Advanced server settings showing OS, database and PHP version options

I picked Postgres because I like that more, but it’s just a preference.

Create the server and wait for provisioning to finish:

Server installation progress screen showing setup in progress

It will take some minutes, after which you’ll have your server up and running.

A server perfectly configured to run Laravel, already set up with the Nginx server, database, and much more.

Once it’s done, here is the control panel of your server. On the left, there’s a menu that gives you access to specific menus.

Laravel Forge server control panel with left navigation menu

For example you have access to server logs through “Logs”:

Server logs page showing various log files

You can see the scheduled jobs in “Scheduler”:

Scheduler page for managing scheduled jobs

…and lots more.

Back to the Sites menu.

You can restart the entire server, or specific services, throught the Restart drop down menu:

Restart dropdown menu showing server and service restart options

which is very handy, and you can deploy new sites on this server.

Each server can host multiple different sites.

There is a default one already set up, and if you copy and paste the public IP address of the server in your browser, you’ll see it working:

Default Laravel Forge site showing welcome page in browser

Now let’s deploy the application on this site.

Ideally what you want to do is, you create a new site with a domain / subdomain assigned.

But it’s starting to become complicated for this handbook, so we’ll just use the default site which works on the IP address instead.

Click the default site in the dashboard and you’ll see the site panel:

Site panel showing configuration options for the default site

We have the site in GitHub, so open the site’s Git repository settings:

Git Repository configuration form with repository name and branch fields

Type the repository as account/repo (in my case flaviocopes/second), pick the branch (usually main), and install it.

After a while it’s done!

Success message showing repository installation completed

But if you go to the IP address again, there’s an error:

Browser showing 500 error page when visiting the deployed site

Mmmm! We don’t see more details because now the site is in a production environment, and we don’t show detailed logs to users.

To figure out the problem let’s go back to the panel, open Logs and you’ll see the error is related to connecting to the database.

Error logs showing database connection failure

If you look closely in the GitHub repository you will see the .env file was not pushed to GitHub, and this is correct because you don’t want to store the environment variables in Git.

In the Forge site config open the environment editor. That’s where production env vars live:

Environment tab showing environment variables configuration

For this demo I switched the app to SQLite. Comment the unused DB_* fields and set:

DB_CONNECTION=sqlite

Environment variables editor with DB_CONNECTION set to sqlite

Save the environment, then trigger a deploy.

Deploy Now button to trigger manual deployment

Open the deployments list to inspect the output. That’s the first place to look when something fails:

Deployments page showing deployment history and output logs

If the build fails, Forge usually emails you too.

The deploy can succeed and the site still break in the browser. Mine failed on Vite assets.

Remember we ran npm run dev in development? On the server you need a production build: npm install then npm run build.

Edit the site’s deploy script and add those at the end (Forge’s default script already runs composer install and php artisan migrate for you):

npm install
npm run build

Deploy script editor with npm install and npm run build commands added

Save the script and deploy again.

Now it works!

Successfully deployed Laravel application running in browser

Also try registering in, it will work as expected and we’ll be able to add and edit data:

Laravel application with user registration form working correctly

Nice! We’re done with deployments and Forge.

We could spend more time on this topic, but there’s so much more to explore.

We’ve seen how to create a Web Application, as simple as it could be, just a form that stores a field into a database, but complete with ready-made authentication provided by the Breeze starter kit.

We’ve seen basic routing, and models, views and controllers interact to store and retrieve data through the Eloquent ORM.

For the full learning path, go back to The Laravel Guide.

Tagged: Laravel · All topics

Want me to talk about your product? You can sponsor this site.

~~~

Related posts about laravel: