# Deploy Laravel 6 utilizando a ferramenta Deployer

Fala pessoal tudo beleza?

Mais um artigo hoje, no formato tutorial. Nesse artigo aprenderemos como fazer o deploy de uma aplicação desenvolvida com o Laravel, usando uma ferramenta de deploy.

## Deployer

O [Deployer](https://deployer.org/?ref=aristides.dev) é uma ferramenta desenvolvida em PHP e que faz todo o trabalho pesado em realizar o deploy da sua aplicação PHP, seja usando um framework ou não.

Todos os passos a seguir, foram executados usando o sistema operacional Linux.

Pré requisitos:

* Conta no Bitbucket (ou em outro repositório git)
    
* Uma VPS (estou usando a Digital Ocean)
    
* Servidor com Nginx, PHP e Mysql instalados
    
* Node e NPM instalados no servidor
    
* Acesso root (ou sudo) ao servidor via SSH
    

Te indico a leitura de 3 artigos do meu blog que pode te ajudar em caso de alguma dúvida de alguns tópicos desse tutorial, são eles:

1. [Configuração de um servidor web usando LEMP no Debian 9. Criando um usuário e configurando o SSH](https://aristides.dev/configurando-um-servidor-lemp-debian-9-parte-1)
    
2. [Aprenda a configurar um servidor web usando LEMP no Debian 9. Iremos instalar o Nginx, MariaDB e PHP 7.2](https://aristides.dev/configurando-um-servidor-lemp-debian-9-parte-2)
    
3. [Aprenda a instalação e a configuração básica de como criar um server block com o servidor web Nginx](https://aristides.dev/configurando-virtual-host-no-nginx)
    

Serão criados dois ambientes, de produção e homologação. Para acessarmos a aplicação, nesse tutorial iremos utilizar o IP do servidor, mas caso queira pode ser usado um domínio válido e configurado. Por exemplo, caso esteja usando um domínio, crie um subdomínio com o prefixo homolog.seusite.com.br. Esse será o endereço para o ambiente de homologação, e o seusite.com.br o endereço de produção.

Para o meu caso, irei usar o IP e definir as portas para diferenciar os ambientes, por exemplo, a porta 80 para produção e 81 para homologação.

## Instalando o Deployer

A instalação deve ser feita na máquina de desenvolvimento. Para isso digite os 3 comandos abaixo em seu terminal.

```bash
curl -LO https://deployer.org/deployer.phar
mv deployer.phar /usr/local/bin/dep
chmod +x /usr/local/bin/dep
```

No comando acima, é feito o download do arquivo `deployer.phar` e em seguinda movemos o arquivo para o diretório `/usr/local/bin` renomeando para `dep`, e para finalizar concedemos permissão de execução para o arquivo.

Para testar o deployer, execute no seu terminal o comando:

```bash
dep --version
```

Se aparecer a versão do Deployer, sucesso!

## Instalando o Laravel

Nesse exemplo iremos baixar uma aplicação Laravel usando o composer. Não terá nenhuma regra de negócio na aplicação, apenas irei criar a autenticação padrão do Laravel e uma implementação a mais para que o deploy funcione corretamente.

```bash
mkdir -p ~/projetos/deployer/
cd ~/projetos/deployer
composer create-project --prefer-dist laravel/laravel blog
```

Com o projeto criado, entre no diretório da aplicação e execute os comandos abaixo para criar a autenticação padrão do Laravel 6 (Esse passo é somente para o Laravel 6+).

```bash
cd blog
composer require laravel/ui --dev
php artisan ui vue --auth
npm install && npm run dev
```

Para que esse exemplo funcione, é necessário criar um controller e alterar a rota barra `/` do Laravel. Durante o deploy é executado o comando `artisan config:cache`, e esse comando não funciona se existir uma rota que esteja usando uma função anônima, conhecida também como *closure*, ou seja, a rota inicial do Laravel utiliza uma função anônima.

```php
Route::get('/', function() {
    return view('welcome');
});
```

Para resolver, crie um controller chamado `WelcomeController` e altere a rota para:

```php
Route::get('/', 'WelcomeController@index');
```

No arquivo `WelcomeController`, adicione no método `index()`, o return para a view welcome.

```php
<?php

namespace App\Http\Controllers;

class WelcomeController extends Controller
{
    public function index()
    {
        return view('welcome');
    }
}
```

No arquivo de rotas da API `routes/api.php` também existe uma função anônima, nesse caso basta remover a rota que o problema é resolvido.

Até esse momento temos nossa aplicação Laravel funcionando e com a autenticação padrão gerada, apenas faltando a conexão com o banco de dados, mas agora não será preciso se preocupar com isso. Vamos fazer isso mais para frente.

## Conhecendo o Deployer

Antes de começar com o deployer, vamos conhecer alguns de seus comandos. Digite no terminal:

```bash
dep list
```

Você verá os comandos disponíveis e dentre eles existe o comando `init`. Essa opção criará o template inicial de uma configuração, é possível também passar um parâmetro informando qual template gostaria de usar. Vamos ver na prática o comando `dep init`.

Dentro do diretório do seu projeto, digite o comando abaixo:

```bash
dep init
```

Veja o retorno do comando:

```bash
Welcome to the Deployer config generator
This utility will walk you through creating a deploy.php file.
It only covers the most common items, and tries to guess sensible defaults.

Press ^C at any time to quit.

Please select your project type [Common]:
[0 ] Common
[1 ] Laravel
[2 ] Symfony
[3 ] Yii
[4 ] Yii2 Basic App
[5 ] Yii2 Advanced App
[6 ] Zend Framework
[7 ] CakePHP
[8 ] CodeIgniter
[9 ] Drupal
[10] TYPO3
>
```

O resultado desse comando é uma lista de **Tipos de Projeto** disponíveis para o uso, o padrão é uma aplicação Common, que seria uma aplicação comum em PHP, sem o uso de frameworks.

Selecione a opção 1 para escolher o template Laravel. Em seguida será solicitado que informe o repositório de onde está seu projeto, apenas dê enter, iremos configurar depois. Em seguida ele pergunta se deseja contribuir com a ferramenta enviando informações anônimas, escolha sim ou não.

Finalizado esses passos, veja que no diretório raiz da sua aplicação foi criado um arquivo chamado `deploy.php`.

*Dica: Podemos criar o mesmo arquivo deploy.php informando o parâmetro -t seguido do nome do template. Veja como ficaria para nosso exemplo:* `dep init -t Laravel`

## Configurando o Deployer

Abra o arquivo `deploy.php` criado na raiz do seu projeto e vamos brincar um pouco.

No trecho abaixo, informamos o endereço do repositório onde a aplicação se encontra. Caso você não tenha essa url ainda, no tópico Versionando a aplicação eu falo sobre isso, deixe como está nesse momento, depois basta atualizar essa informação.

```php
<?php

// Project repository
set('repository', 'git@bitbucket.org:username/deployer-laravel.git');
```

Dica importante: O repositório fica disponível através de dois endereços: `git@bitbucket.org` e `https://username@bitbucket`. Existem diferenças entre eles, para que a primeira opção funcione é necessário ter cadastrado a chave pública do SSH no Bitbucket. Na segunda opção é necessário informar a senha para cada requisição realizada.

Na próxima configuração, definimos o host da aplicação, podemos ter um, dois ou mais hosts configurados. Nesse exemplo criaremos dois, de produção e homologação.

```php
<?php

// Hosts
host('production')
    ->hostname('deploy@174.138.55.236')
    ->port(33458)
    ->stage('prod')
    ->set('keep_releases', 6)
    ->set('branch', 'master')
    ->set('deploy_path', '/var/www/html/production-my-app');

host('homolog')
    ->hostname('deploy@174.138.55.236')
    ->port(33458)
    ->stage('hml')
    ->set('keep_releases', 3)
    ->set('branch', 'develop')
    ->set('deploy_path', '/var/www/html/homolog-my-app');
```

O código em si é bem simples de entender, mas vou explicar o que cada linha significa:

1. **host**: é o nome que identifica aquela conexão
    
2. **hostname**: usuário que será utilizado para fazer o deploy e o IP do servidor
    
3. **port**: porta SSH utilizada (se a porta for a padrão 22, essa opção pode ser omitida)
    
4. **stage**: um alias para o host (sempre utilize)
    
5. **keep\_releases**: número de versões que será mantido no servidor
    
6. **branch**: branch que será utilizado ao realizar o deploy
    
7. **deploy\_path**: diretório onde se encontra a aplicação
    

O parâmetro stage eu recomendo utilizar porque utilizando o stage com a opção abaixo, o `default_stage`, quer dizer que sempre ao realizar um deploy (sem informar o host como parâmetro) será realizado em homologação, assim evitando que seja feito deploy para produção sem querer.

```php
<?php

// Stage default
set('default_stage', 'hml');
```

O restante das informações são bem auto explicativas, caso tiver com dúvidas deixe sua pergunta nos comentários, e não deixe de olhar a documentação do deployer, vale a pena.

## Versionando a aplicação

Crie um repositório no bitbucket e copie a url do seu repositório, com essa url você poderá atualizar o arquivo deploy.php conforme mencionei no tópico anterior.

Dentro do diretório do seu projeto, vamos utilizar o git para versionar e enviar para o bitbucket.

```bash
cd ~/projetos/deployer/blog
git init
git add .
git commit -m “Primeiro commit”
git remote add origin https://username@bitbucket.org/username/deployer-laravel.git
git push -u origin master
```

Acabamos de enviar para o repositório nossa aplicação.

## Branch develop

Vamos criar um branch chamado `develop`, que será nosso branch de homologação. Também iremos enviar para o bitbucket.

```bash
git checkout -b develop
git push -u origin develop
```

Pronto! Até o momento temos nossa aplicação Laravel versionada no Bitbucket com dois branchs (master e develop).

## Criando banco de dados e usuário Mysql

Agora os passos a seguir serão executados no servidor.

Acesse o servidor via SSH para criarmos o banco de dados da nossa aplicação. Digite no terminal os comandos abaixo para criar o banco:

```bash
mysql -uroot -psenha
CREATE DATABASE laravel;
CREATE USER 'deployer'@'localhost' IDENTIFIED BY 'senhaforteaqui';
GRANT ALL PRIVILEGES ON laravel . * TO 'deployer'@'localhost';
FLUSH PRIVILEGES;
```

Pronto, criamos nosso banco de dados chamado laravel e criamos também um usuário com todos os privilégios para que possamos conectar no banco.

## Configurando usuário deploy

Ainda logado no servidor, crie um usuário shell que será responsável em realizar o deploy da sua aplicação:

```bash
# Informe uma senha forte
adduser deploy

# Adicionando o deploy no grupo www-data
usermod -aG www-data deploy
```

## Diretório WEB

Ainda no servidor, vamos criar dois diretórios que irão hospedar nossa aplicação web e alterar o dono para o usuário deploy. Digite os seguintes comandos:

```bash
mkdir -p /var/www/html/production-my-app
mkdir -p /var/www/html/homolog-my-app
chown deploy:deploy /var/www/html/production-my-app
chown deploy:deploy /var/www/html/homolog-my-app
```

## Configurando arquivo host do Nginx

Entre no diretório de configuração de sites do nginx e crie dois arquivos de configuração.

```bash
cd /etc/nginx/sites-available
touch production.conf homolog.conf
```

Agora copie e cole o conteúdo abaixo dentro do arquivo `production.conf`.

Lembre-se de alterar as informações referente ao seu host, por exemplo o IP e a porta caso necessário.

```nginx
# Arquivo production.conf
server {

    listen 80;
    listen [::]:80;       

    server_name 174.138.55.236;

    # Log
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # Directory root
    root /var/www/html/production-my-app/current/public;
    index index.php index.html;

    client_max_body_size 128M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # pass PHP scripts to FastCGI server
    location ~ \.php$ {
        # Note que aqui definimos a versao que iremos utilizar do PHP
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        include /etc/nginx/fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
    }

    # deny access to .htaccess files
    location ~ /\.ht {
        deny all;
    }

    location ~ /\.well-known {
        allow all;
    }

    # Set header expirations on per-project basis
    location ~* \.(?:ico|css|js|jpe?g|JPG|png|svg|woff)$ {
        expires 365d;
    }
}
```

Abra o arquivo `homolog.conf` e cole o conteúdo abaixo:

```nginx
# Arquivo homolog.conf
server {

    listen 81;
    listen [::]:81;       

    server_name 174.138.55.236;

    # Log
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    # Directory root
    root /var/www/html/homolog-my-app/current/public;
    index index.php index.html;

    client_max_body_size 128M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # pass PHP scripts to FastCGI server
    location ~ \.php$ {
        # Note que aqui definimos a versao que iremos utilizar do PHP
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        fastcgi_index index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        include /etc/nginx/fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
    }

    # deny access to .htaccess files
    location ~ /\.ht {
        deny all;
    }

    location ~ /\.well-known {
        allow all;
    }

    # Set header expirations on per-project basis
    location ~* \.(?:ico|css|js|jpe?g|JPG|png|svg|woff)$ {
        expires 365d;
    }
}
```

Ative os dois sites que acabamos de configurar:

```bash
ln -s /etc/nginx/sites-available/production.conf /etc/nginx/sites-enabled/
ln -s /etc/nginx/sites-available/homolog.conf /etc/nginx/sites-enabled/
service nginx restart
```

Pronto. Arquivos vhost do nginx configurados. Se você tentar acessar agora, não funcionará, pois ainda falta realizar o deploy da aplicação, calma que vamos chegar lá.

## Configurando chaves SSH no Bitbucket

Para que o deploy funcione sem a necessidade de informar a senha, vamos criar uma chave SSH para o usuário deploy.

Logue no servidor com o usuário deploy criado neste tutorial e digite o comando:

```bash
# Acessando o servidor com o usuário deploy
ssh deploy@174.138.55.236

# Gerar chaves SSH
ssh-keygen
```

Confirme as informações, quando solicitar uma senha, não é necessário informar, apenas dê enter até finalizar.

Será gerado dois arquivos em `/home/deploy/.ssh` chamado `id_rsa` (chave privada) e `id_rsa.pub` (chave pública).

Copie todo o conteúdo do arquivo `id_rsa.pub` e siga os passos:

1. Abra sua conta do bitbucket
    
2. Clique sobre sua foto de perfil e em Bitbucket settings
    
3. No painel da esquerda clique em SSH Keys
    
4. Clique no botão Add key e cole o conteúdo no campo key
    
5. Dê um nome para identificar essa chave
    
6. Clique em Add key para salvar as informações
    

Nesse ponto a comunicação do servidor e bitbucket já pode ser feita através das chaves SSH de maneira segura e sem a necessidade de informar uma senha.

Apenas para efeito de teste, vamos clonar nosso repositório no servidor. Copie a url do repositório que pode ser obtida no próprio repositório, e dentro do diretório /home/deploy (no servidor) cole a url do repositório e dê enter:

```bash
git clone git@bitbucket.org:username/deployer-laravel.git
```

Irá aparecer uma mensagem para que confirme o host e que seja adicionado na lista de hosts confiáveis, informe yes para continuar.

Sucesso. Seu repositório foi clonado.

## Ufa, chegamos no deploy!

Bom, vamos ver como ficou o nosso arquivo de deploy? Após nossas configurações o arquivo deve estar parecido com esse:

```php
<?php

namespace Deployer;

require 'recipe/laravel.php';

// Project name
set('application', 'My APP');

// Project repository
set('repository', 'git@bitbucket.org:username/deployer-laravel.git');

// [Optional] Allocate tty for git clone. Default value is false.
set('git_tty', true);

// Shared files/dirs between deploys
add('shared_files', []);
add('shared_dirs', []);

// Writable dirs by web server
add('writable_dirs', []);

// Stage default
set('default_stage', 'hml');

// Hosts
host('production')
    ->hostname('deploy@174.138.55.236')
    ->port(33458)
    ->stage('prod')
    ->set('keep_releases', 6)
    ->set('branch', 'master')
    ->set('deploy_path', '/var/www/html/production-my-app');

host('homolog')
    ->hostname('deploy@174.138.55.236')
    ->port(33458)
    ->stage('hml')
    ->set('keep_releases', 3)
    ->set('branch', 'develop')
    ->set('deploy_path', '/var/www/html/homolog-my-app');

// Tasks

task('npm_run', function () {
    // Descomente esse if após o primeiro deploy
    //if (has('previous_release')) {
    //    run('cp -R {{previous_release}}/node_modules {{release_path}}/node_modules');
    //}

    run('cd {{release_path}} && npm install');
    run('cd {{release_path}} && npm run prod');
});

// [Optional] if deploy fails automatically unlock.
after('deploy:failed', 'deploy:unlock');

// Migrate database before symlink new release.

// Descomente essa linha após o primeiro deploy
// before('deploy:symlink', 'artisan:migrate');
```

Um detalhe muito importante para fazermos antes do primeiro deploy é comentar a última linha, ela é responsável em executar a migrate, se fizermos o deploy com a migrate sem antes configurar o arquivo .env no servidor, irá dar erro de conexão com o banco de dados e isso é fato.

Mais um teste rápido antes de iniciar, dentro do seu projeto local, digite no terminal o comando dep ssh:

![Executar login SSH no servidor](https://cdn.hashnode.com/res/hashnode/image/upload/v1735045549579/036f6826-6951-4f65-bbc2-ac49dada1fb8.png align="left")

Executar login SSH no servidor

Viu que bacana? O deployer identificou que foi configurado dois hosts e ele te deu a opção de escolher em qual host deseja conectar via SSH. Informei o host de homologação e ele realizou o login no servidor.

A mensagem de erro dizendo que o diretório `current` não existe é normal, pois ainda não realizamos o deploy e a estrutura de diretórios que a ferramenta de deploy cria, não existe no momento.

Chega de enrolação, bora fazer esse deploy. Se ainda continua logado no servidor, digite `exit` para sair e voltar para sua máquina. Dentro do diretório do seu projeto digite o comando `dep deploy`. Veja que não passamos nenhum parâmetro, nesse caso o deploy será realizado no host de homologação.

![Realizando o deploy da aplicação](https://cdn.hashnode.com/res/hashnode/image/upload/v1735045528004/fc5b78f0-20cf-4f4f-9f5c-46be9a787de1.png align="left")

Realizando o deploy da aplicação

Agora precisamos configurar o arquivo `.env`, se tentar acessar o endereço IP na porta 81 irá receber um erro 500.

Logando no servidor através do comando `dep ssh`, dentro do diretório current de homologação (diretório atual quando se faz login usando o `dep ssh`), se abrirmos o arquivo `.env` verá que está em branco. Copie o conteúdo do arquivo `.env.example` para `.env`:

```bash
cp .env.example .env
```

Agora abra o .env e adicione as informações de acesso ao Mysql que criamos no início do tutorial. Salve as alterações e saia do arquivo.

```bash
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=deployer
DB_PASSWORD=senhaforteaqui
```

É necessário gerar a chave de segurança do artisan para que a aplicação funcione corretamente, execute os comandos:

```bash
php artisan config:clear
php artisan key:generate
```

Nesse momento sua aplicação deve estar funcionando, acesse seu endereço IP na porta 81 e verifique se a página inicial do Laravel irá aparecer. Se não deu certo, verifique o log do Laravel para identificar o problema.

Vamos continuar pois ainda não acabou. Agora que configuramos nosso arquivo .env com as informações de acesso ao Mysql, vamos executar o deploy novamente agora com a opção de executar a migrate. Lembra que comentamos a linha responsável em executar a migrate, vamos descomentar esse linha e aproveite para descomentar a linha da tarefa do `npm_run`, ficando assim:

```php
<?php

// Descomente o if da tarefa npm_run
if (has('previous_release')) {
    run('cp -R {{previous_release}}/node_modules {{release_path}}/node_modules');
}

// Descomente o artisan migrate
before('deploy:symlink', 'artisan:migrate');
```

Ou seja, antes da tarefa symlink, será executado as migrations. Vamos executar o deploy novamente:

![Deploy da migration realizado com sucesso](https://cdn.hashnode.com/res/hashnode/image/upload/v1735045496533/6f054aee-5ce9-4c26-91a3-6644d3e3604a.png align="left")

Deploy da migration realizado com sucesso

Veja que lindo que foi o resultado. Foi executada uma tarefa nova agora, a tarefa responsável em criar as migrations, veja a linha `artisan:migrate` no log acima.

Bom, agora se você acessar sua aplicação e realizar o cadastro de um usuário verá que funcionará lindamente.

## Deploy em produção

Configuramos o deployer para que seja feito em dois ambientes, em homologação e produção. Ao executar o comando dep deploy é feito o deploy em homologação. Para que seja feito em produção é necessário informar um parâmetro a mais no comando, veja:

```bash
dep deploy prod
```

O prod na frente do comando vem do stage definido no arquivo deploy.php. Agora que você já sabe como fazer o deploy em homologação que tal fazer a mesma coisa para produção?

Execute os mesmos passos que você fez para homolog, crie um banco de dados para produção e após o primeiro deploy configure seu .env com os dados de acesso ao Mysql.

A implantação de uma ferramenta de deploy apesar de parecer simples, se torna um pouco complicado se o seu ambiente não está preparado ainda, por exemplo, as configurações essenciais do servidor como o Mysql, Nginx, PHP, etc...

Fico a disposição caso tenham alguma dúvida ou algum problema.

Até a próxima!
