Deploy Laravel 6 utilizando a ferramenta Deployer
Aprenda a fazer o deploy da sua aplicação Laravel utilizando uma ferramenta de deploy
![Deploy Laravel 6 utilizando a ferramenta Deployer](/content/images/size/w2000/2024/03/deploy-laravel-6-utilizando-a-ferramenta-deployer.jpeg)
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 é 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:
- Configuração de um servidor web usando LEMP no Debian 9. Criando um usuário e configurando o SSH
- Aprenda a configurar um servidor web usando LEMP no Debian 9. Iremos instalar o Nginx, MariaDB e PHP 7.2
- Aprenda a instalação e a configuração básica de como criar um server block com o servidor web 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.
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:
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.
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+).
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.
Route::get('/', function() {
return view('welcome');
});
Para resolver, crie um controller chamado WelcomeController
e altere a rota para:
Route::get('/', 'WelcomeController@index');
No arquivo WelcomeController
, adicione no método index()
, o return para a view welcome.
<?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:
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:
dep init
Veja o retorno do comando:
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
// Project repository
set('repository', '[email protected]:username/deployer-laravel.git');
Dica importante: O repositório fica disponível através de dois endereços: [email protected]
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
// Hosts
host('production')
->hostname('[email protected]')
->port(33458)
->stage('prod')
->set('keep_releases', 6)
->set('branch', 'master')
->set('deploy_path', '/var/www/html/production-my-app');
host('homolog')
->hostname('[email protected]')
->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:
- host: é o nome que identifica aquela conexão
- hostname: usuário que será utilizado para fazer o deploy e o IP do servidor
- port: porta SSH utilizada (se a porta for a padrão 22, essa opção pode ser omitida)
- stage: um alias para o host (sempre utilize)
- keep_releases: número de versões que será mantido no servidor
- branch: branch que será utilizado ao realizar o deploy
- 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
// 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.
cd ~/projetos/deployer/blog
git init
git add .
git commit -m “Primeiro commit”
git remote add origin https://[email protected]/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.
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:
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:
# 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:
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.
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.
# 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:
# 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:
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:
# Acessando o servidor com o usuário deploy
ssh [email protected]
# 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:
- Abra sua conta do bitbucket
- Clique sobre sua foto de perfil e em Bitbucket settings
- No painel da esquerda clique em SSH Keys
- Clique no botão Add key e cole o conteúdo no campo key
- Dê um nome para identificar essa chave
- 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:
git clone [email protected]: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
namespace Deployer;
require 'recipe/laravel.php';
// Project name
set('application', 'My APP');
// Project repository
set('repository', '[email protected]: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('[email protected]')
->port(33458)
->stage('prod')
->set('keep_releases', 6)
->set('branch', 'master')
->set('deploy_path', '/var/www/html/production-my-app');
host('homolog')
->hostname('[email protected]')
->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:
![Comando dep ssh](https://aristides.dev/content/images/2024/03/dep-ssh.png)
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.
![Comando dep deploy](https://aristides.dev/content/images/2024/03/dep-deploy.png)
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
:
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.
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:
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
// 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:
![Comando dep deploy com migrations](https://aristides.dev/content/images/2024/03/dep-deploy-success.png)
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:
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!