Introduction
Deployment does not need to be hard or scary. You are a developer, and you can do it yourself. There are many ways of deploying a Laravel application, including multiple commercial offerings that make it much easier to deploy an application. In this article, I will show you how you can easily deploy your Laravel application to any server using a Dokku.
You will learn to create a database, create a Redis database, set up a Laravel app, link a domain to the app, secure the domain with Let's Encrypt, start a queue worker, and horizon.
First, why would you consider deploying an application yourself? You could do so to control your infrastructure, security, and performance, avoid vendor lock-in and ensure your code and data are portable across platforms, reduce costs, and save on costs.
About Dokku
Dokku is an open-source Platform as a Service (PAAS) alternative to Heroku. Docker powers it, and it is stable enough for production apps. Dokku assists in setting up applications, creating databases, linking domains, configuring web servers, securing domains with SSL, handling deployment, and scaling applications. These are standard actions, and Dokku automates them to save time.
There is no benefit in reinventing the wheel. With Linux knowledge, we could set up everything ourselves, but there is no benefit in reinventing the wheel. Once you set up the environment, all you will need to do is push code via git, and Dokku will zero-downtime deploy the application. Learn more from the Dokku website.
Prerequisites
To deploy a Laravel application with Dokku, you will need the following:
- The Laravel application that you want to deploy. The application must be version-controlled using the Git system.
- Server with a minimum of 1GB and either AMD64 (x86_64) or ARMV8 (arm64) architectures. You can get one from Digital Ocean using my referral link.
- A fresh installation of Ubuntu 20.04/22.04/24.04 or Debian 10+ x64 operating system. In this guide, we will use
Ubuntu
, my favourite. - You will need an SSH key on the computer you want to deploy from. There are many guides available on how to create an SSH key.
Step 1 of 9: Setup Dokku
The first step involves installing Dokku on the server. To do so, you will need a Username, IP Address and Password (optional). If you have not setup up SSH key on the server, you must copy the SSH keys to servers else you can skip this command
The ssh-copy-id command logs into the server host, copies keys to the server, and configures them to grant access by adding them to the authorized_keys file. The copying may ask for a password
or other authentication for the server.
When your server ssh key is set up, log in into the server:
Once logged in, start by making sure your server packages are up-to-date. Updating the packages is essential to ensure system security, stability, and access to the latest features and bug fixes.
After that, install the latest stable version of Dokku. The version could be different.
The installation may take 5-10 minutes, depending on your internet connection. You could use the time for a coffee break.
The last step in Dokku installation is to allow the listed keys to access the Dokku instance as the admin user via SSH. Without this, you cannot push your code to the Dokku in the server.
Once installed, you should verify the installation:
shell dokku version
shell dokku version 0.35.5
Here is a video demonstrating the entire Dokku setup process on Ubuntu.
Step 2 of 9: Setup a Database
To setup your application database, install the respective Dokku plugin. You can use MariaDB, PostgreSQL or MySQL.
SSH into your server and install the database plugin of your choice. We will use PostgreSQL in this guide, but you can use MariaDB or MySQL.
Next, we create a postgres database for the application, let's call it laravel-postgres
.
Within a few minutes, the postgres:create
will spin up a new postgres container
and create a database
with a user
with a secure password
. When the command is finished, you will see the database information, including DATABASE_URL,
local storage folder,
and other information.
Since the container data is temporary, the plugin will store database data in the /var/lib/dokku/services/postgres/laravel-postgres
directory on the server. That way, your database data will remain intact even if the container is detected. You can view the database information by running the info command.
In the output, note the Dsn
field. This is the database connection string that we will inject into our Laravel application and connect to the database.
At this point, the database is ready for use. You can verify it by entering and interacting with the database inside the container using the psql
command.
If you wish to access the database from outside the container, you can expose the port to the host.
If you expose the port to the host, ensure you add a new
firewall rule
to allow access to the database from outside the container. e.g. a firewall rule that allows access from a specific IP address.
Here is a video demonstrating the process of setting up Postgres using Dokku.
Step 3 of 9: Setup a Redis
To improve the performance of the Laravel application and power horizon, we will use Redis. We start by installing the Redis plug-in for Dokku.
Next, we create a Redis instance for the application; let's call it laravel-redis
.
Within a few minutes, the redis:create
will spin up a new redis container
and create a secure password
. When the command is finished, you will see the database information, including REDIS_URL,
data storage folder,
and other information.
Since the container data is temporary, the plugin will store database data in the /var/lib/dokku/services/redis/laravel-redis
directory. You can view the database information by running the info command.
In the output, note the Dsn
field. This is the database connection string that we will inject into our Laravel application and connect to the database.
At this point, the redis is ready for use. You can verify it by entering and interacting with the redis inside the redis container using the redis-cli
command.
If you wish to access the redis database from outside the container, you can expose the port to the host.
If you expose the port to the host, ensure you add a new
firewall rule
to allow access to the redis from outside the container. e.g. a firewall rule that allows access from a specific IP address.
Here is a video demonstrating Redis's entire setup process using Dokku.
Step 4 of 9: Create Laravel App
Creating a new Laravel application is as simple as running dokku apps:create
command. Let's call our app laravel-app
.
Next we need to link postgres database to the app. Linking ensure that 'DATABASE_URL' environment variable is available to the laravel app.
Next we need to link redis database to the app. Linking ensure that 'REDIS_URL' environment variable is available to the laravel app.
Linking is simply a way of networking the database container to the app container in a network. This way, the app can access the database in a secure network.
Now that we hav setup DATABASE_URL
and REDIS_URL
environment variables, we can set the remaining environment variables..
Generate the laravel application key locally using
php artisan key:generate --show
We are using config:set
because we will not have a chance to create a .env
file as you may be used to in Laravel. You can set as many environment variables as you want. Confirm that the environment variable has been set by displaying all the app environment variables.
shell dokku config:show laravel-app
At this point, the dokku laravel-app
us ready for your code
Step 5 of 9: Prepare the Laravel Application
To deploy a Laravel application with Dokku, we need to make a few changes.
5.1 Rename DB_URL
to DATABASE_URL
Start by opening /config/database.php
and renaming DB_URL
to DATABASE_URL
. This ensures that the Laravel can connect to the database.
5.2 Create a Dockerfile
Next, we need to create a Dockerfile
at the application's root. Dokku uses this file to build the application's image.
Dokku support other build methods that do not require a
Dockerfile
. However, I preferDockerfile
as it gives us more control over the build process.
We will use Serversideup PHP docker images. These images are built on top of the official PHP docker images. They are production-ready, high-performing, customizable, available in multiple flavours, and open source. However, you are free to use any image you want.
Here is a custom Dockerfile
that I usually use. It includes the additional step of installing NodeJS and building the application. You can remove the node part if you don't need it.
I recommend you consider a container that has a web server such as unitd, nginx + php-fpm, or apache + php-fpm. You can use any of them. I am using unitd because it is lightweight, high performing and reliable.
5.3 Create a Procfile
Next we need to create a Procfile
at the root of the application. This file is used by Dokku to start the application.
Then we need to specify the command to run the application in the Procfile
.
Dokku app run on a container. Replace
/var/www/html/
with the path to your Laravel application.
Let me explain what each command does:
web
: A mandatory command to start the application. In this case weunitd --no-daemon
to start a dynamic application server for our Laravel application. If you are using other web servers, the command will be different. e.g.php-fpm
,horizon
: This is the command to start the horizon worker. If you are not using horizon, you can remove this command and replace it withphp /var/www/html/artisan queue:work --tries=3
.scheduler
: This is the command to start the scheduler worker.websocket
: This is the command to start the websocket worker for handling websocket connections. If you are not using revert, replace with the right command.release
: This is not a process. It is a command that is executed after the laravel-app's docker image is built, but before any containers are scheduled.
You can ignore horizon
, scheduler
and websocket
if you do not need them. Dokku will spin up a container for each of the services as we will see later.
5.4 Create a app.json
file (optional)
Finally in the app preparation step, we will create a app.json
file. This file is used by dokku to configure the application. app.json
is not mandatory, but it is useful for configuring dokku.
For example, to ensure that Dokku performs zero downtime deployments
, we need to specify the healthchecks
points for our processes. When Dokku health checks pass, the respective container will be deployed, and the old container will be shut down in 60s. If it fails, the application will not be deployed, and the old container will be kept running.
Make sure you commit the changes.
Step 6 of 9: Your First Deployment
Dokku allow you to push code straight from your repository to the server. To do so, you need to add a remote to your git repository.
shell git remote add dokku dokku@IP_ADDRESS:laravel-app git remote -v
If there was no error, the application was deployed successfully. But not accessible yet. Let's fix that.
Step 7 of 9: Add a domain to the app
We need to be able to access the application from the internet. To do so, we need to add a domain to the app. Navigate to your domain provider and point the domain to the IP address of the server using an A record
.
If you use Cloudflare like me, turn off the DNS-only
option. Else, you may not be able to add a free ssl certificate later.
In this case, I will point subdomain, demo.artisanelevated.com
to the IP address (159.89.171.252)
of the server.
Next we expose the laravel application port to the host so that nginx can proxy requests to it.
shell dokku ports:add laravel-app http:80:8080
shell dokku domains:add laravel-app demo.artisanelevated.com dokku domains:set laravel-app demo.artisanelevated.com
At this point, you should be able to access the application at http://your-domain.com
. But the application is not secured. Let's secure it.
Step 8 of 9: Secure the domain with Let's Encrypt
Now that we have a domain working, we need to secure it with Let's Encrypt. Start by installing the lets encrypt plugin for dokku.
Next we enable the lets encrypt plugin for the domain. We will need an email for that.
Finally we activate a cron job to renew the certificate before it expires.
At this point, you should be able to access the application with a secure domain https://your-domain.com
.
If you are using Cloudflare, you can no turn on the orange proxy option and enable strict ssl option.
Step 9 of 9: Start horizon, reverb and scheduler (Optional)
If you application requires horizon or reverb or scheduler, you can start them. To do so, you need to SSH into the server and start the services.
Make sure you have updated the
Procfile
with the correct commands. You only need to start the services once and dokku will take care of the rest in the subsequent deployments.
shell # Create one (1) scheduler container dokku ps:scale laravel-app scheduler=1
shell # Create one (1) horizon container dokku ps:scale laravel-app horizon=1
shell # Create one (1) reverb container dokku ps:scale laravel-app reverb=1
You can also scale the number of workers for the queues. For example, to scale the
web
process to2
workers, rundokku ps:scale laravel-app web=2
. You now have two workers running for the web process. That how easy it is to scale your dokku applications.
With that done, you have your processes running. When you push code to the server, all the containers will be deployed and started.
You can verify that the containers are running by running the following command.
If you deploy reverb, you will need to expose port
8080
and add a new websocket domain to the app.
Conclusion
I hope you have learned how easy it is to deploy your Laravel application to the Internet. Using this Dokku to deploy Laravel applications is inexpensive, developer-friendly, and maintainable. Using this knowledge, you can create a staging application for testing. To avoid making this article too long, I did not cover other topics that you should consider researching. These include:
- Backing up Postgres and Redis on S3 compatible object storage.
- Integrating a Dokku CI - GitHub Actions and GitLab CI.
- Mounting storage to the app e.g the laravel storage directory.
- How to manage server ports with
ufw
. - How to debug errors using logs.
If there is any part of this article that is not clear to you, feel free to leave a comment. I will improve it.
Have a look at the source code of this article.
Do you need help deploying your Laravel application? Contact me and we can work it out.