- entrypoint.sh: Redis wait tenía loop infinito sin timeout → el contenedor se quedaba colgado para siempre si Redis tardaba, causando 504 Gateway Timeout Ahora tiene MAX_RETRIES=15 (30s) y continúa aunque Redis no esté disponible - entrypoint.sh: removido set -e para que errores no-críticos (permisos, SSL, etc.) no maten el arranque del contenedor - docker-compose.yml: removido depends_on redis con condition:service_healthy Docker bloqueaba el inicio de app hasta que Redis estuviera healthy, lo que podía exceder el timeout de Traefik
159 lines
6.0 KiB
Bash
Executable File
159 lines
6.0 KiB
Bash
Executable File
#!/bin/bash
|
||
# Entrypoint script para el contenedor
|
||
# set -e removido: comandos no críticos (permisos, SSL) no deben matar el arranque
|
||
|
||
echo "🚀 Iniciando WhatsApp Bot Manager..."
|
||
|
||
# Esperar a que Redis esté disponible (con timeout para no bloquear el arranque)
|
||
if [ "${REDIS_HOST:-redis}" != "" ]; then
|
||
echo "⏳ Esperando Redis..."
|
||
MAX_RETRIES=15
|
||
RETRY=0
|
||
until redis-cli -h ${REDIS_HOST:-redis} -p ${REDIS_PORT:-6379} ping 2>/dev/null | grep -q PONG; do
|
||
RETRY=$((RETRY + 1))
|
||
if [ $RETRY -ge $MAX_RETRIES ]; then
|
||
echo "⚠️ Redis no disponible después de $MAX_RETRIES intentos, continuando sin Redis..."
|
||
break
|
||
fi
|
||
echo " Redis no disponible, intento $RETRY/$MAX_RETRIES..."
|
||
sleep 2
|
||
done
|
||
if [ $RETRY -lt $MAX_RETRIES ]; then
|
||
echo "✅ Redis conectado"
|
||
fi
|
||
fi
|
||
|
||
# Esperar a que MySQL esté disponible
|
||
if [ "${DB_HOST}" = "mysql" ] || [ "${DB_HOST}" = "db" ]; then
|
||
echo "⏳ Esperando MySQL local..."
|
||
MAX_RETRIES=30
|
||
RETRY=0
|
||
until mariadb -h "${DB_HOST:-mysql}" -u "${DB_USER:-whatsapp_user}" -p"${DB_PASS}" --skip-ssl -e "SELECT 1" >/dev/null 2>&1; do
|
||
RETRY=$((RETRY + 1))
|
||
if [ $RETRY -ge $MAX_RETRIES ]; then
|
||
echo "⚠️ MySQL no disponible después de $MAX_RETRIES intentos, continuando..."
|
||
break
|
||
fi
|
||
echo " MySQL no disponible, intento $RETRY/$MAX_RETRIES..."
|
||
sleep 2
|
||
done
|
||
if [ $RETRY -lt $MAX_RETRIES ]; then
|
||
echo "✅ MySQL conectado"
|
||
fi
|
||
elif [ "${DB_HOST}" != "localhost" ] && [ "${DB_HOST}" != "127.0.0.1" ]; then
|
||
echo "ℹ️ Usando base de datos externa (${DB_HOST}), omitiendo verificación de conectividad..."
|
||
fi
|
||
|
||
# Crear directorios si no existen
|
||
mkdir -p /var/www/html/logs
|
||
mkdir -p /var/www/html/uploads
|
||
mkdir -p /var/cache/nginx
|
||
mkdir -p /run/php
|
||
mkdir -p /var/lib/nginx/tmp/client_body
|
||
mkdir -p /var/lib/nginx/tmp/proxy
|
||
mkdir -p /var/lib/nginx/tmp/fastcgi
|
||
mkdir -p /var/lib/nginx/tmp/uwsgi
|
||
mkdir -p /var/lib/nginx/tmp/scgi
|
||
|
||
# Establecer permisos ANTES de iniciar servicios
|
||
chown -R www:www /var/www/html/logs
|
||
chown -R www:www /var/www/html/uploads
|
||
chmod -R 775 /var/www/html/logs
|
||
chmod -R 775 /var/www/html/uploads
|
||
|
||
# IMPORTANTE: nginx necesita acceso a sus directorios temporales
|
||
# Usar grupo nginx para compartir acceso entre nginx y www
|
||
chown -R nginx:nginx /var/lib/nginx
|
||
chmod -R 775 /var/lib/nginx/tmp
|
||
|
||
# Generar certificados SSL si no existen
|
||
SSL_DIR="/etc/nginx/ssl"
|
||
if [ ! -f "$SSL_DIR/server.crt" ] || [ ! -f "$SSL_DIR/server.key" ]; then
|
||
echo "🔐 Generando certificados SSL autofirmados..."
|
||
mkdir -p "$SSL_DIR"
|
||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||
-keyout "$SSL_DIR/server.key" \
|
||
-out "$SSL_DIR/server.crt" \
|
||
-subj "/C=CO/ST=Cundinamarca/L=Bogota/O=U-Site/OU=WhatsApp Bot/CN=bot.u-s.app" \
|
||
-addext "subjectAltName=DNS:bot.u-s.app,DNS:localhost,DNS:*.u-s.app,IP:127.0.0.1" 2>/dev/null || \
|
||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||
-keyout "$SSL_DIR/server.key" \
|
||
-out "$SSL_DIR/server.crt" \
|
||
-subj "/C=CO/ST=Cundinamarca/L=Bogota/O=U-Site/OU=WhatsApp Bot/CN=bot.u-s.app"
|
||
chmod 600 "$SSL_DIR/server.key"
|
||
chmod 644 "$SSL_DIR/server.crt"
|
||
echo "✅ Certificados SSL generados para bot.u-s.app"
|
||
else
|
||
echo "✅ Certificados SSL existentes encontrados"
|
||
fi
|
||
|
||
# Ejecutar migraciones de BD (si existen)
|
||
if [ -f /var/www/html/database/migrate.php ]; then
|
||
echo "🔄 Ejecutando migraciones..."
|
||
php /var/www/html/database/migrate.php || echo "⚠️ Migraciones fallaron o no aplicables"
|
||
fi
|
||
|
||
# Generar archivo .env desde variables de entorno (si no existe)
|
||
if [ ! -f /var/www/html/.env ]; then
|
||
echo "📝 Generando .env desde variables de entorno..."
|
||
cat > /var/www/html/.env <<EOF
|
||
# Generado automáticamente por Docker
|
||
DB_HOST=${DB_HOST:-db}
|
||
DB_PORT=${DB_PORT:-3306}
|
||
DB_NAME=${DB_NAME:-whatsapp_bot}
|
||
DB_USER=${DB_USER:-whatsapp_user}
|
||
DB_PASS=${DB_PASS}
|
||
|
||
REDIS_HOST=${REDIS_HOST:-redis}
|
||
REDIS_PORT=${REDIS_PORT:-6379}
|
||
REDIS_PASSWORD=${REDIS_PASSWORD:-}
|
||
REDIS_DB=0
|
||
|
||
WHATSAPP_TOKEN=${WHATSAPP_TOKEN}
|
||
WHATSAPP_PHONE_NUMBER_ID=${WHATSAPP_PHONE_NUMBER_ID}
|
||
WEBHOOK_VERIFY_TOKEN=${WEBHOOK_VERIFY_TOKEN}
|
||
|
||
LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||
ENABLE_RATE_LIMIT=${ENABLE_RATE_LIMIT:-true}
|
||
EOF
|
||
chown www:www /var/www/html/.env
|
||
fi
|
||
|
||
# Verificar vendor/ — Coolify puede montar un volumen vacío sobre /var/www/html
|
||
# Si vendor/autoload.php no existe, regenerar dependencias
|
||
if [ ! -f /var/www/html/vendor/autoload.php ]; then
|
||
echo "⚠️ vendor/autoload.php no encontrado (volumen vacío de Coolify). Ejecutando composer install..."
|
||
cd /var/www/html && composer install --no-dev --optimize-autoloader --no-interaction 2>&1
|
||
echo "✅ Dependencias instaladas"
|
||
else
|
||
echo "✅ vendor/autoload.php presente"
|
||
fi
|
||
|
||
# Limpiar cache de OPcache
|
||
if [ -f /usr/local/bin/php ]; then
|
||
echo "🧹 Limpiando cache de OPcache..."
|
||
php -r "if(function_exists('opcache_reset')) opcache_reset();"
|
||
fi
|
||
|
||
# Configurar crontab para tareas programadas (usar /etc/crontabs/root para que crond lo ejecute como root)
|
||
echo "⏰ Configurando cron jobs..."
|
||
cat > /etc/crontabs/root <<EOF
|
||
# Procesar mensajes delayed cada minuto
|
||
* * * * * cd /var/www/html && /usr/local/bin/php -r "require 'vendor/autoload.php'; use WhatsApp\Queue\RedisQueue; \$q = new RedisQueue(); \$q->processDelayed('messages'); \$q->processDelayed('media');" >> /tmp/delayed_processor.log 2>&1
|
||
|
||
# Procesar cola de media pendiente cada 2 minutos
|
||
*/2 * * * * cd /var/www/html && /usr/local/bin/php scripts/media_worker.php >> /tmp/media_worker.log 2>&1
|
||
|
||
# Limpiar logs antiguos (diario a las 3 AM)
|
||
0 3 * * * cd /var/www/html && /usr/local/bin/php -r "require 'classes/LoggerFactory.php'; echo LoggerFactory::cleanup(30) . ' logs eliminados';" >> /tmp/log_cleanup.log 2>&1
|
||
|
||
# Health check de workers (cada 5 minutos)
|
||
*/5 * * * * supervisorctl status whatsapp-worker:* | grep -q RUNNING || supervisorctl restart whatsapp-worker:* >> /tmp/worker_monitor.log 2>&1
|
||
EOF
|
||
|
||
echo "✅ Configuración completada"
|
||
echo "🎯 Iniciando servicios..."
|
||
|
||
# Ejecutar comando pasado al contenedor
|
||
exec "$@"
|