From 11429790c3eff2be30050318c8240e7d62ff6ee4 Mon Sep 17 00:00:00 2001 From: Tiago Date: Tue, 29 Sep 2026 12:31:04 -0300 Subject: [PATCH] Add automated production deploy scripts --- DEPLOY.md | 73 ++++++++++++++++++++++++--------------- scripts/install-prod.sh | 75 +++++++++++++++++++++++++++++++++++++++++ scripts/update-prod.sh | 23 +++++++++++++ 3 files changed, 143 insertions(+), 28 deletions(-) create mode 100755 scripts/install-prod.sh create mode 100755 scripts/update-prod.sh diff --git a/DEPLOY.md b/DEPLOY.md index 0dc1a58..4a3f9a0 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -14,49 +14,65 @@ Valor: 45.13.59.110 TTL: 300 ou automático ``` -Aguarde a propagação e confirme: +Confirme: ```bash dig +short condominio.seconectai.com.br ``` -Deve retornar `45.13.59.110`. +## 2. Primeira instalação com um comando -## 2. Servidor - -Instale Docker e Docker Compose Plugin no servidor. Libere no firewall: +No servidor, dentro da pasta do projeto: ```bash -sudo ufw allow 80/tcp -sudo ufw allow 443/tcp -sudo ufw allow 22/tcp -sudo ufw enable +./scripts/install-prod.sh "SENHA_MASTER_AQUI" ``` -## 3. Código e variáveis +O script gera automaticamente: -No servidor, envie ou clone o projeto. Dentro da pasta do projeto: +- `DB_PASSWORD` +- `JWT_SECRET` +- `EVOLUTION_GLOBAL_API_KEY` +- `ABACATEPAY_WEBHOOK_SECRET` +- `EVOLUTION_DATABASE_CONNECTION_URI` com senha URL-encoded +- `MASTER_PASSWORD_HASH` a partir da senha Master informada -```bash -cp .env.production.example .env -nano .env -``` - -Preencha senhas e chaves reais. Não suba `.env` para Git. - -## 4. Subir produção +Depois sobe tudo com Docker Compose: ```bash docker compose -f docker-compose.prod.yml up -d --build ``` -Acompanhe logs: +Acesse: -```bash -docker compose -f docker-compose.prod.yml logs -f app caddy +```text +https://condominio.seconectai.com.br ``` -Caddy emitirá HTTPS automaticamente para `https://condominio.seconectai.com.br`. +## 3. Atualizar o sistema depois de novos commits + +No servidor, dentro da pasta do projeto: + +```bash +./scripts/update-prod.sh +``` + +Esse comando faz: + +```bash +git fetch +git pull --ff-only +docker compose -f docker-compose.prod.yml up -d --build --remove-orphans +``` + +## 4. Logs úteis + +```bash +docker compose -f docker-compose.prod.yml ps +docker compose -f docker-compose.prod.yml logs -f app +docker compose -f docker-compose.prod.yml logs -f evolution-api +docker compose -f docker-compose.prod.yml logs -f caddy +``` ## 5. Testes @@ -65,7 +81,7 @@ curl -I https://condominio.seconectai.com.br curl https://condominio.seconectai.com.br/health ``` -Resposta esperada do health: +Resposta esperada: ```json {"status":"ok"} @@ -73,17 +89,18 @@ Resposta esperada do health: ## 6. Webhook AbacatePay -Configure no AbacatePay: +Depois da instalação, o script mostra o link completo. O formato é: ```text https://condominio.seconectai.com.br/api/master/webhooks/abacatepay?webhookSecret=SEU_SEGREDO ``` -Use o mesmo valor de `ABACATEPAY_WEBHOOK_SECRET`. +Use o valor gerado em `ABACATEPAY_WEBHOOK_SECRET` no `.env`. ## 7. Observações -- Em produção, Postgres e Redis não ficam publicados na internet. -- O app fica atrás do Caddy, com HTTPS automático. +- O arquivo `.env` gerado contém segredos reais e não deve ir para Git. +- Postgres e Redis não ficam publicados na internet no compose de produção. +- Caddy emite HTTPS automaticamente. - Uploads ficam em `./uploads` no servidor. - Faça backup dos volumes Docker e da pasta `uploads`. diff --git a/scripts/install-prod.sh b/scripts/install-prod.sh new file mode 100755 index 0000000..17651c3 --- /dev/null +++ b/scripts/install-prod.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +set -euo pipefail + +DOMAIN="${DOMAIN:-condominio.seconectai.com.br}" +COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.prod.yml}" +ENV_FILE="${ENV_FILE:-.env}" + +if [[ ! -f "$COMPOSE_FILE" ]]; then + echo "Erro: $COMPOSE_FILE nao encontrado. Rode este script na raiz do projeto." + exit 1 +fi + +if ! command -v docker >/dev/null 2>&1; then + echo "Erro: Docker nao encontrado. Instale Docker e Docker Compose plugin antes de continuar." + exit 1 +fi + +if [[ $# -gt 0 ]]; then + MASTER_PASSWORD="$1" +else + read -rsp "Senha Master: " MASTER_PASSWORD + echo +fi + +if [[ -z "${MASTER_PASSWORD:-}" ]]; then + echo "Erro: senha Master vazia." + exit 1 +fi + +secret() { + openssl rand -base64 32 | tr -d '\n' +} + +urlencode() { + python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$1" +} + +hash_master() { + docker run --rm httpd:2.4-alpine htpasswd -bnBC 12 "" "$1" | tr -d ':\n' | sed 's/^\$2y\$/\$2a\$/' +} + +DB_PASSWORD="$(secret)" +JWT_SECRET="$(secret)" +EVOLUTION_GLOBAL_API_KEY="$(secret)" +ABACATEPAY_WEBHOOK_SECRET="$(secret)" +MASTER_PASSWORD_HASH="$(hash_master "$MASTER_PASSWORD")" +DB_PASSWORD_URL="$(urlencode "$DB_PASSWORD")" + +cat > "$ENV_FILE" <