Instalar Membresia 360 em uma VPS
Passo a passo completo para rodar o app em um servidor próprio (Ubuntu 22.04), com Node.js, Nginx, SSL gratuito e domínio personalizado.

Toda vez que você fizer mudanças no Lovable (e sincronizar com o GitHub), rode este bloco na VPS para refletir as novidades. Leva ~1 minuto.
cd /var/www/membresia360
git pull
npm install
NITRO_PRESET=node-server npm run build
pm2 restart membresia360Dica: se algo falhar, veja os logs com pm2 logs membresia360 --lines 100.
Prefere pular o passo a passo? Rode o script abaixo na sua VPS Ubuntu recém-criada (como root). Ele instala Node.js, Bun, Nginx, PM2, faz build, sobe o app e (opcional) emite SSL grátis.
curl -fsSL https://igreja-conectada-360.lovable.app/install-membresia360.sh -o install.sh
sudo bash install.shModo não interativo (informe repositório, domínio e e-mail):
sudo REPO_URL="https://github.com/usuario/repo.git" \
DOMAIN="app.suaigreja.com.br" \
EMAIL="admin@suaigreja.com.br" \
bash install.shO workflow .github/workflows/deploy-vps.yml já está incluso no projeto. Toda vez que você fizer push no branch main (o Lovable já faz isso quando você sincroniza com o GitHub), o GitHub Actions conecta na sua VPS via SSH e roda git pull, build e pm2 restart sozinho.
1. Gere uma chave SSH só para o deploy (na sua VPS)
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/gh_deploy -N ""
cat ~/.ssh/gh_deploy.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
cat ~/.ssh/gh_deploy # copie TUDO — é a chave PRIVADA que vai no GitHub2. Adicione os secrets no GitHub
No repositório: Settings → Secrets and variables → Actions → New repository secret. Crie um por vez:
| Secret | Valor |
|---|---|
| VPS_HOST | IP da VPS (ex.: 91.98.120.163) |
| VPS_USER | root (ou o usuário sudo) |
| VPS_PORT | Porta SSH (padrão 22). Opcional. |
| VPS_SSH_KEY | Conteúdo do arquivo ~/.ssh/gh_deploy (privada, inclui BEGIN/END) |
| VPS_APP_PATH | Caminho do projeto (ex.: /var/www/membresia360) |
| PM2_APP_NAME | Nome do processo PM2 (ex.: membresia360) |
3. Teste
Faça qualquer push em main (ou clique em Actions → Deploy to VPS → Run workflow). Acompanhe o log em tempo real na aba Actions do GitHub. Se der verde, sua VPS já está com a versão nova.
- Use uma chave SSH exclusiva para o deploy — não reaproveite a sua pessoal.
- Nunca cole a chave privada no chat ou em commits.
- Se quiser restringir mais: crie um usuário
deployna VPS com sudo limitado só parapm2.
- 1Contratar a VPS
- 2Conectar via SSH
- 3Atualizar o sistema
- 4Instalar Node.js e Bun
- 5Instalar Nginx
- 6Criar o banco de dados no Supabase
- 7Clonar e configurar o projeto
- 8Rodar em produção com PM2
- 9Configurar domínio e DNS
- 10SSL grátis com Certbot
- 11Manutenção e atualizações
- 12Instalação automatizada com 1 clique
- 13Erros reais & sequência que funcionou
- 14Comandos de operação diária
- 15Scripts prontos & status ao vivo
- 16Configurar domínio próprio passo a passo
- 17Depois do SSL: atualizar .env e publicar
- 18Subdomínios e outros sites na mesma VPS
- 19Cloudflare: DNS, cache e proteção
Marque cada comando conforme executa na VPS. Cole o output ou anexe um print como evidência. Tudo fica salvo no seu navegador.
Conectar na VPS via SSH
Confirme o login (yes) e digite a senha root do provedor.
Atualizar o sistema
Pode demorar alguns minutos. Aceite as opções padrão.
Liberar a porta 80 (parar LiteSpeed, se existir)
Só execute se aparecer erro 'bind() to 0.0.0.0:80 failed'.
Instalar Node.js 20
Instalar PM2 (gerenciador de processos)
Instalar Nginx
Confirmar Nginx escutando na porta 80
Deve mostrar 0.0.0.0:80 LISTEN nginx.
Clonar o repositório (com token PAT)
Criar arquivo .env com chaves do Supabase
Cole VITE_SUPABASE_URL, VITE_SUPABASE_PUBLISHABLE_KEY e demais variáveis.
Instalar dependências
Build de produção (preset node-server)
Sem o preset o app não sobe em Node — dá 500 no Nginx.
Subir o app com PM2 na porta 3000
Configurar Nginx como proxy reverso para :3000
proxy_pass http://127.0.0.1:3000; dentro do bloco location /.
Abrir http://SEU_IP no navegador
A landing do Membresia 360 deve carregar.
Apontar DNS (registro A) para o IP da VPS
No painel do domínio: A @ SEU_IP e A www SEU_IP.
Emitir SSL grátis com Certbot
Fluxo de atualização (novas versões)
Executa comandos autorizados diretamente na VPS onde o Membresia 360 está rodando. Requer que o servidor tenha a variável VPS_EXEC_TOKEN definida no .env. Só funciona quando esta página é acessada pelo domínio da VPS (não pelo preview do Lovable).
Clique em um botão acima para ver a saída aqui.
- VPS com Ubuntu 22.04 LTS — mínimo 1 vCPU, 2 GB de RAM, 20 GB SSD
- Acesso SSH (usuário
rootou sudo) - Domínio próprio (ex.:
minhaigreja.com.br) - Conta no Supabase com projeto criado e banco de dados configurado
- Arquivo
schema.sqldo projeto aplicado no Supabase
Contratar a VPS
Contrate uma VPS em qualquer provedor: Hostinger, Contabo, DigitalOcean, Vultr, Hetzner ou AWS Lightsail. Escolha o sistema operacional Ubuntu 22.04 LTS.
Após a criação, o painel do provedor mostrará o IP público (ex.: 203.0.113.10) e a senha root. Guarde essas informações — vamos usá-las já no próximo passo.
Conectar via SSH
Abra o terminal do seu computador (ou PuTTY no Windows) e conecte:
ssh root@SEU_IP_DA_VPS
# Ex: ssh root@203.0.113.10
# Digite a senha quando pedir.
Crie um usuário não-root (recomendado por segurança):
adduser membresia
usermod -aG sudo membresia
su - membresiaAtualizar o sistema
Atualize os pacotes do Ubuntu antes de instalar qualquer coisa:
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl git build-essential ufwAtive o firewall liberando SSH, HTTP e HTTPS:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enableInstalar Node.js e Bun
Instale o Node.js 20 LTS via NodeSource:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node -v # deve mostrar v20.x
npm -vInstale o Bun (usado pelo projeto):
curl -fsSL https://bun.sh/install | bash
source ~/.bashrc
bun --versionInstalar Nginx
O Nginx vai servir como proxy reverso do app:
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginxAbra http://SEU_IP no navegador — deve aparecer a página "Welcome to nginx".

