Laravel Horizon with Nginx and Ubuntu 18.04 on DigitalOcean
Tags: php, laravel, nginx, digitalocean
Published: 2019-05-28 19:27:20

---
title: Laravel Horizon with Nginx and Ubuntu 18.04 on DigitalOcean
published: true
description: This is just to share my experience of configuring and deploying a Laravel application on an Ubuntu Server on DigitalOcean droplet
tags: php, laravel, nginx, digitalocean
---
I had been working with an eCommerce SaaS application a few months ago. Parts of it is built with Laravel 5 and the application is hosted on DigitalOcean on an Ubuntu Server. It's not yet in production but still the setups are pretty much the same. My specific server environment was an Ubuntu 18.04 OS, Nginx 1.14 web server and PHP 7.2

This application has many queued and scheduled tasks to handle. Many tasks had been made automated using Laravel's Scheduler and all the mailing jobs are queued. I used a very handy tool from Laravel called Horizon to monitor and maintain the queues, schedules and events. My intention here is to document the procedure I followed to setup the environment and how I made it work properly.

I am not going to get in details of deploying a laravel project on DigitalOcean droplet. I am diving straight in Horizon setup and it will work for any version of laravel greater than 5.4. I used `redis-server` as laravel's queue management storage.


### Step 1: Installing Redis Server on Ubuntu 18.04
---

First of all we have to ssh into our DigitalOcean droplet and after successful login we will get root access to our Ubuntu server.

We have to use the following commands to install Redis 
```bash
$ apt-get update
$ apt-get upgrade
$ apt-get install redis-server
$ systemctl enable redis-server.service
```

Redis can be started without a configuration file using a built-in default configuration. But to make any extra parameter changes we can use its configuration file that is: `/etc/redis/redis.conf`. We have to edit the Redis configuration file in a text editor to make changes

```bash
$ vim /etc/redis/redis.conf
```

The above configuration tells Redis to remove any key using the LRU algorithm when the max memory of 256mb is reached. Save the configuration file and restart the Redis service:

```bash
$ systemctl restart redis-server.service
```

Use redis-cli tool to verify the connection between Redis server and redis-cli.

```bash
$ redis-cli

127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
```


### Step 2: Installing Predis for using Redis with Laravel
---

Before using Redis with Laravel, you will need to install the `predis/predis` package via Composer:

```bash
$ composer require predis/predis
```

After `predis` is installed we have to configure it for our application. The configuration file for redis is located in the `config/database.php` configuration file. Within this file, you will see a `redis` array containing the Redis servers utilized by your application:

```php
/* config/database.php file */
'redis' => [

    'client' => 'predis',

    'default' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_DB', 0),
    ],

    'cache' => [
        'host' => env('REDIS_HOST', '127.0.0.1'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => env('REDIS_CACHE_DB', 1),
    ],

],
```

### Step 3: Installing Horizon
---

We have to use `composer` to intall Laravel Horizon.

```bash
$ composer require laravel/horizon
```
After installing Horizon, publish its assets using the horizon:install Artisan command:

```bash
$ php artisan horizon:install
```
We should also create the failed_jobs table which Laravel will use to store any failed queue jobs:

```bash
$ php artisan queue:failed-table
$ php artisan migrate
```
Horizon's primary configuration file will be located at  `config/horizon.php`. This configuration file allows us to configure our worker options and each configuration option includes a description of its purpose. In the file we must define connection as `redis`.

```php
/* config/horizon.php file */
'environments' => [
        'production' => [
            'supervisor-1' => [
                'connection' => 'redis',
                'queue' => ['default'],
                'balance' => 'simple',
                'processes' => 10,
                'tries' => 3,
            ],
        ],

        'local' => [
            'supervisor-1' => [
                'connection' => 'redis',
                'queue' => ['default'],
                'balance' => 'simple',
                'processes' => 3,
                'tries' => 3,
            ],
        ],
    ],
```
Now Horizon is installed. We have to start horizon with an Artisan command and keep the command running to be able to use horizon to process queues at this point. To do that navigate to project root and run:

```bash
$ php artisan horizon
```
After Horizon is run we can find it on `http://project.link/horizon`. We will see a dashboard page like below:

![Horizon](https://res.cloudinary.com/dtfbvvkyp/image/upload/v1537195039/photos/Test.png)

### Step 4: Dashboard Authorization
---

But this will work only in `local` environment of the application. To use it in production we have to add `dashboard authorization` to it so that no one can access the page without logging in. Within the  `app/Providers/HorizonServiceProvider.php` file, there is a gate method. This authorization gate controls access to Horizon in non-local environments. You are free to modify this gate as needed to restrict access to your Horizon installation:

```php
/**
 * Register the Horizon gate.
 *
 * This gate determines who can access Horizon in non-local environments.
 *
 * @return void
 */
protected function gate()
{
    Gate::define('viewHorizon', function ($user) {
        return in_array($user->email, [
            'admin@application.com',
        ]);
    });
}
```
This will allow the user with the email `admin@application.com` to access `/horizon` route and use horizon.

### Step 5: Automate Horizon 
---

If we are deploying Horizon to a live server, we should configure a process monitor to monitor the php artisan horizon command and restart it if it quits unexpectedly. When deploying fresh code to our server, we will need to instruct the master Horizon process to terminate so it can be restarted by your process monitor and receive your code changes. To handle that we will need `supervisor`. To install `supervisor` :

```bash
$ apt-get install supervisor
```
After installation is complete we have to run the following command to run `supervisor` at startup.

```bash
$ systemctl enable supervisord
```
Now we have to create a new file in `/etc/supervisor/conf.d/` named `horizon.conf` and add the below configuration:

```bash
[program:horizon]
process_name=%(program_name)s
command=php /full/path/to/our/application/artisan horizon
autostart=true
autorestart=true
user=root
redirect_stderr=true
stdout_logfile=/full/path/to/our/application/horizon.log

```
Now to read and reload the config and restart the process we have to run the below commands:

```bash
$ supervisorctl reread
$ supervisorctl update
$ supervisorctl start horizon
```
This will setup Laravel horizon properly and make it run automatically on the server. But if some changes have been made
to the Queues or Schedules Horizon must be restarted to make those change take effect on the server. To do that navigate to project root and run:

```bash
$ php artisan horizon:terminate
```
These were pretty much the steps I followed to setup Laravel Horizon on Ubuntu 18.04 server on a DigitalOcean droplet. Hope this guide will help some of you to easily accomplish the task and be more productive.