Substituição completa na mesma VPS, reutilizando Docker, Compose, Caddy e webhook.
Domínio: narvane.com.br com subdomínios api. e app..
Atenção: este guia apaga containers, volumes e deploy do narvane-api. Se precisar de dados do banco antigo, faça backup antes de
docker compose down -v.
| Antes (narvane) | Depois (Intensity) |
|---|---|
narvane.com.br → API + /hooks/* |
api.narvane.com.br → API |
| Caddy no compose do narvane | Caddy no compose do Intensity |
| Webhook na porta 9000 (host) | Mesmo webhook, paths atualizados |
| — | app.narvane.com.br → deep links (/.well-known/*) |
Imagem Docker: ghcr.io/<seu-usuario>/intesity-2/api (tags latest e SHA do commit).
Em Settings → Secrets and variables → Actions, crie:
| Secret | Valor |
|---|---|
DEPLOY_WEBHOOK_SECRET |
string aleatória longa (ex.: openssl rand -hex 32) |
DEPLOY_WEBHOOK_URL |
ver seção 1.3 — configure depois do Caddy subir |
- Faça merge/push na branch
masteroumaincom mudanças emapi/**. - Confira em Actions que o workflow API CI passou.
- Em Packages do GitHub, verifique o pacote
intesity-2/api. - Se o pacote for privado: na VPS você precisará de
docker login ghcr.io(passo 4.4).
Opção A — Igual ao narvane (recomendado): HTTPS via Caddy
https://api.narvane.com.br/hooks/intensity-api-deploy
Requer ajuste no Caddyfile (passo 5.3). Só configure DEPLOY_WEBHOOK_URL no GitHub depois disso funcionar.
Opção B — Porta 9000 direta (como no README padrão):
http://IP_DA_VPS:9000/hooks/intensity-api-deploy
Mais simples, menos seguro (porta aberta). Use firewall ou migre para A depois.
- Acesse registro.br → seu domínio narvane.com.br → DNS.
- Anote o IP público da VPS (
curl -4 ifconfig.mena VPS). - Adicione dois registros A:
| Tipo | Nome | Destino | TTL |
|---|---|---|---|
| A | api |
IP_DA_VPS |
300–3600 |
| A | app |
IP_DA_VPS |
300–3600 |
Isso cria api.narvane.com.br e app.narvane.com.br.
- Aguarde propagação (minutos a algumas horas). Teste:
dig +short api.narvane.com.br
dig +short app.narvane.com.brAmbos devem retornar o IP da VPS.
- Pode continuar apontando para a VPS enquanto o narvane existir.
- Depois da migração: remova o registro A da raiz, ou redirecione no Caddy, ou deixe sem uso.
- Não é obrigatório comprar outro domínio.
Conecte via SSH.
docker ps -a
docker volume ls
ls -la /opt/Procure algo como /opt/narvane, /opt/narvane-api ou pasta com docker-compose.yml e Caddyfile antigo.
cd /opt/narvane/deploy # ajuste o caminho real
docker compose downSe não precisar dos dados do Postgres do narvane:
docker compose down -vRemova imagens órfãs (opcional):
docker image ls | grep -i narvane
docker rmi <IMAGE_ID> # se ainda existirsudo systemctl list-units --type=service | grep -iE 'narvane|webhook|deploy'Se existir unit do webhook apontando para hooks do narvane:
sudo systemctl stop narvane-webhook # nome pode variar
sudo systemctl disable narvane-webhookNão desinstale o binário webhook — vamos reutilizá-lo.
cp /opt/narvane/deploy/.env ~/narvane-env-backup.txtÚtil para lembrar padrões de senha/email, não reutilize JWT/DB do narvane no Intensity.
sudo rm -rf /opt/narvanesudo ss -tlnp | grep -E ':80|:443'Não deve haver nada escutando antes de subir o Intensity. Se houver:
docker stop <container_id>sudo mkdir -p /opt/intensity
sudo chown "$USER:$USER" /opt/intensity
git clone https://github.com/<SEU_USUARIO>/intesity-2.git /opt/intensity
cd /opt/intensity
git checkout master # ou maincd /opt/intensity/deploy
cp .env.example .env
nano .envExemplo para narvane.com.br:
API_IMAGE=ghcr.io/<seu-usuario-github-minusculo>/intesity-2/api:latest
API_DOMAIN=api.narvane.com.br
APP_DOMAIN=app.narvane.com.br
ACME_EMAIL=seu@email.com
POSTGRES_DB=intensity
POSTGRES_USER=intensity
POSTGRES_PASSWORD=<gere-senha-forte>
INTENSITY_JWT_SECRET=<gere-32+-chars-aleatorios>
DEPLOY_WEBHOOK_SECRET=<mesmo-valor-do-secret-no-GitHub>Gerar segredos:
openssl rand -base64 32chmod +x deploy.sh webhook/receive.sh- GitHub → Settings → Developer settings → Personal access tokens
- Token com
read:packages(classic) ou permissão Packages no fine-grained. - Na VPS:
echo "SEU_TOKEN" | docker login ghcr.io -u SEU_USUARIO_GITHUB --password-stdinO arquivo já espera /opt/intensity:
"execute-command": "/opt/intensity/deploy/webhook/receive.sh"Se clonou em outro path, edite deploy/webhook/hooks.json para bater com o caminho real.
O Caddyfile do repo já cobre api. e app.. Suba o stack:
cd /opt/intensity/deploy
./deploy.shNa primeira subida o Caddy pede certificados Let's Encrypt (DNS já deve estar ok).
Crie ou atualize a unit systemd /etc/systemd/system/intensity-webhook.service:
[Unit]
Description=Intensity deploy webhook
After=network.target docker.service
[Service]
ExecStart=/usr/bin/webhook -hooks /opt/intensity/deploy/webhook/hooks.json -port 9000 -verbose
Restart=on-failure
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now intensity-webhook
sudo systemctl status intensity-webhookTeste local:
curl -X POST http://127.0.0.1:9000/hooks/intensity-api-deploy \
-H "Content-Type: application/json" \
-H "X-Deploy-Secret: SEU_SECRET" \
-d '{"sha":"latest"}'Edite deploy/Caddyfile para o bloco da API ficar assim:
{$API_DOMAIN} {
handle /hooks/* {
reverse_proxy host.docker.internal:9000
}
handle {
reverse_proxy api:8080
}
}No serviço proxy do docker-compose.prod.yml, confirme (já presente no repositório atual):
extra_hosts:
- "host.docker.internal:host-gateway"Se precisar alterar o compose, reinicie o proxy:
docker compose -f docker-compose.prod.yml up -d proxyTeste:
curl -X POST "https://api.narvane.com.br/hooks/intensity-api-deploy" \
-H "Content-Type: application/json" \
-H "X-Deploy-Secret: SEU_SECRET" \
-d '{"sha":"latest"}'DEPLOY_WEBHOOK_URL:
https://api.narvane.com.br/hooks/intensity-api-deploy
(opção A) ou http://IP:9000/hooks/intensity-api-deploy (opção B).
# API
curl -fsS https://api.narvane.com.br/actuator/health
# Deep links
curl -fsS https://app.narvane.com.br/.well-known/assetlinks.json
curl -fsS https://app.narvane.com.br/.well-known/apple-app-site-association
# Containers
docker psEsperado:
| Container | Função |
|---|---|
intensity-postgres |
Banco |
intensity-api |
Spring Boot |
intensity-proxy |
Caddy :80/:443 |
- Faça um push em
api/**namaster. - Confira Actions → build + push GHCR + POST webhook.
- Na VPS:
docker logs intensity-api --tail 50se algo falhar.
Edite no repo (não só na VPS):
client/deep-link/.well-known/assetlinks.json— SHA256 do certificado Android releaseclient/deep-link/.well-known/apple-app-site-association— Team ID Apple
Depois: git pull na VPS e docker compose -f docker-compose.prod.yml up -d proxy.
No deploy/.env:
API_IMAGE=ghcr.io/<user>/intesity-2/api:<SHA_ANTERIOR>./deploy.sh- Registro.br: registros A para
apieapp - DNS propagado (
dig) - narvane:
docker compose down(+-vse ok apagar dados) - Portas 80/443 livres
- Repo em
/opt/intensity -
deploy/.envpreenchido -
docker login ghcr.io(se pacote privado) -
./deploy.shOK - Webhook systemd apontando para
intensity/deploy/webhook/hooks.json - (Opcional)
/hooks/*no Caddy +extra_hosts - GitHub secrets:
DEPLOY_WEBHOOK_URL,DEPLOY_WEBHOOK_SECRET -
curlhealth +.well-knownOK - Push teste na
masterdispara deploy
| Sintoma | Causa provável | Solução |
|---|---|---|
| Caddy não sobe | 80/443 ocupadas | ss -tlnp, pare stack antigo |
| Certificado falha | DNS não aponta para VPS | Confira Registro.br, aguarde TTL |
pull falha |
GHCR sem login | docker login ghcr.io |
| Webhook 401 | Secret diferente | .env = GitHub secret |
| Webhook não alcança host | Falta extra_hosts |
Adicione no compose do proxy |
| API unhealthy | Postgres senha errada | Confira .env e logs intensity-api |
- DNS no Registro.br (pode propagar enquanto você limpa a VPS)
- GitHub: gerar
DEPLOY_WEBHOOK_SECRET(URL depois) - Push para gerar imagem no GHCR
- SSH: limpar narvane
- Clonar Intensity +
.env ./deploy.sh- Webhook systemd (+ Caddy
/hooks/*se quiser) - GitHub:
DEPLOY_WEBHOOK_URL - Testes
curl+ push de teste