Criar o banco de dados no Supabase
O Membresia 360 usa o Supabase como banco de dados (PostgreSQL) e autenticação. Antes de subir o app, você precisa criar o projeto e aplicar as tabelas do sistema.
1. Crie um projeto gratuito em https://supabase.com:
- Clique em New project e escolha uma organização.
- Dê um nome (ex.:
membresia360-suaigreja). - Escolha a região mais próxima do Brasil (recomendado: South America).
- Defina uma senha segura para o banco e aguarde a criação.
2. Acesse Project Settings → API e copie os valores:
Project URL(ex.: https://abc123.supabase.co)Project API keys → anon / public(chave pública)Project API keys → service_role(chave secreta — server side)
3. Aplique o schema do banco de dados:
- Abra SQL Editor → New query.
- Cole o conteúdo do arquivo
schema.sqlque acompanha o projeto. - Clique em Run. Isso cria as tabelas, políticas (RLS), funções e triggers.
-- Exemplo rápido: confirme se as tabelas foram criadas
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public';4. Configure o Auth do Supabase (opcional, mas recomendado):
- Vá em Authentication → Settings e ajuste o site URL para o seu domínio.
- Desative provedores que não usar (Google, GitHub, etc.) para manter a segurança.
- Em Email Templates personalize os e-mails de confirmação e recuperação.
Importante: a chave service_role nunca deve ir para o frontend. Ela é usada apenas no servidor (.env local/VPS) para funções administrativas.
Clonar e configurar o projeto
Clone o projeto na VPS (troque pela URL do seu repositório):
cd ~
git clone https://github.com/SEU_USUARIO/membresia-360.git app
cd app
bun installRepositório privado no GitHub?
O GitHub não aceita senha diretamente no git clone. Se seu repositório for privado, crie um Personal Access Token (PAT):
- Acesse https://github.com/settings/tokens
- Clique em Generate new token (classic)
- Marque a permissão repo e copie o token
Use o token no lugar da senha no comando abaixo:
git clone https://SEU_TOKEN@github.com/SEU_USUARIO/membresia-360.git appDica: se o repo não tiver dados sensíveis, você pode torná-lo público em Settings → Visibility → Public.
Crie o arquivo .env na raiz do projeto com as credenciais do Supabase:
nano .env# Frontend (anon/public key)
VITE_SUPABASE_URL=https://SEU_PROJETO.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
VITE_SUPABASE_PUBLISHABLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
VITE_SUPABASE_PROJECT_ID=SEU_PROJETO
# Backend (service_role key — nunca exponha no navegador)
SUPABASE_URL=https://SEU_PROJETO.supabase.co
SUPABASE_PUBLISHABLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Opcional: URL pública do site (usada em links/QR Code)
VITE_PUBLIC_SITE_URL=https://app.suaigreja.com.brSubstitua SEU_PROJETO pelo ID do projeto Supabase e as chaves pelos valores copiados no passo anterior.
Salve (Ctrl+O, Enter, Ctrl+X) e gere o build de produção para VPS:
NITRO_PRESET=node-server bun run build:vpsRodar em produção com PM2
PM2 mantém o app rodando 24/7 e reinicia em caso de erro:
sudo npm install -g pm2
PORT=3000 NODE_ENV=production pm2 start "bun run start" --name membresia
pm2 save
pm2 startup systemd # copie e cole o comando que aparecerAgora configure o Nginx como proxy do app (porta 3000 por padrão):
sudo nano /etc/nginx/sites-available/membresiaserver {
listen 80;
server_name minhaigreja.com.br www.minhaigreja.com.br;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}Ative o site e recarregue o Nginx:
sudo ln -s /etc/nginx/sites-available/membresia /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxConfigurar domínio e DNS
No painel do seu registrador (Registro.br, GoDaddy, etc.), crie os registros:
Tipo Nome Valor TTL
A @ IP_DA_SUA_VPS 3600
A www IP_DA_SUA_VPS 3600Aguarde a propagação (10 minutos a 24 horas). Teste com:
ping minhaigreja.com.br
SSL grátis com Certbot
Instale o Let's Encrypt via Certbot para ativar HTTPS:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d minhaigreja.com.br -d www.minhaigreja.com.brAceite os termos, forneça um e-mail e escolha a opção de redirecionar HTTP → HTTPS. O Certbot renova o certificado sozinho a cada 60 dias.

Manutenção e atualizações
Para publicar uma nova versão do app:
cd ~/app
git pull
bun install
NITRO_PRESET=node-server bun run build:vps
pm2 restart membresiaComandos úteis do PM2:
pm2 status # ver processos
pm2 logs membresia # ver logs em tempo real
pm2 restart membresia # reiniciar
pm2 stop membresia # pararPronto! Seu Membresia 360 está rodando em uma VPS própria, com domínio e SSL. Em caso de dúvidas, fale com o suporte via WhatsApp (69) 99246-7599.
Instalação automatizada com 1 clique
Se você preferir automatizar todo o processo acima, use o script oficialinstall-membresia360.sh. Ele instala Node.js, Bun, Nginx, PM2, clona o repositório, faz o build, sobe o app e ainda emite SSL grátis via Certbot (se informar domínio e e-mail).
Observação: o script automatiza a parte da VPS, mas ainda é necessário ter um projeto Supabase criado e as chaves configuradas no arquivo .env antes de rodar o script (veja o Passo 6).
1. Baixe o script na VPS:
curl -fsSL https://igreja-conectada-360.lovable.app/install-membresia360.sh -o install.sh2. Rode como root:
sudo bash install.shModo não interativo (responde tudo por variáveis de ambiente):
sudo REPO_URL="https://github.com/usuario/repo.git" \
DOMAIN="app.suaigreja.com.br" \
EMAIL="admin@suaigreja.com.br" \
VITE_SUPABASE_URL="https://SEU_PROJETO.supabase.co" \
VITE_SUPABASE_ANON_KEY="sua_chave_anon" \
SUPABASE_SERVICE_ROLE_KEY="sua_chave_service_role" \
bash install.shO que o script faz por você:
- Atualiza pacotes e ativa firewall UFW
- Instala Node.js 20 LTS e Bun
- Instala Nginx e PM2
- Clona ou atualiza o repositório do app
- Valida se as variáveis do Supabase foram preenchidas antes de prosseguir (VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY e SUPABASE_SERVICE_ROLE_KEY)
- Instala dependências e gera build de produção
- Configura proxy reverso no Nginx
- Emite certificado SSL gratuito com Certbot (opcional)
Erros reais & sequência que funcionou
Esta seção documenta os erros reais encontrados durante uma instalação de produção (VPS Hetzner Ubuntu, IP 91.98.120.163) e a sequência exata de comandos que resolveu cada um. Use como referência rápida quando algo travar.
Erro 1 — Nginx não sobe na porta 80 (LiteSpeed ocupando)
Mensagem: nginx: bind() to 0.0.0.0:80 failed (98: Address already in use). Acontece em VPS que já vêm com OpenLiteSpeed / lsws pré-instalado (Hostinger, alguns templates da Hetzner).
# Descobrir quem está usando a porta 80
sudo ss -tlnp | grep ':80 '
# Parar e desabilitar o LiteSpeed
sudo systemctl stop lsws || sudo /usr/local/lsws/bin/lswsctrl stop
sudo systemctl disable lsws 2>/dev/null || true
# Confirmar que a porta 80 está livre e subir o Nginx
sudo systemctl start nginx
sudo ss -tlnp | grep nginx # deve mostrar nginx escutando em :80Erro 2 — E: Unable to locate package upgrade
O comando certo é apt upgrade (verbo), não apt install upgrade.
# ERRADO
sudo apt install upgrade
# CERTO
sudo apt update && sudo apt upgrade -yErro 3 — install.sh: No such file or directory
Você tentou rodar o script antes de baixá-lo, ou baixou em outra pasta. Sempre rode os dois comandos na mesma sessão e na mesma pasta:
cd /root
curl -fsSL https://igreja-conectada-360.lovable.app/install-membresia360.sh -o install.sh
ls -la install.sh # confirme que existe
sudo bash install.shErro 4 — Repository not found no git clone
Repositório privado exige Personal Access Token (PAT) e a URL correta do repositório. Confira o dono do repo no GitHub — não use neuzinaldo/… se o repo está em jogosdaunidade/…, por exemplo.
# Formato com token embutido (repo privado)
git clone https://SEU_PAT@github.com/DONO_REAL/NOME_DO_REPO.git /var/www/igreja-conectada-360
# Depois de clonar, REVOGUE o token em:
# https://github.com/settings/tokensSegurança: nunca deixe um PAT em histórico de shell público. Revogue e gere um novo assim que terminar o clone.
Erro 5 — ERR_MODULE_NOT_FOUND: dist/server/server.js
Aconteceu ao tentar usar vite preview como servidor de produção. TanStack Start não é um SPA estático — ele precisa do bundle SSR do Nitro. A correção é gerar o build com preset node-server e subir o .output/server/index.mjs.
Erro 6 — 500 Internal Server Error do Nginx
Ocorre quando o Nginx aponta para uma pasta estática que não existe (dist/client/index.html) ou faz proxy para uma porta onde nada está escutando. A solução definitiva é servir via proxy reverso para o processo Node do Nitro na porta 3000.
Sequência final que funcionou (copiar e colar na VPS)
Rode como root, dentro da pasta do projeto já clonado (/var/www/igreja-conectada-360) e com o .env preenchido:
cd /var/www/igreja-conectada-360
# 1. Limpar processos e builds antigos
pm2 delete igreja-conectada-360 || true
rm -rf dist .output
# 2. Instalar dependências e gerar build SSR para VPS (Node)
npm install
NITRO_PRESET=node-server npm run build
# 3. Confirmar que o bundle do servidor foi gerado
ls -la .output/server/index.mjs
# 4. Subir com PM2 na porta 3000
PORT=3000 NODE_ENV=production pm2 start "node .output/server/index.mjs" \
--name igreja-conectada-360 --update-env
pm2 save
pm2 startup systemd -u root --hp /root | tail -n 1 | bash || true
# 5. Configurar Nginx como proxy reverso para :3000
sudo tee /etc/nginx/sites-available/igreja-conectada-360 >/dev/null <<'EOF'
server {
listen 80;
server_name _;
client_max_body_size 25M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/igreja-conectada-360 /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx
# 6. Testar
curl -I http://127.0.0.1:3000 # deve retornar HTTP/1.1 200
curl -I http://SEU_IP_DA_VPS # também deve retornar 200Diagnóstico rápido quando algo falhar
# Nginx com erro?
sudo tail -n 80 /var/log/nginx/error.log
# App caiu?
pm2 status
pm2 logs igreja-conectada-360 --lines 100
# Porta 80 ocupada?
sudo ss -tlnp | grep ':80 '
# Testar se o Node está respondendo antes do Nginx
curl -v http://127.0.0.1:3000Publicando atualizações depois
A VPS não atualiza sozinha quando você mexe no Lovable. Rode este bloco sempre que quiser puxar as mudanças:
cd /var/www/igreja-conectada-360
git pull --ff-only
npm install
NITRO_PRESET=node-server npm run build
pm2 restart igreja-conectada-360Comandos de operação diária
Guia rápido com os comandos que você mais vai usar depois que a VPS já está no ar. Todos os caminhos assumem a instalação padrão em /var/www/membresia360.
Reiniciar só o app (mais comum)
Se o processo ainda não existir no PM2 (ex.: instalação nova ou após pm2 delete), o restart falha. O comando abaixo cai automaticamente no start nesse caso.
pm2 restart membresia360 || pm2 start /var/www/membresia360/.output/server/index.mjs --name membresia360
pm2 saveReiniciar a VPS inteira
O site fica fora do ar alguns minutos até o sistema voltar.
sudo reboot
# ou
sudo shutdown -r nowReiniciar o Nginx
sudo systemctl restart nginx
# ou só recarregar configurações
sudo systemctl reload nginxVer status de tudo
pm2 status
systemctl status nginx --no-pager
sudo ss -tlnp | grep -E 'nginx|:3000'Ver logs
# Logs do app
pm2 logs membresia360 --lines 100
# Logs do Nginx
sudo tail -n 80 /var/log/nginx/error.log
sudo tail -n 80 /var/log/nginx/access.logAtualizar o app depois de mudanças no Lovable
cd /var/www/membresia360
git pull
npm install
NITRO_PRESET=node-server npm run build
pm2 restart membresia360 || pm2 start /var/www/membresia360/.output/server/index.mjs --name membresia360
pm2 saveAtualização forçada (limpeza profunda)
Use quando o site continua mostrando a versão antiga.
cd /var/www/membresia360 && git fetch origin && git reset --hard origin/main && rm -rf .output node_modules/.vite dist && npm install && NITRO_PRESET=node-server npm run build && (pm2 restart membresia360 || pm2 start /var/www/membresia360/.output/server/index.mjs --name membresia360) && pm2 saveCorrigir erro 502 Bad Gateway
Significa que o Nginx está de pé, mas o app Node caiu.
pm2 delete membresia360 || true && cd /var/www/membresia360 && NITRO_PRESET=node-server npm run build && pm2 start ".output/server/index.mjs" --name membresia360 && pm2 save && systemctl reload nginxApagar processos antigos/errored do PM2
Troque NOME_DO_PROCESSO pelo nome que aparece na coluna name do pm2 status (ex.: igreja-conectada-360).
pm2 delete NOME_DO_PROCESSO
pm2 saveVer quem está usando a porta 80
sudo ss -tlnp | grep ':80 '
# Se aparecer lsws (LiteSpeed), pare ele:
sudo systemctl stop lsws || sudo /usr/local/lsws/bin/lswsctrl stop
sudo systemctl disable lsws 2>/dev/null || true
sudo systemctl start nginxAtualizar pacotes do sistema
sudo apt update && sudo apt upgrade -yParar ou iniciar o app manualmente
pm2 stop membresia360 # para
pm2 start membresia360 # inicia
pm2 delete membresia360 # remove do PM2Quando o comando de atualização "não faz nada"
Se você rodou o comando de atualização e o site continuou igual, rode esses comandos um por um dentro da pasta do projeto. Eles mostram onde a atualização travou: pasta errada, conflito no Git, build falhando ou processo parado no PM2.
cd /var/www/membresia360 && pwd
git status
git log --oneline -5
git pull
pm2 statusLeia a saída de cada um. Se git status mostrar conflitos, resolva ou use a atualização forçada abaixo. Se pm2 status mostrar o processo em errored, remova com pm2 delete nome-do-processo.
Atualização forçada (quando a normal não funciona)
Ignora possíveis conflitos no Git, limpa o cache de build e reinstala tudo. Use só quando a atualização normal falhar.
cd /var/www/membresia360 && git fetch origin && git reset --hard origin/main && rm -rf .output node_modules/.vite dist && npm install && NITRO_PRESET=node-server npm run build && (pm2 restart membresia360 || pm2 start /var/www/membresia360/.output/server/index.mjs --name membresia360) && pm2 saveDica final
Sempre que atualizar e o navegador parecer não refletir as mudanças, aperte Ctrl+F5 para limpar o cache. A maior parte dos "site antigo" é só cache.
Scripts prontos & status ao vivo
Baixe os scripts .sh, envie para sua VPS (por SFTP ou wget) e execute com bash nome-do-script.sh. Todos assumem a instalação padrão em /var/www/membresia360 — para outra pasta, exporte APP_DIR antes de rodar.
Baixar todos de uma vez direto na VPS
Substitua SEU-DOMINIO pelo seu domínio (ou use o IP da VPS):
mkdir -p ~/scripts && cd ~/scripts
for f in restart-app.sh restart-nginx.sh reboot-vps.sh status.sh update.sh update-force.sh fix-502.sh; do
wget -q "https://SEU-DOMINIO/scripts/$f" -O "$f"
done
chmod +x *.sh
ls -laPainel de status ao vivo
Mostra em tempo real se o PM2 e o Nginx estão online, uso de CPU/RAM, restarts, uptime, portas abertas e espaço em disco. Requer que a VPS esteja com o VPS_EXEC_TOKEN configurado no .env (mesmo token do painel de execução abaixo).
Vazio = usa a URL atual da página.
Verifica se o HTML está sendo servido do cache do navegador, CDN ou Service Worker.
Requer que o endpoint /api/public/vps-status esteja rodando na VPS e a variável VPS_EXEC_TOKEN configurada no .env.
Configurar domínio próprio passo a passo
Este passo mostra a sequência exata para apontar um domínio já comprado (ex.: apachedesenvolvedor.com.br) para a sua VPS e ativar HTTPS. Substitua SEU-DOMINIO.COM.BR e IP_DA_VPS pelos seus dados reais.
Exemplo real: domínio apachedesenvolvedor.com.br apontado para o IP 91.98.120.163.
1. Apontar o DNS no painel do registrador
Acesse o painel de onde você comprou o domínio (Registro.br, Hostinger, GoDaddy, etc.) e crie estes registros:
Tipo Nome Valor TTL
A @ IP_DA_VPS 3600
A www IP_DA_VPS 3600Para o exemplo apachedesenvolvedor.com.br com IP 91.98.120.163:
Tipo Nome Valor TTL
A @ 91.98.120.163 3600
A www 91.98.120.163 36001.1 Passo a passo visual no Registro.br
- Acesse https://registro.br e faça login em Minha conta.
- No menu lateral, clique em Domínios e depois em apachedesenvolvedor.com.br.
- Clique na aba Editar zona (ou Zona DNS / Gerenciar DNS).
- Clique em Novo registro e adicione duas entradas do tipo
A:- Nome
@(ou deixe em branco) → Valor91.98.120.163→ TTL3600 - Nome
www→ Valor91.98.120.163→ TTL3600
- Nome
- Clique em Salvar ou Aplicar alterações.
- Aguarde a propagação (geralmente poucos minutos, máximo 72 horas).

Dica: na Registro.br o campo @ significa o domínio raiz. Se o painel não aceitar @, deixe o campo "Nome" em branco.
Aguarde a propagação. Pode ser de 10 minutos até 72 horas, mas geralmente funciona em poucos minutos. Teste com:
ping SEU-DOMINIO.COM.BR
# ou, no exemplo:
ping apachedesenvolvedor.com.br2. Ajustar o Nginx para responder pelo domínio
Conecte-se na VPS por SSH e rode os comandos abaixo. Eles criam o arquivo de configuração do Nginx apontando para o app na porta 3000.
cd /var/www/membresia360
sudo tee /etc/nginx/sites-available/membresia360 >/dev/null <<'EOF'
server {
listen 80;
server_name SEU-DOMINIO.COM.BR www.SEU-DOMINIO.COM.BR;
client_max_body_size 25M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOF
# Exemplo para apachedesenvolvedor.com.br:
# sudo tee /etc/nginx/sites-available/membresia360 >/dev/null <<'EOF'
# server {
# listen 80;
# server_name apachedesenvolvedor.com.br www.apachedesenvolvedor.com.br;
# client_max_body_size 25M;
# ...
# }
# EOF
sudo ln -sf /etc/nginx/sites-available/membresia360 /etc/nginx/sites-enabled/membresia360
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx3. Emitir certificado SSL grátis (HTTPS)
Instale o Certbot e peça o certificado para o domínio e o www. Ele já configura o redirecionamento HTTP → HTTPS automaticamente.
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d SEU-DOMINIO.COM.BR -d www.SEU-DOMINIO.COM.BR --non-interactive --agree-tos -m admin@SEU-DOMINIO.COM.BR --redirectPara o exemplo apachedesenvolvedor.com.br:
sudo certbot --nginx -d apachedesenvolvedor.com.br -d www.apachedesenvolvedor.com.br --non-interactive --agree-tos -m admin@apachedesenvolvedor.com.br --redirectO Certbot renova o certificado sozinho. Para testar a renovação automática:
sudo certbot renew --dry-run3.1 SSL automatizado (aguarda DNS + redirect HTTPS)
Script que espera o DNS propagar (checa a cada 30s por até 30 min) e, assim que @ e www apontarem para o IP da VPS, emite o certificado e ativa o redirect HTTP → HTTPS automaticamente.
curl -fsSL https://apachedesenvolvedor.com.br/scripts/ssl-auto.sh -o /tmp/ssl-auto.sh
sudo bash /tmp/ssl-auto.sh SEU-DOMINIO.COM.BR admin@SEU-DOMINIO.COM.BR
# Exemplo real para apachedesenvolvedor.com.br:
sudo bash /tmp/ssl-auto.sh apachedesenvolvedor.com.br neuzinaldo@gmail.comO script instala o Certbot se faltar, valida propagação via dig @8.8.8.8, roda certbot --nginx --redirect e finaliza com um --dry-run.
3.2 Renovação automática (systemd timer + dry-run)
Garante que o timer certbot.timer esteja ativo (roda 2x/dia) e, se por algum motivo não existir, cria um cron diário de fallback. Ao final, executa um dry-run para provar que o certificado vai se renovar sozinho antes de expirar.
curl -fsSL https://apachedesenvolvedor.com.br/scripts/ssl-renew-setup.sh -o /tmp/ssl-renew.sh
sudo bash /tmp/ssl-renew.sh
# Ver quando será a próxima renovação:
systemctl list-timers | grep certbot
# Forçar um teste de renovação a qualquer momento:
sudo certbot renew --dry-runDica: o Let's Encrypt emite certificados de 90 dias. Com o timer ativo, o Certbot tenta renovar automaticamente a partir dos 30 dias antes do vencimento — você não precisa fazer nada.
4. Verificar se tudo está no ar
pm2 status
pm2 logs membresia360 --lines 50
# Teste local (deve retornar HTTP/1.1 200):
curl -I http://127.0.0.1:3000
# Teste pelo domínio (depois da propagação DNS):
curl -I https://SEU-DOMINIO.COM.BR
# ou
# curl -I https://apachedesenvolvedor.com.brAcesse no navegador: https://SEU-DOMINIO.COM.BR(ex.: https://apachedesenvolvedor.com.br).
Problemas comuns ao configurar o domínio
Nginx não sobe na porta 80: outro serviço (OpenLiteSpeed/lsws) pode estar ocupando a porta. Pare ele e suba o Nginx:
sudo ss -tlnp | grep ':80 '
sudo systemctl stop lsws || sudo /usr/local/lsws/bin/lswsctrl stop
sudo systemctl disable lsws 2>/dev/null || true
sudo systemctl start nginxCertbot não consegue validar: o DNS ainda não propagou. Confira com:
nslookup SEU-DOMINIO.COM.BR
# Deve retornar o IP da VPS (ex.: 91.98.120.163)Site abre pelo IP mas não pelo domínio: aguarde mais um pouco a propagação DNS ou verifique se o registro A está correto no painel do registrador.
Comando rápido para reaplicar Nginx + SSL
Se você trocar de domínio futuramente, rode este bloco inteiro (substitua os valores pelo novo domínio/e-mail):
DOMAIN="SEU-DOMINIO.COM.BR"
EMAIL="admin@$DOMAIN"
cd /var/www/membresia360
# Recria config do Nginx
sudo tee /etc/nginx/sites-available/membresia360 >/dev/null <<EOF
server {
listen 80;
server_name $DOMAIN www.$DOMAIN;
client_max_body_size 25M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
EOF
sudo ln -sf /etc/nginx/sites-available/membresia360 /etc/nginx/sites-enabled/membresia360
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx
# Emite SSL
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d "$DOMAIN" -d "www.$DOMAIN" --non-interactive --agree-tos -m "$EMAIL" --redirectLembrete: depois de qualquer mudança no Nginx, rode sudo nginx -t antes de sudo systemctl reload nginx para evitar quebrar o site.
Depois do SSL: atualizar .env e publicar
O Certbot já emitiu o certificado e o Nginx já redireciona HTTP → HTTPS. Agora você precisa contar ao próprio app qual é o domínio oficial dele, senão metadados, links e compartilhamentos ainda vão sair com a URL antiga.
1. Atualizar o .env na VPS
O arquivo .env na VPS pode ser diferente do que está no GitHub. Edite-o diretamente no servidor — não commite chaves e URLs sensíveis no repositório.
cd /var/www/membresia360
nano .envLocalize (ou adicione) a linha:
VITE_PUBLIC_SITE_URL=https://apachedesenvolvedor.com.br⚠️ Atenção: substitua apachedesenvolvedor.com.br pelo seu domínio real. Se estiver com http://, troque para https://.
2. Salvar, recompilar e reiniciar
No Nano, aperte Ctrl+O, depois Enter para salvar, e Ctrl+X para sair. Em seguida, rode:
cd /var/www/membresia360
NITRO_PRESET=node-server npm run build
pm2 restart membresia360
pm2 saveO build pode levar de 30s a 2min na primeira vez. O PM2 já reinicia o app sem derrubar o Nginx na frente.
3. Confirmar que o site está no ar
No navegador, abra:
https://apachedesenvolvedor.com.brPara conferir se o certificado e o redirect estão perfeitos, use a página de diagnóstico do próprio app:
https://apachedesenvolvedor.com.br/ssl-statusDigite o domínio e clique em Verificar. Você deve ver HTTPS respondendo, redirect ativo e dias restantes do certificado.
4. Comando rápido para reaplicar tudo
Se precisar repetir no futuro (trocou de domínio, por exemplo), este é o bloco completo:
cd /var/www/membresia360
# 1. edite .env: VITE_PUBLIC_SITE_URL=https://SEU-DOMINIO.COM.BR
# 2. salve e saia do editor
NITRO_PRESET=node-server npm run build
pm2 restart membresia360
pm2 save
# 3. teste em https://SEU-DOMINIO.COM.BR/ssl-statuspm2 logs membresia360 --lines 100.Subdomínios e outros sites na mesma VPS
Você pode hospedar vários sites no mesmo servidor usando subdomínios. Cada subdomínio aponta para uma porta local diferente no Nginx, então o app principal continua na porta 3000 e os novos apps podem rodar nas portas 3001, 3002, etc.
Exemplo prático: criar o site de cifras no subdomínio cifras.apachedesenvolvedor.com.br, rodando na porta 3001.
Checklist antes de começar
- Defina o nome do novo site (ex.: cifras, blog, loja, eventos).
- Escolha uma porta livre (evite 3000; use 3001, 3002, 3003...).
- Tenha o repositório Git do novo site pronto.
- Confirme que o domínio principal já aponta para a VPS (Passo 9/16).
1. Criar o registro DNS do subdomínio
No painel do Registro.br (ou do seu registrador), adicione uma entrada do tipo A para o subdomínio, apontando para o mesmo IP da VPS:
Tipo: A
Nome: cifras
Valor: 91.98.120.163Se quiser também o www.cifras..., adicione outra entrada A com nome www.cifras.
2. Instalar o segundo app na VPS
O script abaixo clona um repositório, instala dependências, faz build e sobe o app no PM2 com uma porta exclusiva. Rode dentro da VPS:
cd /var/www/membresia360 && sudo bash public/scripts/setup-second-site.sh https://github.com/jogosdaunidade/cifras-igreja.git /var/www/cifras 3001 cifras⚠️ Ajuste os valores: troque o repositório, a pasta, a porta e o nome do processo PM2 conforme o seu projeto. A porta deve ser diferente de 3000.
3. Criar o subdomínio no Nginx e emitir SSL
Com o app rodando na porta 3001, configure o Nginx para ouvir o subdomínio e encaminhar para essa porta. O script já faz isso e emite o SSL:
cd /var/www/membresia360 && sudo bash public/scripts/add-subdomain.sh cifras.apachedesenvolvedor.com.br 3001 neuzinaldo@gmail.comO script cria o arquivo de configuração em /etc/nginx/sites-available/cifras.apachedesenvolvedor.com.br, ativa no Nginx, emite o certificado SSL e aplica o redirect HTTP → HTTPS.
4. Testar o novo site
Aguarde a propagação do DNS (pode levar alguns minutos) e abra:
https://cifras.apachedesenvolvedor.com.brVerifique se o PM2 está rodando com pm2 status e se o Nginx não tem erros de configuração com sudo nginx -t.
5. Manutenção futura
Para atualizar o segundo site, rode os comandos dentro da pasta dele (não dentro de /var/www/membresia360):
cd /var/www/cifras
git pull
npm install
NITRO_PRESET=node-server npm run build
pm2 restart cifras
pm2 save6. Gerenciar sites na mesma VPS
Para ver todos os sites, subdomínios e processos ativos em um só lugar:
cd /var/www/membresia360 && sudo bash public/scripts/list-sites.shPara remover um subdomínio (e seus certificados SSL):
cd /var/www/membresia360 && sudo bash public/scripts/remove-subdomain.sh cifras.apachedesenvolvedor.com.br| Site | Subdomínio | Porta | PM2 |
|---|---|---|---|
| Membresia 360 | apachedesenvolvedor.com.br | 3000 | membresia360 |
| Cifras | cifras.apachedesenvolvedor.com.br | 3001 | cifras |
| Blog | blog.apachedesenvolvedor.com.br | 3002 | blog |
Cloudflare: DNS, cache e proteção
A Cloudflare fica na frente da sua VPS: cuida do DNS, acelera o site com CDN mundial, esconde o IP real do servidor e bloqueia ataques (DDoS, bots). É grátis no plano básico.
Antes de começar, tenha em mãos
- O domínio já registrado (ex.:
apachedesenvolvedor.com.br). - Login do Registro.br para trocar os nameservers.
- IP da sua VPS (ex.:
91.98.120.163). - SSL do Certbot já ativo na VPS (Passo 16).
- ~20 minutos para propagar o DNS.
Criar conta grátis na Cloudflare
- Abra dash.cloudflare.com/sign-up.
- Cadastre e-mail + senha, confirme o e-mail.
- No painel, clique em Add a Site / Adicionar Site.
✅ Checagem: você caiu no painel principal com um botão azul + Add site.
Adicionar o domínio e escolher plano Free
- Digite somente o domínio raiz, sem
wwwe semhttps://— ex.:apachedesenvolvedor.com.br. - Clique em Continue.
- Na lista de planos, role até o fim e clique em Free · $0/month.
- Clique em Continue novamente.
✅ Checagem: a Cloudflare vai escanear os DNS e mostrar uma lista de registros já existentes.
Conferir / adicionar os registros DNS
Verifique se existem estes registros. Se faltar algum, clique em Add record e crie:
| Tipo | Nome | Conteúdo (IPv4) | Proxy | TTL |
|---|---|---|---|---|
| A | @ | 91.98.120.163 | 🟠 Proxied | Auto |
| A | www | 91.98.120.163 | 🟠 Proxied | Auto |
| A | cifras (opcional) | 91.98.120.163 | 🟠 Proxied | Auto |
🟠 Proxied (laranja): passa pela Cloudflare (cache + proteção).
⚪ DNS only (cinza): só resolve o IP. Use cinza em registros de e-mail (mail, MX).
Depois clique em Continue.
Trocar os nameservers no Registro.br (passo mais importante)
A Cloudflare vai mostrar 2 nameservers pessoais (parecidos com ana.ns.cloudflare.com e rick.ns.cloudflare.com). Copie os dois exatamente como aparecem.
- Abra registro.br e faça login.
- Vá em Meus Domínios → clique no seu domínio → aba DNS.
- Escolha a opção Configurar DNS → Usar outros servidores DNS.
- Apague os servidores atuais (
a.dns.br,b.dns.br) e cole os dois da Cloudflare. - Salve.
- Volte na Cloudflare e clique em Done, check nameservers.
⏱️ Propagação: 15 min a 24 h. A Cloudflare manda um e-mail dizendo "Great news! Cloudflare is now protecting your site" quando o domínio ficar Active.
🔎 Checagem manual: abra whatsmydns.net, digite seu domínio e escolha NS. Deve retornar nomes com .cloudflare.com.
Configurar SSL como Full (strict)
- No painel do domínio, menu lateral: SSL/TLS → Overview.
- Marque Full (strict).
❌ Nunca use Flexible — causa loop de redirect com o Nginx da VPS.
✅ Só use Full (strict) depois do Certbot rodar OK (Passo 16).
Ativar HTTPS obrigatório e otimizações
Ainda em SSL/TLS → Edge Certificates, ative estes 3 switches:
- Always Use HTTPS — força HTTP → HTTPS para todo mundo.
- Automatic HTTPS Rewrites — corrige links antigos
http://no HTML. - Minimum TLS Version: selecione 1.2.
Depois vá em Speed → Optimization e ative:
- Auto Minify → marque JavaScript, CSS e HTML.
- Brotli → ligado.
Toda vez que publicar: limpar o cache
A Cloudflare guarda uma cópia dos arquivos. Depois de um pm2 restart, faça:
No navegador, aperte Ctrl+F5 para pegar a nova versão.
(Opcional) Mostrar o IP real do visitante no Nginx
Com o proxy laranja, o Nginx passa a receber os IPs da Cloudflare em vez do IP real. Para consertar, rode uma única vez na VPS:
sudo bash -c 'cat > /etc/nginx/cloudflare-realip.conf <<EOF
$(for ip in $(curl -s https://www.cloudflare.com/ips-v4); do echo "set_real_ip_from $ip;"; done)
$(for ip in $(curl -s https://www.cloudflare.com/ips-v6); do echo "set_real_ip_from $ip;"; done)
real_ip_header CF-Connecting-IP;
EOF'
# inclui o arquivo dentro do bloco http { } do nginx.conf
sudo sed -i '/http {/a \ include /etc/nginx/cloudflare-realip.conf;' /etc/nginx/nginx.conf
# valida e recarrega
sudo nginx -t && sudo systemctl reload nginxRode somente uma vez. Se rodar de novo, vai duplicar a linha include no nginx.conf.
Testar se a Cloudflare está ativa
- Abra o site no navegador.
- Botão direito → Inspecionar → aba Network.
- Aperte F5.
- Clique na primeira requisição (o próprio domínio).
- Em Response Headers, procure:
server: cloudflare
cf-cache-status: HIT # HIT = veio do cache; MISS = veio da VPS
cf-ray: 8f2a1b3c4d5e-GRU✅ Se aparecer server: cloudflare, está funcionando.
🏆 Teste também em ssllabs.com/ssltest — nota esperada: A ou A+.
Erros comuns e como resolver
| Erro | Causa | Solução |
|---|---|---|
| ERR_TOO_MANY_REDIRECTS | SSL Flexible ligado | Trocar para Full (strict) no passo 5 |
| Error 521 · Web server is down | App Node caiu | pm2 restart membresia360 |
| Error 522 · Connection timed out | Firewall bloqueia Cloudflare | sudo ufw allow 443 && sudo ufw allow 80 |
| Error 525 · SSL handshake failed | Certbot ainda não rodou | Rode o Passo 16 antes de marcar Full (strict) |
| Nameservers ainda não trocaram | Propagação lenta | Aguarde e clique em Recheck nameservers |