395 lines
11 KiB
Bash
Executable File
395 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
#############################################################
|
|
# DEPLOY SCRIPT PARA VPS - WhatsApp Bot
|
|
#
|
|
# Uso: ./deploy-vps.sh [opciones]
|
|
#
|
|
# Opciones:
|
|
# --install Primera instalación (instala Docker, etc)
|
|
# --update Solo actualizar código y reiniciar
|
|
# --ssl Generar/renovar certificados SSL
|
|
# --logs Ver logs de la aplicación
|
|
# --status Ver estado de los contenedores
|
|
#############################################################
|
|
|
|
set -e
|
|
|
|
# ==================== CONFIGURACIÓN ====================
|
|
# Modificar estos valores según tu VPS
|
|
|
|
DOMAIN="bot.u-s.app" # Tu dominio
|
|
EMAIL="admin@u-s.app" # Email para Let's Encrypt
|
|
APP_DIR="/var/www/whatsapp" # Directorio de la app en VPS
|
|
COMPOSE_FILE="docker-compose.prod.yml"
|
|
|
|
# Colores para output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# ==================== FUNCIONES ====================
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[OK]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# Verificar que se ejecuta como root o con sudo
|
|
check_root() {
|
|
if [ "$EUID" -ne 0 ]; then
|
|
log_error "Este script debe ejecutarse como root o con sudo"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Instalar Docker y Docker Compose
|
|
install_docker() {
|
|
log_info "Instalando Docker..."
|
|
|
|
# Verificar si Docker ya está instalado
|
|
if command -v docker &> /dev/null; then
|
|
log_success "Docker ya está instalado: $(docker --version)"
|
|
else
|
|
curl -fsSL https://get.docker.com | sh
|
|
systemctl enable docker
|
|
systemctl start docker
|
|
log_success "Docker instalado correctamente"
|
|
fi
|
|
|
|
# Verificar Docker Compose
|
|
if command -v docker-compose &> /dev/null || docker compose version &> /dev/null; then
|
|
log_success "Docker Compose disponible"
|
|
else
|
|
log_info "Instalando Docker Compose plugin..."
|
|
apt-get update
|
|
apt-get install -y docker-compose-plugin
|
|
log_success "Docker Compose instalado"
|
|
fi
|
|
}
|
|
|
|
# Instalar Certbot para SSL
|
|
install_certbot() {
|
|
log_info "Instalando Certbot para SSL..."
|
|
|
|
if command -v certbot &> /dev/null; then
|
|
log_success "Certbot ya está instalado"
|
|
else
|
|
apt-get update
|
|
apt-get install -y certbot
|
|
log_success "Certbot instalado"
|
|
fi
|
|
}
|
|
|
|
# Generar certificados SSL con Let's Encrypt
|
|
generate_ssl() {
|
|
log_info "Generando certificados SSL para ${DOMAIN}..."
|
|
|
|
# Detener contenedores que usan puerto 80
|
|
cd "$APP_DIR"
|
|
docker compose -f "$COMPOSE_FILE" down 2>/dev/null || true
|
|
|
|
# Generar certificado
|
|
certbot certonly \
|
|
--standalone \
|
|
--preferred-challenges http \
|
|
--agree-tos \
|
|
--email "$EMAIL" \
|
|
-d "$DOMAIN" \
|
|
--non-interactive
|
|
|
|
if [ -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then
|
|
log_success "Certificado SSL generado correctamente"
|
|
|
|
# Crear directorio y copiar certificados
|
|
mkdir -p "$APP_DIR/docker/ssl"
|
|
cp "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" "$APP_DIR/docker/ssl/server.crt"
|
|
cp "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" "$APP_DIR/docker/ssl/server.key"
|
|
chmod 600 "$APP_DIR/docker/ssl/server.key"
|
|
|
|
log_success "Certificados copiados a docker/ssl/"
|
|
else
|
|
log_error "Error generando certificado SSL"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Renovar certificados SSL
|
|
renew_ssl() {
|
|
log_info "Renovando certificados SSL..."
|
|
|
|
cd "$APP_DIR"
|
|
docker compose -f "$COMPOSE_FILE" stop app 2>/dev/null || true
|
|
|
|
certbot renew --standalone
|
|
|
|
# Copiar certificados actualizados
|
|
if [ -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then
|
|
cp "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" "$APP_DIR/docker/ssl/server.crt"
|
|
cp "/etc/letsencrypt/live/${DOMAIN}/privkey.pem" "$APP_DIR/docker/ssl/server.key"
|
|
log_success "Certificados renovados"
|
|
fi
|
|
|
|
docker compose -f "$COMPOSE_FILE" start app
|
|
}
|
|
|
|
# Configurar cron para renovación automática de SSL
|
|
setup_ssl_cron() {
|
|
log_info "Configurando renovación automática de SSL..."
|
|
|
|
CRON_CMD="0 3 * * * cd $APP_DIR && docker compose -f $COMPOSE_FILE stop app && certbot renew --quiet && docker compose -f $COMPOSE_FILE start app"
|
|
|
|
# Añadir al crontab si no existe
|
|
(crontab -l 2>/dev/null | grep -v "certbot renew"; echo "$CRON_CMD") | crontab -
|
|
|
|
log_success "Cron configurado para renovar SSL cada día a las 3am"
|
|
}
|
|
|
|
# Crear archivo .env si no existe
|
|
create_env_file() {
|
|
if [ ! -f "$APP_DIR/.env" ]; then
|
|
log_info "Creando archivo .env..."
|
|
|
|
cat > "$APP_DIR/.env" << 'EOF'
|
|
# ============================================
|
|
# CONFIGURACIÓN DE PRODUCCIÓN
|
|
# ============================================
|
|
|
|
# Base de datos
|
|
DB_HOST=77.37.126.126
|
|
DB_PORT=3306
|
|
DB_NAME=usite_whatsapp_bot
|
|
DB_USER=usite_whatsapp_user
|
|
DB_PASS=6q!Vio0fn@PFmsLyHjH5
|
|
|
|
# Redis (opcional, dejar vacío si no usa password)
|
|
REDIS_PASSWORD=
|
|
|
|
# WhatsApp API (obtener de Facebook Developer)
|
|
WHATSAPP_TOKEN=
|
|
WHATSAPP_PHONE_NUMBER_ID=
|
|
WEBHOOK_VERIFY_TOKEN=
|
|
EOF
|
|
|
|
log_warn "Archivo .env creado. ¡EDITA LAS CREDENCIALES antes de continuar!"
|
|
log_warn "Ejecuta: nano $APP_DIR/.env"
|
|
else
|
|
log_success "Archivo .env ya existe"
|
|
fi
|
|
}
|
|
|
|
# Crear directorios necesarios
|
|
create_directories() {
|
|
log_info "Creando directorios..."
|
|
|
|
mkdir -p "$APP_DIR/logs"
|
|
mkdir -p "$APP_DIR/uploads"
|
|
mkdir -p "$APP_DIR/docker/ssl"
|
|
|
|
# Permisos
|
|
chown -R www-data:www-data "$APP_DIR/logs" 2>/dev/null || true
|
|
chown -R www-data:www-data "$APP_DIR/uploads" 2>/dev/null || true
|
|
chmod -R 755 "$APP_DIR/logs"
|
|
chmod -R 755 "$APP_DIR/uploads"
|
|
|
|
log_success "Directorios creados"
|
|
}
|
|
|
|
# Construir y levantar contenedores
|
|
deploy() {
|
|
log_info "Desplegando aplicación..."
|
|
|
|
cd "$APP_DIR"
|
|
|
|
# Construir imágenes
|
|
log_info "Construyendo imágenes Docker..."
|
|
docker compose -f "$COMPOSE_FILE" build --no-cache
|
|
|
|
# Detener contenedores existentes
|
|
log_info "Deteniendo contenedores anteriores..."
|
|
docker compose -f "$COMPOSE_FILE" down --remove-orphans 2>/dev/null || true
|
|
|
|
# Levantar nuevos contenedores
|
|
log_info "Levantando contenedores..."
|
|
docker compose -f "$COMPOSE_FILE" up -d
|
|
|
|
# Esperar a que estén listos
|
|
log_info "Esperando a que los servicios estén listos..."
|
|
sleep 10
|
|
|
|
# Verificar estado
|
|
if docker compose -f "$COMPOSE_FILE" ps | grep -q "Up"; then
|
|
log_success "Contenedores ejecutándose correctamente"
|
|
else
|
|
log_error "Error iniciando contenedores"
|
|
docker compose -f "$COMPOSE_FILE" logs --tail=50
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Actualizar código y reiniciar
|
|
update() {
|
|
log_info "Actualizando aplicación..."
|
|
|
|
cd "$APP_DIR"
|
|
|
|
# Si es un repo git, hacer pull
|
|
if [ -d ".git" ]; then
|
|
log_info "Actualizando desde Git..."
|
|
git pull origin main || git pull origin master
|
|
fi
|
|
|
|
# Reconstruir y reiniciar
|
|
docker compose -f "$COMPOSE_FILE" build
|
|
docker compose -f "$COMPOSE_FILE" up -d
|
|
|
|
log_success "Aplicación actualizada"
|
|
}
|
|
|
|
# Ver logs
|
|
show_logs() {
|
|
cd "$APP_DIR"
|
|
docker compose -f "$COMPOSE_FILE" logs -f --tail=100
|
|
}
|
|
|
|
# Ver estado
|
|
show_status() {
|
|
cd "$APP_DIR"
|
|
|
|
echo ""
|
|
echo "==================== ESTADO DE CONTENEDORES ===================="
|
|
docker compose -f "$COMPOSE_FILE" ps
|
|
|
|
echo ""
|
|
echo "==================== USO DE RECURSOS ===================="
|
|
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
|
|
|
|
echo ""
|
|
echo "==================== VERIFICACIÓN DE SERVICIOS ===================="
|
|
|
|
# Verificar HTTP
|
|
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost/health.php" 2>/dev/null || echo "ERROR")
|
|
if [ "$HTTP_STATUS" = "200" ]; then
|
|
log_success "HTTP: OK (status $HTTP_STATUS)"
|
|
else
|
|
log_error "HTTP: FALLO (status $HTTP_STATUS)"
|
|
fi
|
|
|
|
# Verificar HTTPS
|
|
HTTPS_STATUS=$(curl -sk -o /dev/null -w "%{http_code}" "https://localhost/health.php" 2>/dev/null || echo "ERROR")
|
|
if [ "$HTTPS_STATUS" = "200" ]; then
|
|
log_success "HTTPS: OK (status $HTTPS_STATUS)"
|
|
else
|
|
log_warn "HTTPS: $HTTPS_STATUS (puede necesitar certificados SSL)"
|
|
fi
|
|
|
|
echo ""
|
|
echo "==================== URLS ===================="
|
|
echo " App: https://${DOMAIN}"
|
|
echo " Health: https://${DOMAIN}/health.php"
|
|
}
|
|
|
|
# Primera instalación completa
|
|
full_install() {
|
|
check_root
|
|
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " INSTALACIÓN COMPLETA - WhatsApp Bot"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
install_docker
|
|
install_certbot
|
|
create_directories
|
|
create_env_file
|
|
|
|
echo ""
|
|
log_warn "ANTES DE CONTINUAR:"
|
|
log_warn "1. Edita el archivo .env con tus credenciales"
|
|
log_warn "2. Asegúrate que el dominio ${DOMAIN} apunta a este servidor"
|
|
echo ""
|
|
read -p "¿Continuar con el deploy? (s/n): " -n 1 -r
|
|
echo ""
|
|
|
|
if [[ $REPLY =~ ^[Ss]$ ]]; then
|
|
generate_ssl
|
|
setup_ssl_cron
|
|
deploy
|
|
show_status
|
|
else
|
|
log_info "Deploy cancelado. Ejecuta './deploy-vps.sh' cuando estés listo."
|
|
fi
|
|
}
|
|
|
|
# Mostrar ayuda
|
|
show_help() {
|
|
echo ""
|
|
echo "Uso: ./deploy-vps.sh [opción]"
|
|
echo ""
|
|
echo "Opciones:"
|
|
echo " --install Primera instalación completa"
|
|
echo " --update Actualizar código y reiniciar"
|
|
echo " --ssl Generar/renovar certificados SSL"
|
|
echo " --logs Ver logs en tiempo real"
|
|
echo " --status Ver estado de servicios"
|
|
echo " --help Mostrar esta ayuda"
|
|
echo ""
|
|
echo "Ejemplos:"
|
|
echo " sudo ./deploy-vps.sh --install # Primera vez"
|
|
echo " sudo ./deploy-vps.sh --update # Actualizar"
|
|
echo " ./deploy-vps.sh --logs # Ver logs"
|
|
echo ""
|
|
}
|
|
|
|
# ==================== MAIN ====================
|
|
|
|
case "${1:-}" in
|
|
--install)
|
|
full_install
|
|
;;
|
|
--update)
|
|
update
|
|
;;
|
|
--ssl)
|
|
check_root
|
|
generate_ssl
|
|
;;
|
|
--renew-ssl)
|
|
check_root
|
|
renew_ssl
|
|
;;
|
|
--logs)
|
|
show_logs
|
|
;;
|
|
--status)
|
|
show_status
|
|
;;
|
|
--help|-h)
|
|
show_help
|
|
;;
|
|
*)
|
|
# Sin argumentos, hacer deploy normal
|
|
if [ ! -d "$APP_DIR" ] || [ ! -f "$APP_DIR/$COMPOSE_FILE" ]; then
|
|
log_error "Directorio de aplicación no encontrado: $APP_DIR"
|
|
log_info "Para primera instalación usa: sudo ./deploy-vps.sh --install"
|
|
exit 1
|
|
fi
|
|
deploy
|
|
show_status
|
|
;;
|
|
esac
|