Deploy em Produção
Guia completo para implantar o LJ Velas e Aromas em ambiente de produção na Hostinger.
Sumário
- Arquitetura de produção
- Pré-requisitos
- Configuração do servidor
- Variáveis de ambiente de produção
- Processo de build e deploy
- PM2 para produção
- Configuração do NF-e
- Domínio e SSL
- CI/CD com GitHub Actions
- Rollback
- Monitoramento
- Checklist de go-live
Arquitetura de produção
Pré-requisitos
Plano Hostinger
- Plano mínimo: Business Hosting ou superior (para apps Node.js)
- VPS alternativo: KVM 2 ou superior (recomendado para controle total com PM2)
- Banco de dados MySQL 8.0 (incluído em todos os planos)
- Suporte a Node.js 20.x
Ferramentas necessárias
| Ferramenta | Versão | Observação |
|---|---|---|
| Node.js | 20.x LTS | Configure no painel Hostinger |
| npm | 10.x | Incluído com Node.js |
| PM2 | latest | npm install -g pm2 |
| Git | 2.x | Para pull do repositório |
Configuração do servidor
1. Acesse o servidor via SSH
ssh usuario@seu-servidor.hostinger.com
# ou pela chave SSH configurada no hPanel
2. Crie o banco de dados MySQL
No painel hPanel da Hostinger:
- Acesse Bancos de Dados → MySQL
- Clique em Criar banco de dados
- Preencha:
- Nome do banco:
ljvemasearomas - Nome do usuário:
ljvemas_app - Senha: gere uma senha forte e anote
- Nome do banco:
- Clique em Criar
Importante: O banco de dados da Hostinger fica acessível em
localhost— aDATABASE_URLdeve usar127.0.0.1ou o hostname interno fornecido pelo hPanel.
3. Clone o repositório
cd ~/domains/ljvelasearomas.com.br
git clone https://github.com/seu-usuario/ljvemasearomas.git app
cd app
4. Instale as dependências de produção
npm install --omit=dev
O
postinstallexecutaprisma generateautomaticamente.
5. Crie o diretório de uploads
mkdir -p ~/domains/ljvelasearomas.com.br/public_html/uploads/products
chmod 755 ~/domains/ljvelasearomas.com.br/public_html/uploads/products
6. Configure o Nginx para servir os uploads
Adicione ao bloco server do Nginx:
# Servir uploads diretamente pelo Nginx (sem passar pelo Node.js)
location /uploads/ {
alias /home/USER/domains/ljvelasearomas.com.br/public_html/uploads/;
expires 30d;
add_header Cache-Control "public, immutable";
}
Variáveis de ambiente de produção
Crie o arquivo .env no diretório da aplicação (~/domains/ljvelasearomas.com.br/app/.env):
nano .env
Variáveis obrigatórias
NODE_ENV="production"
# ─── Banco de dados ───────────────────────────────────────────
# Formato: mysql://USUARIO:SENHA@HOST:PORTA/BANCO
# O host geralmente é localhost ou 127.0.0.1 na Hostinger
DATABASE_URL="mysql://ljvemas_app:SUA_SENHA@localhost:3306/ljvemasearomas"
# Banco sombra (pode ser omitido em produção se não usar migrate dev)
# Se necessário, crie um segundo banco "ljvemasearomas_shadow" no hPanel
SHADOW_DATABASE_URL="mysql://ljvemas_app:SUA_SENHA@localhost:3306/ljvemasearomas_shadow"
# ─── Autenticação ─────────────────────────────────────────────
# OBRIGATÓRIO: gere com: openssl rand -hex 32
JWT_SECRET="sua-chave-producao-de-64-caracteres-aqui"
# ─── Upload de arquivos ───────────────────────────────────────
# Caminho absoluto fora do diretório da aplicação
UPLOAD_DIR="/home/USER/domains/ljvelasearomas.com.br/public_html/uploads/products"
# URL pública base das imagens
UPLOAD_URL_BASE="https://ljvelasearomas.com.br/uploads/products"
# ─── E-mail ───────────────────────────────────────────────────
EMAIL_HOST="smtp.hostinger.com"
EMAIL_PORT="587"
EMAIL_USER="contato@ljvelasearomas.com.br"
EMAIL_PASS="senha-do-email-hostinger"
EMAIL_FROM="LJ Velas e Aromas <contato@ljvelasearomas.com.br>"
# ─── Mercado Pago (PRODUÇÃO — sem o prefixo TEST-) ────────────
# Obtido em: mercadopago.com.br/developers/panel/app
# Use as credenciais de PRODUÇÃO (sem "TEST-" no início)
MERCADOPAGO_ACCESS_TOKEN="APP_USR-0000000000000000-000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-000000000"
NEXT_PUBLIC_MP_PUBLIC_KEY="APP_USR-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
# ─── Frete ───────────────────────────────────────────────────
STORE_ORIGIN_CEP="01310-100"
# ─── Aplicação ────────────────────────────────────────────────
NEXT_PUBLIC_APP_URL="https://ljvelasearomas.com.br"
# ─── NF-e ─────────────────────────────────────────────────────
# Gere uma chave aleatória: openssl rand -hex 32
NFE_API_KEY="sua-chave-nfe-secreta"
NFE_SERVICE_URL="http://localhost:8001"
Variáveis de observabilidade (opcionais mas recomendadas)
# HyperDX — APM e logs centralizados
# Crie uma conta em: https://www.hyperdx.io
HYPERDX_API_KEY="sua-chave-hyperdx"
OTEL_SERVICE_NAME="ljvemasearomas-production"
Segurança: O arquivo
.envnunca deve ser commitado. Ele está no.gitignore. Em pipelines CI/CD, use os Secrets do GitHub Actions para injetar as variáveis.
Processo de build e deploy
Deploy manual (primeira vez)
# 1. Entrar no diretório da aplicação
cd ~/domains/ljvelasearomas.com.br/app
# 2. Garantir que está na branch correta
git checkout main
git pull origin main
# 3. Instalar dependências
npm install --omit=dev
# 4. Fazer o build de produção
npm run build
# 5. Aplicar migrações do banco de dados
npx prisma migrate deploy
# 6. Iniciar o servidor
npm run start
Deploy de atualização
cd ~/domains/ljvelasearomas.com.br/app
# 1. Parar a aplicação atual (se usando PM2)
pm2 stop ljvemasearomas
# 2. Atualizar o código
git pull origin main
# 3. Instalar novas dependências (se houver)
npm install --omit=dev
# 4. Fazer o novo build
npm run build
# 5. Aplicar novas migrações (se houver)
npx prisma migrate deploy
# 6. Reiniciar com PM2
pm2 restart ljvemasearomas
PM2 para produção
O PM2 é o gerenciador de processos recomendado para garantir que a aplicação seja reiniciada automaticamente após falhas ou reinicializações do servidor.
Instalação
npm install -g pm2
Arquivo de configuração PM2
Crie ecosystem.config.js na raiz do projeto:
module.exports = {
apps: [
{
name: 'ljvemasearomas',
script: 'server.js',
instances: 1, // aumente para usar múltiplos cores
exec_mode: 'fork', // use 'cluster' com instances > 1
env: {
NODE_ENV: 'production',
PORT: 3000,
},
// Reiniciar se o uso de memória ultrapassar 512MB
max_memory_restart: '512M',
// Logs
out_file: './logs/pm2-out.log',
error_file: './logs/pm2-error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
// Reiniciar automaticamente em caso de falha
autorestart: true,
watch: false,
restart_delay: 5000,
},
],
};
Comandos PM2 essenciais
# Iniciar pela primeira vez
pm2 start ecosystem.config.js
# Ou diretamente com server.js
pm2 start server.js --name ljvemasearomas
# Reiniciar (zero-downtime reload)
pm2 reload ljvemasearomas
# Parar
pm2 stop ljvemasearomas
# Deletar processo
pm2 delete ljvemasearomas
# Ver status
pm2 status
# Ver logs em tempo real
pm2 logs ljvemasearomas
# Ver últimas 200 linhas de log
pm2 logs ljvemasearomas --lines 200
# Monitorar CPU/memória
pm2 monit
Inicialização automática no boot
# Gerar script de startup para o sistema
pm2 startup
# Execute o comando exibido pelo PM2 (começa com "sudo env PATH=...")
# Exemplo:
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u usuario --hp /home/usuario
# Salvar a lista de processos atual
pm2 save
Configuração do NF-e
O serviço de NF-e é um microserviço PHP independente localizado em /nfe-service/. Ele requer um certificado digital .pfx para assinar notas fiscais.
1. Faça upload do certificado
# Crie o diretório para o certificado (fora do webroot)
mkdir -p ~/certificates
# Copie o certificado .pfx via SCP (da sua máquina local)
scp /caminho/local/certificado.pfx usuario@servidor:~/certificates/
# Defina permissões restritivas
chmod 600 ~/certificates/certificado.pfx
2. Configure o serviço NF-e
No arquivo de configuração do nfe-service (consulte nfe-service/README.md):
# Caminho do certificado
NFE_CERT_PATH="/home/USER/certificates/certificado.pfx"
# Senha do certificado
NFE_CERT_PASSWORD="senha-do-certificado"
# Ambiente (1 = produção, 2 = homologação)
NFE_AMBIENTE="1"
3. Defina permissões do diretório
# O usuário do Apache/PHP-FPM precisa ler o certificado
# Verifique o usuário com: ps aux | grep apache
chown USER:www-data ~/certificates/certificado.pfx
chmod 640 ~/certificates/certificado.pfx
4. Configure as variáveis no .env principal
NFE_API_KEY="chave-secreta-compartilhada-entre-nextjs-e-nfe-service"
NFE_SERVICE_URL="http://localhost:8001"
Domínio e SSL
SSL automático pela Hostinger
A Hostinger gerencia certificados SSL automaticamente via Let's Encrypt para todos os domínios configurados:
- No hPanel, acesse Domínios → Gerenciar
- Certifique-se de que os nameservers apontam para a Hostinger
- Acesse SSL → Gerenciar e ative o SSL Gratuito (Let's Encrypt)
- O certificado é renovado automaticamente — nenhuma ação necessária
Redirecionamento HTTP → HTTPS
O header HSTS já está configurado em next.config.ts. Certifique-se de que o Nginx (ou o configurador de proxy da Hostinger) redireciona todo tráfego HTTP para HTTPS:
server {
listen 80;
server_name ljvelasearomas.com.br www.ljvelasearomas.com.br;
return 301 https://$host$request_uri;
}
DNS
| Tipo | Nome | Valor | TTL |
|---|---|---|---|
| A | @ | IP do servidor | 3600 |
| A | www | IP do servidor | 3600 |
| CNAME | www | ljvelasearomas.com.br | 3600 |
CI/CD com GitHub Actions
O projeto inclui dois workflows em .github/workflows/:
ci.yml — Lint e Type Check
- Trigger: Push para qualquer branch
- O que faz: Instala dependências, roda ESLint e verifica tipos TypeScript
- Objetivo: Bloquear código com erros de lint ou tipo antes do merge
tests.yml — Testes automatizados
- Trigger:
- Push para
developoumain→ roda testes Jest (unitários + integração) - Pull Request para
main→ roda testes Jest + Playwright E2E (apenas Chromium)
- Push para
- Artefatos: Relatórios de teste e cobertura ficam disponíveis por 7 dias
Configurando os Secrets no GitHub
Acesse Settings → Secrets and variables → Actions e adicione:
| Secret | Descrição |
|---|---|
DATABASE_URL | URL do banco de teste (pode ser SQLite em memória para CI) |
JWT_SECRET | Qualquer valor aleatório seguro |
MERCADOPAGO_ACCESS_TOKEN | Token de teste (começa com TEST-) |
NEXT_PUBLIC_MP_PUBLIC_KEY | Chave pública de teste |
STORE_ORIGIN_CEP | CEP qualquer válido |
UPLOAD_DIR | /tmp/uploads (para CI) |
UPLOAD_URL_BASE | http://localhost:3000/uploads/products |
Pipeline completo
Push → develop
└── ci.yml (lint + typecheck)
└── tests.yml (Jest)
Pull Request → main
└── ci.yml (lint + typecheck)
└── tests.yml (Jest + Playwright Chromium)
Merge → main
└── (deploy manual via SSH ou script deploy.bat)
Rollback
Rollback rápido com Git + PM2
cd ~/domains/ljvelasearomas.com.br/app
# 1. Ver histórico de commits
git log --oneline -10
# 2. Voltar para o commit anterior
git checkout HASH_DO_COMMIT_ANTERIOR
# 3. Rebuild na versão anterior
npm run build
# 4. Reiniciar
pm2 restart ljvemasearomas
Rollback de banco de dados (migrações)
# Ver histórico de migrações aplicadas
npx prisma migrate status
# Reverter para uma migração específica (requer Prisma Migrate)
# Atenção: operação destrutiva — faça backup antes
npx prisma migrate resolve --rolled-back NOME_DA_MIGRACAO
Boas práticas: Sempre faça backup do banco antes de aplicar migrações em produção:
mysqldump -u ljvemas_app -p ljvemasearomas > backup_$(date +%Y%m%d_%H%M%S).sql
Monitoramento
HyperDX (APM e logs)
O projeto já inclui @hyperdx/node-opentelemetry via instrumentation.ts. Para ativar:
- Crie uma conta em https://www.hyperdx.io
- Obtenha sua API Key no painel
- Configure no
.env:HYPERDX_API_KEY="sua-api-key"OTEL_SERVICE_NAME="ljvemasearomas-production" - O HyperDX captura automaticamente:
- Erros não tratados
- Latência de rotas
- Queries lentas
- Logs estruturados
Logs PM2
# Logs em tempo real
pm2 logs ljvemasearomas
# Logs de erro
pm2 logs ljvemasearomas --err
# Limpar logs
pm2 flush ljvemasearomas
Alertas de uptime
Configure um monitor externo para receber alertas se o site ficar fora do ar:
- UptimeRobot — gratuito, verifica a cada 5 minutos
- Better Uptime — mais recursos, alertas por e-mail/SMS
Checklist de go-live
Use esta lista antes de abrir a loja para o público:
Infraestrutura
- Servidor Node.js 20.x configurado na Hostinger
- Banco MySQL 8.0 criado e acessível
- PM2 instalado e configurado para auto-start no boot
- Diretório de uploads criado com permissões corretas
- Nginx configurado (proxy reverso + servir uploads)
- SSL ativado e redirecionamento HTTPS funcionando
Variáveis de ambiente
-
NODE_ENV=production -
DATABASE_URLapontando para o banco de produção -
JWT_SECRETgerado comopenssl rand -hex 32(nunca reutilize o de dev) -
MERCADOPAGO_ACCESS_TOKENé a chave de produção (não começa comTEST-) -
NEXT_PUBLIC_MP_PUBLIC_KEYé a chave pública de produção -
UPLOAD_DIRé um caminho absoluto persistente -
EMAIL_*configurados e testados comnpm run test:smtp -
STORE_ORIGIN_CEPé o CEP real da loja
Banco de dados
-
npx prisma migrate deployexecutado com sucesso - Admin criado (via seed ou manualmente)
- Backup automático configurado no hPanel
Pagamentos
- Webhook do Mercado Pago apontando para
https://ljvelasearomas.com.br/api/webhooks/mercadopago - Teste de pagamento realizado com conta real (compra de 1 real)
- Confirmação de e-mail de pedido recebida
NF-e (se aplicável)
- Certificado
.pfxem/home/USER/certificates/com permissões640 -
NFE_API_KEYconfigurada em ambos os serviços - Serviço NF-e em execução e acessível em
NFE_SERVICE_URL - NF-e de teste emitida com sucesso
Monitoramento
- HyperDX configurado (ou outra solução de APM)
- Monitor de uptime ativo (UptimeRobot ou similar)
- Alertas de e-mail configurados para erros críticos
SEO e performance
- Domínio com HTTPS sem mixed content
- Sitemap.xml acessível em
/sitemap.xml - Robots.txt presente em
/robots.txt - Lighthouse score ≥ 85 nas páginas principais
Segurança
-
.envnão está no repositório Git - Senhas de teste (
admin123) alteradas - Headers de segurança presentes (HSTS configurado em
next.config.ts) - Rate limiting ativo nas rotas de autenticação