#!/bin/bash # ============================================================= # Chatc2 - Instalacao automatizada para Ubuntu 22.04 LTS # Uso: curl -sL https://bit.ly/chatc2-install | bash # ou: wget -qO- https://bit.ly/chatc2-install | bash # ============================================================= set -euo pipefail # ████████████████████████████████████████████████████ # VARIAVEIS # ████████████████████████████████████████████████████ CHATC2_USER="chatc2" CHATC2_DIR="/home/$CHATC2_USER/chatc2" CHATC2_REPO="https://github.com/seu-usuario/chatc2/archive/refs/heads/main.tar.gz" NODE_VERSION="22" FIREBIRD_VERSION="3.0" WHISPER_VERSION="1.5.4" WHISPER_MODEL="ggml-tiny.bin" # 75MB - troque para ggml-base.bin (142MB) para mais precisao SERVER_DOMAIN="${SERVER_DOMAIN:-}" # Opcional: seu-dominio.com.br JWT_SECRET="" NGROK_URL="" # PostgreSQL EXTERNO (banco principal "novo_local"). # Informe via variaveis de ambiente antes de rodar, ou edite o .env depois. PG_HOST="${PG_HOST:-}" PG_PORT="${PG_PORT:-5432}" PG_USER="${PG_USER:-postgres}" PG_PASSWORD="${PG_PASSWORD:-}" PG_DATABASE="${PG_DATABASE:-postgres}" PG_SCHEMA="${PG_SCHEMA:-public}" # Cores RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' log() { echo -e "${GREEN}[✓]${NC} $1"; } warn() { echo -e "${YELLOW}[!]${NC} $1"; } err() { echo -e "${RED}[✘]${NC} $1"; exit 1; } info() { echo -e "${CYAN}[i]${NC} $1"; } # ████████████████████████████████████████████████████ # VERIFICACAO INICIAL # ████████████████████████████████████████████████████ if [ "$EUID" -ne 0 ]; then err "Execute como root: sudo bash install.sh" fi echo "" echo "╔══════════════════════════════════════════════════╗" echo "║ Chatc2 - Instalacao Automatica ║" echo "║ Ubuntu 22.04 LTS ║" echo "╚══════════════════════════════════════════════════╝" echo "" # ████████████████████████████████████████████████████ # PASSO 1: SYSTEMA BASE # ████████████████████████████████████████████████████ info "Passo 1/12: Atualizando sistema..." apt-get update -y apt-get upgrade -y apt-get install -y curl wget git unzip tar gzip \ build-essential python3 python3-pip \ ffmpeg nginx ufw certbot python3-certbot-nginx \ firebird3.0-server firebird3.0-utils # ████████████████████████████████████████████████████ # PASSO 2: NODE.JS # ████████████████████████████████████████████████████ info "Passo 2/12: Instalando Node.js $NODE_VERSION..." curl -fsSL "https://deb.nodesource.com/setup_${NODE_VERSION}.x" | bash - apt-get install -y nodejs npm install -g pm2 log "Node.js $(node -v) instalado" # ████████████████████████████████████████████████████ # PASSO 3: FIREBIRD # ████████████████████████████████████████████████████ info "Passo 3/12: Configurando Firebird..." systemctl enable firebird3.0 systemctl start firebird3.0 2>/dev/null || true sleep 2 sed -i 's/^isc_password =.*/isc_password = masterkey/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true sed -i 's/^RemoteBindAddress = localhost/RemoteBindAddress = 0.0.0.0/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true # ── Correção de compatibilidade node-firebird + Firebird 3.0 ── # Usa Legacy_Auth (mais compatível) em vez de Srp256 (não suportado pelo node-firebird) sed -i 's/^#AuthServer = Srp$/AuthServer = Legacy_Auth/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true sed -i 's/^#AuthClient = Srp, Srp256, Legacy_Auth #Non Windows clients$/AuthClient = Legacy_Auth/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true # WireCrypt = Enabled (compatível com Legacy_Auth — não exige criptografia) sed -i 's/^#WireCrypt = Enabled (for client) \/ Required (for server)$/WireCrypt = Enabled/' /etc/firebird/3.0/firebird.conf 2>/dev/null || true systemctl restart firebird3.0 log "Firebird 3.0 configurado (senha: masterkey, auth: Legacy_Auth, WireCrypt: Enabled)" # Garante que o Firebird esta rodando antes de continuar systemctl restart firebird3.0 2>/dev/null || systemctl start firebird3.0 2>/dev/null || true sleep 1 # ████████████████████████████████████████████████████ # PASSO 4: USUARIO E DIRETORIOS # ████████████████████████████████████████████████████ info "Passo 4/12: Criando usuario e diretorios..." id -u "$CHATC2_USER" &>/dev/null || useradd -m -s /bin/bash "$CHATC2_USER" mkdir -p "$CHATC2_DIR"/{db,logs,tmp,uploads/audio,public,whisper/models,scripts,app/config,app/controllers,app/routes,app/middlewares} chown -R "$CHATC2_USER:$CHATC2_USER" "$CHATC2_DIR" # ████████████████████████████████████████████████████ # PASSO 5: WHISPER.CPP (Transcricao de Audio) # ████████████████████████████████████████████████████ info "Passo 5/12: Instalando Whisper.cpp (compilacao nativa Linux)..." mkdir -p "$CHATC2_DIR/whisper/models" # Compila whisper.cpp do source (Linux) - binario nativo if [ ! -f "$CHATC2_DIR/whisper/main" ]; then info "Compilando whisper.cpp v${WHISPER_VERSION}..." cd /tmp rm -rf whisper-build 2>/dev/null || true git clone --depth 1 --branch v${WHISPER_VERSION} https://github.com/ggerganov/whisper.cpp.git whisper-build 2>&1 | tail -1 cd whisper-build make -j$(nproc) main 2>&1 | tail -3 cp -f main "$CHATC2_DIR/whisper/main" chmod +x "$CHATC2_DIR/whisper/main" cd /tmp && rm -rf whisper-build log "Whisper.cpp compilado e instalado em $CHATC2_DIR/whisper/main" else log "Whisper.cpp binario Linux ja existe, pulando compilacao" fi info "Baixando modelo $WHISPER_MODEL (pode levar alguns minutos)..." if [ ! -f "$CHATC2_DIR/whisper/models/$WHISPER_MODEL" ]; then su - "$CHATC2_USER" -c "cd $CHATC2_DIR/whisper && \ curl -sL -o models/$WHISPER_MODEL \ https://huggingface.co/ggerganov/whisper.cpp/resolve/main/$WHISPER_MODEL" log "Modelo $WHISPER_MODEL baixado" else log "Modelo $WHISPER_MODEL ja existe" fi log "Whisper.cpp instalado em $CHATC2_DIR/whisper/" # ████████████████████████████████████████████████████ # PASSO 6: ARQUIVOS DO PROJETO # ████████████████████████████████████████████████████ info "Passo 6/12: Preparando para receber arquivos..." info "Transfira os arquivos do projeto para $CHATC2_DIR via SCP/SFTP" info "Depois execute manualmente: cd $CHATC2_DIR && npm install" echo "" echo " ╔══════════════════════════════════════════════════════════╗" echo " ║ Comando para enviar os arquivos (do seu computador): ║" echo " ║ ║" echo " ║ cd C:/projects/Chatc2 ║" echo " ║ scp -r src/ scripts/ package.json package-lock.json ║" echo " ║ .env.example deploy-linux/ ║" echo " ║ root@:$CHATC2_DIR/ ║" echo " ║ ║" echo " ║ E depois rode novamente este script: ║" echo " ║ bash $0 --continue ║" echo " ╚══════════════════════════════════════════════════════════╝" echo "" # Se o script foi chamado com --continue, pula a espera if [ "${1:-}" != "--continue" ]; then info "Aguardando transferencia dos arquivos..." info "Apos transferir, execute: bash $0 --continue" exit 0 fi # ████████████████████████████████████████████████████ # PASSO 7: NPM INSTALL # ████████████████████████████████████████████████████ if [ ! -f "$CHATC2_DIR/package.json" ]; then err "Arquivos do projeto nao encontrados em $CHATC2_DIR. Transfira via SCP primeiro." fi info "Passo 7/12: Instalando dependencias Node..." chown -R "$CHATC2_USER:$CHATC2_USER" "$CHATC2_DIR" # Remove node_modules anterior (se existir) para garantir instalação limpa if [ -d "$CHATC2_DIR/node_modules" ]; then info "Removendo node_modules anterior para instalacao limpa..." rm -rf "$CHATC2_DIR/node_modules" fi # Executa npm install com saida completa (sem suprimir erros) if ! su - "$CHATC2_USER" -c "cd $CHATC2_DIR && npm install"; then err "Falha ao instalar dependencias Node. Verifique a conexao e o package.json" fi # Verifica se modulos criticos foram instalados if [ ! -d "$CHATC2_DIR/node_modules/express" ]; then err "Modulo 'express' nao encontrado apos npm install. Verifique o package.json" fi if [ ! -d "$CHATC2_DIR/node_modules/dotenv" ]; then info "Instalando dotenv (carregamento de .env)..." su - "$CHATC2_USER" -c "cd $CHATC2_DIR && npm install dotenv" || warn "Falha ao instalar dotenv" fi # Garante que o server.js carrega dotenv (variaveis do .env) SERVER_JS="$CHATC2_DIR/src/server.js" if [ -f "$SERVER_JS" ] && ! grep -q "require('dotenv').config()" "$SERVER_JS" 2>/dev/null; then sed -i "1s/^/require('dotenv').config();\n/" "$SERVER_JS" log "dotenv configurado no server.js" fi log "Dependencias instaladas e verificadas" # ── Patch node-firebird: compatibilidade com Firebird 3.0 + sintaxe Node 22 ── info "Passo 7b/12: Aplicando patches node-firebird..." if [ -f "$(dirname "$0")/patch_node_firebird.py" ]; then python3 "$(dirname "$0")/patch_node_firebird.py" "$CHATC2_DIR" 2>&1 log "Patches node-firebird aplicados" else warn "patch_node_firebird.py nao encontrado" fi # ── wireCrypt (Firebird 3.0) ── # A partir da v2.0 a camada de banco foi unificada em src/database.js e o # wireCrypt já vem embutido nos defaults do driver Firebird — nada a patchar. info "Passo 7c/12: wireCrypt (Firebird) já embutido em src/database.js" log "Nenhum patch de wireCrypt necessário" # ████████████████████████████████████████████████████ # PASSO 8: ARQUIVO .ENV # ████████████████████████████████████████████████████ info "Passo 8/12: Configurando .env..." JWT_SECRET="CHATc2_$(date +%s)_$(openssl rand -hex 16)" # Detecta IPs da maquina LOCAL_IP=$(ip -4 addr show scope global | grep -oP 'inet \K[\d.]+' | head -1) [ -z "$LOCAL_IP" ] && LOCAL_IP="127.0.0.1" PUBLIC_IP=$(curl -s ifconfig.me 2>/dev/null || echo "") # Monta URLs LOCAL_URL="http://${LOCAL_IP}:3000" if [ -n "$SERVER_DOMAIN" ]; then EXTERNAL_URL="https://${SERVER_DOMAIN}" elif [ -n "$PUBLIC_IP" ]; then EXTERNAL_URL="http://${PUBLIC_IP}" else EXTERNAL_URL="http://${LOCAL_IP}:3000" fi # Sempre gera um .env limpo (remove paths Windows, comentarios invalidos, etc.) if [ -f "$CHATC2_DIR/.env" ]; then info ".env existente encontrado — fazendo backup e recriando..." cp "$CHATC2_DIR/.env" "$CHATC2_DIR/.env.bak.$(date +%Y%m%d%H%M%S)" 2>/dev/null || true fi cat > "$CHATC2_DIR/.env" << EOF # ============================================================ # Configuracao do Chatc2 # ============================================================ # Driver padrao do banco principal DB_DRIVER=postgres # ------------------------------------------------------------ # PostgreSQL (EXTERNO) — banco principal "novo_local" # ------------------------------------------------------------ PG_HOST=${PG_HOST} PG_PORT=${PG_PORT} PG_USER=${PG_USER} PG_PASSWORD=${PG_PASSWORD} PG_DATABASE=${PG_DATABASE} PG_SCHEMA=${PG_SCHEMA} # ------------------------------------------------------------ # Firebird (legado / alias "firebird_local") # ------------------------------------------------------------ DB_HOST=localhost DB_PORT=3050 DB_USER=SYSDBA DB_PASSWORD=masterkey DB_ENCODING=UTF-8 # Caminho do .FDB (vazio = usa ../NOVO.FDB na raiz do projeto) DB_DATABASE= # Servidor PORT=3000 JWT_SECRET=$JWT_SECRET JWT_EXPIRES_IN=1h # URLs de acesso LOCAL_URL=${LOCAL_URL} EXTERNAL_URL=${EXTERNAL_URL} # ------------------------------------------------------------ # Seguranca (opcionais) # ------------------------------------------------------------ # Origens permitidas no CORS (vazio = usa LOCAL_URL + EXTERNAL_URL) # CORS_ORIGINS=${EXTERNAL_URL} # Token de verificacao do webhook Evolution (header apikey) # WEBHOOK_TOKEN= EOF chown "$CHATC2_USER:$CHATC2_USER" "$CHATC2_DIR/.env" log "Arquivo .env criado/atualizado com JWT_SECRET seguro" log " PG_HOST/DB = ${PG_HOST:-(vazio)} / ${PG_DATABASE} (schema: ${PG_SCHEMA})" log " LOCAL_URL = ${LOCAL_URL}" log " EXTERNAL_URL = ${EXTERNAL_URL}" if [ -z "$PG_HOST" ] || [ -z "$PG_PASSWORD" ]; then warn "PostgreSQL externo nao configurado: edite $CHATC2_DIR/.env (PG_HOST, PG_PASSWORD, PG_DATABASE, PG_SCHEMA) antes de iniciar." fi # ████████████████████████████████████████████████████ # PASSO 9: MIGRACOES DO BANCO # ████████████████████████████████████████████████████ # ── Permissões dos arquivos .FDB ── info "Passo 8b/12: Ajustando permissoes dos arquivos .FDB..." # O Firebird roda como usuario 'firebird'. Os arquivos .FDB precisam # pertencer ao grupo firebird com permissao de leitura+escrita (660). if ls "$CHATC2_DIR/db/"*.FDB 2>/dev/null; then chown "$CHATC2_USER:firebird" "$CHATC2_DIR/db/"*.FDB 2>/dev/null || true chmod 660 "$CHATC2_DIR/db/"*.FDB 2>/dev/null || true # Garante que o diretório db/ também seja acessível chmod 750 "$CHATC2_DIR/db/" 2>/dev/null || true log "Permissoes ajustadas: $CHATC2_USER:firebird 660" else warn "Nenhum arquivo .FDB encontrado em $CHATC2_DIR/db/ — copie os bancos manualmente" warn "Apos copiar, execute: chown $CHATC2_USER:firebird $CHATC2_DIR/db/*.FDB && chmod 660 $CHATC2_DIR/db/*.FDB" fi info "Passo 9/12: Migracoes (Firebird legado)..." # O schema do PostgreSQL e gerenciado no banco EXTERNO — nao migramos aqui. # Migracoes Firebird so rodam se houver um .FDB local (alias firebird_local). if ls "$CHATC2_DIR/db/"*.FDB "$CHATC2_DIR/"*.FDB >/dev/null 2>&1; then if [ -f "$CHATC2_DIR/scripts/migracoes.js" ]; then su - "$CHATC2_USER" -c "cd $CHATC2_DIR && node scripts/migracoes.js firebird_local 2>&1 | tail -10" || warn "Migracoes Firebird podem ter falhado" log "Migracoes Firebird executadas" fi else info "Sem .FDB local — pulando migracoes Firebird (schema do Postgres e externo)." fi # ████████████████████████████████████████████████████ # PASSO 9b: HABILITAR USUARIOS ADMIN PARA WEB # ████████████████████████████████████████████████████ info "Passo 9b/12: Habilitando usuarios admin para acesso web..." # Habilita acesso web para admins (Postgres principal e Firebird se presente) cat > /tmp/chatc2-habilitar-web.js << 'SCRIPTJS' const db = require('DATABASE_PATH'); (async () => { const alias = process.argv[2]; if (!alias) { console.log('Uso: node script '); process.exit(1); } try { // Habilita USU_ACESSO_WEB = 1 para usuarios ativos com perfil admin (USU_TIPO = A) const result = await db.query(alias, "SELECT USU_CODIGO_ID, USU_NOME, USU_LOGIN FROM USUARIOS WHERE USU_STATUS = 'A' AND USU_TIPO = 'A' AND COALESCE(USU_ACESSO_WEB, 0) = 0"); for (const u of result) { await db.execute(alias, 'UPDATE USUARIOS SET USU_ACESSO_WEB = 1 WHERE USU_CODIGO_ID = ?', [u.USU_CODIGO_ID]); console.log(' ✅ ' + u.USU_NOME.trim() + ' (' + u.USU_LOGIN.trim() + ') — acesso web habilitado'); } if (result.length === 0) console.log(' Nenhum usuario admin pendente.'); process.exit(0); } catch(e) { console.error('Erro:', e.message); process.exit(1); } })(); SCRIPTJS sed -i "s|DATABASE_PATH|$CHATC2_DIR/src/database|" /tmp/chatc2-habilitar-web.js # Postgres externo (alias principal) su - "$CHATC2_USER" -c "cd $CHATC2_DIR && node /tmp/chatc2-habilitar-web.js novo_local" 2>&1 || true # Firebird local (apenas se houver .FDB) if ls "$CHATC2_DIR/db/"*.FDB "$CHATC2_DIR/"*.FDB >/dev/null 2>&1; then su - "$CHATC2_USER" -c "cd $CHATC2_DIR && node /tmp/chatc2-habilitar-web.js firebird_local" 2>&1 || true fi rm -f /tmp/chatc2-habilitar-web.js log "Usuarios admin verificados (Postgres + Firebird se presente)" # ████████████████████████████████████████████████████ # PASSO 10: NGINX # ████████████████████████████████████████████████████ info "Passo 10/12: Configurando Nginx..." cat > /etc/nginx/sites-available/chatc2 << 'NGINX' server { listen 80; server_name _; client_max_body_size 100M; 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; proxy_read_timeout 86400s; proxy_send_timeout 86400s; } } NGINX # Remove sites padrao que podem conflitar rm -f /etc/nginx/sites-enabled/default 2>/dev/null || true rm -f /etc/nginx/sites-enabled/example.com 2>/dev/null || true # Habilita o site do chatc2 if [ ! -L /etc/nginx/sites-enabled/chatc2 ]; then ln -sf /etc/nginx/sites-available/chatc2 /etc/nginx/sites-enabled/ fi # Testa configuracao antes de aplicar if nginx -t 2>&1; then systemctl enable nginx 2>/dev/null || true systemctl restart nginx 2>/dev/null || systemctl start nginx 2>/dev/null || true log "Nginx configurado e iniciado" else warn "Erro na configuracao do nginx. Verifique manualmente: nginx -t" fi # SSL com Let's Encrypt (se dominio foi informado) if [ -n "${SERVER_DOMAIN:-}" ]; then info "Configurando SSL para $SERVER_DOMAIN..." certbot --nginx -d "$SERVER_DOMAIN" --non-interactive --agree-tos \ --email "admin@${SERVER_DOMAIN}" || warn "SSL falhou (verifique DNS)" log "SSL configurado para $SERVER_DOMAIN" fi # ████████████████████████████████████████████████████ # PASSO 11: PM2 (INICIO AUTOMATICO) # ████████████████████████████████████████████████████ info "Passo 11/12: Configurando PM2..." # Para processos anteriores (se existirem) pm2 delete chatc2 2>/dev/null || true # Inicia a aplicacao com PM2 como root (script ja exige root) cd "$CHATC2_DIR" if ! pm2 start src/server.js --name chatc2 --max-memory-restart 512M --time 2>&1; then err "Falha ao iniciar a aplicacao com PM2. Verifique os logs." fi # Aguarda o servidor iniciar e verifica se esta ouvindo na porta 3000 sleep 2 if ss -tlnp | grep -q ':3000'; then log "Servidor Node.js ouvindo na porta 3000" else warn "Servidor pode nao estar ouvindo na porta 3000. Verifique: pm2 logs chatc2" fi # Salva a lista de processos e configura inicio automatico no boot pm2 save 2>/dev/null || true pm2 startup systemd -u root --hp /root 2>/dev/null || true log "PM2 configurado - aplicacao iniciara automaticamente no boot" # ████████████████████████████████████████████████████ # PASSO 12: FIREWALL # ████████████████████████████████████████████████████ info "Passo 12/12: Configurando firewall..." ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw allow 3000/tcp ufw --force enable log "Firewall configurado (portas: 22, 80, 443, 3000)" # ████████████████████████████████████████████████████ # FINAL # ████████████████████████████████████████████████████ PUBLIC_IP=$(curl -s ifconfig.me 2>/dev/null || echo "") echo "" echo "╔══════════════════════════════════════════════════╗" echo "║ Chatc2 - Instalacao Concluida! ║" echo "╚══════════════════════════════════════════════════╝" echo "" echo " 📍 Acessar: http://$PUBLIC_IP" echo " 📁 Diretorio: $CHATC2_DIR" echo " 👤 Usuario: $CHATC2_USER" echo " 🗄️ Firebird: senha: masterkey" echo " 🎤 Whisper: modelo $WHISPER_MODEL" echo "" echo " 📋 Proximos passos:" echo " 1. Copie seus bancos .FDB para $CHATC2_DIR/db/" echo " 2. Edite $CHATC2_DIR/.env se necessario" echo " 3. Crie usuario admin: node $CHATC2_DIR/scripts/gerar-token-usuario.js" echo " 4. Configure o webhook na Evolution API:" echo " POST http://$PUBLIC_IP/api/webhook/evolution" echo " 5. Logs: pm2 logs chatc2" echo " 6. Parar: pm2 stop chatc2" echo " 7. Reset: pm2 restart chatc2" echo ""