up
This commit is contained in:
Executable
+394
@@ -0,0 +1,394 @@
|
||||
#!/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
|
||||
Reference in New Issue
Block a user