Como fazer deploy de um projeto Laravel em produção (passo a passo)
Deploy & DevOps · Por Kevin Marcondes · Publicado em · Atualizado em · 7 min de leitura
Este tutorial mostra, passo a passo, como fazer deploy de um projeto Laravel em produção com Nginx, PHP‑FPM, .env seguro, migrações, filas e agendador. Você sairá com um servidor configurado, seu app rodando e uma checklist de verificação. Quando quiser automatizar, veja também CI/CD. O foco aqui é um deploy clássico em Linux, simples e direto.
Pré-requisitos e visão geral do processo
Vamos preparar servidor, instalar dependências, configurar o código com .env, otimizar o Laravel, habilitar Nginx/PHP‑FPM, aplicar migrações, subir filas (Supervisor) e o agendador (cron). Alguns passos exigem sudo/root.
Se você planeja automatizar o pipeline depois, veja o guia de CI/CD com GitHub Actions para PHP/Laravel em CI/CD com GitHub Actions.
- Servidor Linux (Ubuntu/Debian) com acesso SSH e sudo/root.
- Domínio apontado para o servidor (DNS A/AAAA).
- Git habilitado e repositório do projeto acessível.
- PHP‑FPM, Nginx e banco (MySQL/MariaDB ou PostgreSQL).
- Composer instalado; Node.js LTS se usar Vite.
- Variáveis de ambiente e segredos definidos para produção.
1) Preparar o servidor: pacotes essenciais
Atualize o sistema e instale Nginx, PHP‑FPM com extensões comuns, Composer, Git e Node.js (se for compilar assets com Vite). Execute em root ou com sudo.
Após instalar, confirme que Nginx e PHP‑FPM estão ativos. Em muitos ambientes, PHP‑FPM já cria um socket em /run/php/. Ajustaremos isso no Nginx mais adiante.
sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx php-fpm php-cli php-zip php-mbstring php-xml php-curl php-redis php-mysql php-pgsql git unzip curl
sudo apt install -y composer
# Opcional: Node.js LTS para build com Vite
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs
2) Estrutura do projeto, usuário e permissões
Crie um usuário para o deploy e diretório da aplicação em /var/www/app. O grupo www-data (ou equivalente do seu sistema) costuma rodar Nginx/PHP‑FPM. Vamos garantir que o webserver tenha acesso de leitura e que storage/ e bootstrap/cache tenham escrita.
Evite permissões 777. Mantenha 775/664 para pastas/arquivos, com dono do app e grupo do webserver.
sudo adduser --disabled-password --gecos "" deploy
sudo usermod -aG www-data deploy
sudo mkdir -p /var/www/app
sudo chown -R deploy:www-data /var/www/app
sudo chmod -R 775 /var/www/app
3) Código e configuração do Laravel (.env, migrações e otimizações)
Clone o repositório, instale dependências e gere a APP_KEY. Configure o .env para produção (APP_ENV=production, APP_DEBUG=false, DB_*, CACHE_DRIVER, SESSION_DRIVER, QUEUE_CONNECTION, LOG_CHANNEL etc.). Nunca faça commit do .env.
Aplique as migrações com --force para permitir em produção. Para boas práticas de versionamento de schema, veja Guia: versionamento de banco de dados ágil.
Por fim, crie o link de storage e faça cache de config/rotas/visões. Em mudanças de env, use optimize:clear antes de recachear.
sudo -u deploy -H bash -lc '
cd /var/www/app
# Substitua <SEU_REPO_GIT> pela URL do seu repositório (SSH/HTTPS)
git clone <SEU_REPO_GIT> .
composer install --prefer-dist --no-dev --optimize-autoloader
cp .env.example .env
php artisan key:generate
php artisan storage:link
# Ajuste o .env com credenciais reais antes de migrar
php artisan migrate --force
php artisan config:cache
php artisan route:cache
php artisan view:cache
'
# Garantir permissões de escrita no runtime
sudo chown -R deploy:www-data /var/www/app
sudo find /var/www/app/storage /var/www/app/bootstrap/cache -type d -exec chmod 775 {} \;
sudo find /var/www/app/storage /var/www/app/bootstrap/cache -type f -exec chmod 664 {} \;
4) Build de frontend (Vite) – opcional
Se o projeto usa Vite, compile os assets em modo produção. Sem build, CSS/JS podem não carregar corretamente.
Após a compilação, o Laravel usará o manifest gerado para servir arquivos estáticos. Se mudar variáveis do Vite, faça novo build.
cd /var/www/app
npm ci
npm run build
5) Nginx + PHP-FPM: configuração de produção
Crie um server block apontando para public/. Use try_files para redirecionar ao index.php. Ajuste o socket do PHP‑FPM conforme a sua versão. Ative logs dedicados do site para facilitar diagnóstico e observabilidade.
Para formatos de logs melhores em produção, veja o guia de Logs estruturados (JSON) e correlação.
sudo tee /etc/nginx/sites-available/laravel.conf > /dev/null <<'NGINX'
server {
listen 80;
server_name exemplo.com www.exemplo.com;
root /var/www/app/public;
index index.php;
access_log /var/log/nginx/laravel_access.log;
error_log /var/log/nginx/laravel_error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock; # ajuste para sua versão, ex.: /run/php/php8.2-fpm.sock
fastcgi_param PHP_VALUE "opcache.validate_timestamps=0";
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff2?)$ {
expires 7d;
access_log off;
try_files $uri $uri/ @laravel;
}
location @laravel {
rewrite ^/(.*)$ /index.php?$query_string last;
}
client_max_body_size 10M;
}
NGINX
sudo ln -s /etc/nginx/sites-available/laravel.conf /etc/nginx/sites-enabled/laravel.conf
sudo nginx -t && sudo systemctl reload nginx
6) Filas com Supervisor (queue:work resiliente)
Use o Supervisor para manter o worker de filas sempre ativo. Defina usuário, diretório e parâmetros de estabilidade (tries, timeout, max-time). Após configurar, recarregue o Supervisor e verifique o status.
Para estratégias de observabilidade em PHP (APM, traces), veja o comparativo em Observabilidade PHP.
sudo apt install -y supervisor
sudo tee /etc/supervisor/conf.d/laravel-worker.conf > /dev/null <<'SUP'
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/app/artisan queue:work --sleep=3 --tries=3 --max-time=3600 --timeout=120
autostart=true
autorestart=true
user=deploy
numprocs=2
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker.log
stopwaitsecs=600
SUP
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status
7) Agendador (cron) e verificação final do deploy
O scheduler do Laravel deve rodar a cada minuto via cron. Adicione ao crontab do usuário que executa o app. Depois, valide Nginx, faça uma requisição HTTP e confira logs/filas.
Se quiser aprofundar em recomendações oficiais, leia a documentação do Laravel sobre deployment, queues e scheduling.
Solução de problemas comuns:
- 502 Bad Gateway: socket/porta do PHP‑FPM incorretos; ajuste fastcgi_pass e verifique serviço do php-fpm.
- 500 em produção: verifique APP_KEY no .env e permissões de storage/ e bootstrap/cache.
- CSS/JS quebrados: rode npm run build e confira URLs dos assets.
- Alterou .env e nada mudou? Rode php artisan optimize:clear e recacheie.
# Agendador do Laravel (executa a cada minuto)
( crontab -l 2>/dev/null; echo "* * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1" ) | crontab -u deploy -
# Verificações rápidas
systemctl status nginx --no-pager
curl -I http://exemplo.com
tail -n 50 /var/log/nginx/laravel_error.log
php /var/www/app/artisan queue:failed
Perguntas frequentes
É possível fazer deploy zero-downtime neste fluxo?
Sim. Use uma estratégia de releases com symlink (ex.: pastas releases/current) e troca atômica do link após build e migrações. Combine com health-check antes do switch e rollback rápido ao release anterior. Automatizar isso com CI/CD é o caminho recomendado.
Como faço rollback se algo der errado após o deploy?
Volte ao commit/tag anterior, aplique php artisan migrate:rollback se necessário (cautela com dados) e limpe caches (optimize:clear). Depois recarregue o Nginx e reinicie workers. Ter releases versionadas e backup do banco facilita o retorno seguro.
Onde configuro logs em produção no Laravel?
No .env, ajuste LOG_CHANNEL (stack, daily, stderr etc.) e nivele LOG_LEVEL. Em Nginx, mantenha access/error logs por site. Padronizar logs em JSON e usar correlação ajuda a depurar. Veja o guia de logs estruturados na seção de links internos.
Preciso do Node.js em produção para Laravel com Vite?
Você precisa do Node.js apenas para compilar os assets (npm run build). Em produção, depois de gerar o build, o servidor entrega os arquivos estáticos. Em ambientes CI/CD, a build ocorre no pipeline e o servidor recebe apenas os artefatos prontos.
Como lidar com segredos (senhas de banco, chaves) no .env?
Não versione o .env. Carregue segredos via variáveis de ambiente e mantenha permissões restritas. Em infra mais avançada, use gerenciadores de segredos do provedor de nuvem. Sempre revise quem tem acesso ao servidor e ao repositório.
Quer evoluir seu deploy para CI/CD?
Este passo a passo coloca seu Laravel no ar com segurança. Se você precisa revisar o processo, padronizar ambientes e automatizar releases, vamos conversar.
Falar sobre pipeline de deployVeja também
- tutorial: implementar Canary releases com Traefik em Docker Compose usando headers e weight routing para deploys graduais de aplicações PHP
- Tutorial: configurar HAProxy com Let's Encrypt e healthchecks para balanceamento de tráfego entre containers Docker em VPS (passo a passo)
- Tutorial prático: implementar mTLS entre Nginx e microserviços usando smallstep CA em Docker Compose
- Tutorial: configurar cgroup v2 e systemd ResourceControl para limitar CPU, memória e I/O de containers Docker no Debian