up
This commit is contained in:
Executable
+48
@@ -0,0 +1,48 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "🚀 Iniciando WhatsApp Bot - MODO DESARROLLO"
|
||||
echo "============================================="
|
||||
|
||||
# Esperar a que Redis esté disponible
|
||||
echo "⏳ Esperando Redis..."
|
||||
until nc -z redis 6379; do
|
||||
echo " Redis no disponible, reintentando..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✅ Redis disponible"
|
||||
|
||||
# Crear directorios necesarios
|
||||
echo "📁 Creando directorios..."
|
||||
mkdir -p /var/www/html/logs
|
||||
mkdir -p /var/www/html/uploads
|
||||
mkdir -p /run/php
|
||||
|
||||
# Establecer permisos
|
||||
echo "🔐 Configurando permisos..."
|
||||
chown -R www-data:www-data /var/www/html/logs
|
||||
chown -R www-data:www-data /var/www/html/uploads
|
||||
chmod -R 755 /var/www/html/logs
|
||||
chmod -R 755 /var/www/html/uploads
|
||||
|
||||
# Información de desarrollo
|
||||
echo ""
|
||||
echo "🛠️ HERRAMIENTAS DE DESARROLLO DISPONIBLES:"
|
||||
echo " - Aplicación: http://localhost:8080"
|
||||
echo " - XDebug: Puerto 9003"
|
||||
echo " - Redis Commander: http://localhost:8082"
|
||||
echo " - MailHog: http://localhost:8025"
|
||||
echo " - Adminer: http://localhost:8083"
|
||||
echo ""
|
||||
echo "📝 Configuración:"
|
||||
echo " - OPcache: Desactivado"
|
||||
echo " - Error Display: Activado"
|
||||
echo " - Log Level: DEBUG"
|
||||
echo " - Hot Reload: Activado"
|
||||
echo ""
|
||||
echo "============================================="
|
||||
echo "✅ Entorno de desarrollo listo"
|
||||
echo ""
|
||||
|
||||
# Ejecutar el comando principal
|
||||
exec "$@"
|
||||
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# Entrypoint script para el contenedor
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Iniciando WhatsApp Bot Manager..."
|
||||
|
||||
# Esperar a que Redis esté disponible
|
||||
echo "⏳ Esperando Redis..."
|
||||
until redis-cli -h ${REDIS_HOST:-redis} ping 2>/dev/null; do
|
||||
echo " Redis no disponible, esperando..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✅ Redis conectado"
|
||||
|
||||
# Esperar a que MySQL esté disponible (solo si no es localhost ni IP interna)
|
||||
if [ "${DB_HOST}" != "localhost" ] && [ "${DB_HOST}" != "127.0.0.1" ] && [ "${DB_HOST}" != "db" ]; then
|
||||
echo "ℹ️ Usando base de datos externa (${DB_HOST}), omitiendo verificación de conectividad..."
|
||||
else
|
||||
echo "⏳ Esperando MySQL..."
|
||||
until mysql -h ${DB_HOST:-db} -u ${DB_USER:-whatsapp_user} -p${DB_PASS} -e "SELECT 1" >/dev/null 2>&1; do
|
||||
echo " MySQL no disponible, esperando..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✅ MySQL conectado"
|
||||
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
|
||||
|
||||
# Establecer permisos
|
||||
chown -R www:www /var/www/html/logs
|
||||
chown -R www:www /var/www/html/uploads
|
||||
chmod -R 755 /var/www/html/logs
|
||||
chmod -R 755 /var/www/html/uploads
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
echo "⏰ Configurando cron jobs..."
|
||||
cat > /etc/crontabs/www <<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');" 2>&1 | logger -t delayed-processor
|
||||
|
||||
# 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';" 2>&1 | logger -t log-cleanup
|
||||
|
||||
# Health check de workers (cada 5 minutos)
|
||||
*/5 * * * * supervisorctl status whatsapp-worker:* | grep -q RUNNING || supervisorctl restart whatsapp-worker:* 2>&1 | logger -t worker-monitor
|
||||
EOF
|
||||
chown www:www /etc/crontabs/www
|
||||
|
||||
echo "✅ Configuración completada"
|
||||
echo "🎯 Iniciando servicios..."
|
||||
|
||||
# Ejecutar comando pasado al contenedor
|
||||
exec "$@"
|
||||
@@ -0,0 +1,120 @@
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
root /var/www/html;
|
||||
index index.php index.html;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade" always;
|
||||
|
||||
# Logs
|
||||
access_log /var/log/nginx/whatsapp-access.log;
|
||||
error_log /var/log/nginx/whatsapp-error.log warn;
|
||||
|
||||
# Aumentar timeouts para webhook (procesamiento puede tardar)
|
||||
fastcgi_read_timeout 300;
|
||||
fastcgi_send_timeout 300;
|
||||
proxy_read_timeout 300;
|
||||
proxy_send_timeout 300;
|
||||
|
||||
# Root location
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# PHP files
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
|
||||
# FastCGI buffers
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
|
||||
# Importante para que webhook responda rápido
|
||||
fastcgi_buffering off;
|
||||
}
|
||||
|
||||
# Webhook endpoint (configuración especial para respuesta rápida)
|
||||
location ~ ^/api/webhook(_optimized)?\.php$ {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_index webhook_optimized.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
|
||||
# Sin buffering para respuesta inmediata
|
||||
fastcgi_buffering off;
|
||||
fastcgi_request_buffering off;
|
||||
|
||||
# Timeouts ajustados
|
||||
fastcgi_read_timeout 60;
|
||||
fastcgi_send_timeout 60;
|
||||
|
||||
# No cache
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
expires off;
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
location /health.php {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root/health.php;
|
||||
include fastcgi_params;
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Static assets caching
|
||||
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 30d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
# Deny access to hidden files
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Deny access to sensitive files
|
||||
location ~ /(?:composer\.json|composer\.lock|package\.json|\.env|\.git) {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
# Uploads directory
|
||||
location ^~ /uploads/ {
|
||||
alias /var/www/html/uploads/;
|
||||
autoindex off;
|
||||
|
||||
# Security: solo permitir ciertos tipos de archivo
|
||||
location ~* \.(jpg|jpeg|png|gif|pdf|doc|docx|xls|xlsx|mp4|mp3|webp)$ {
|
||||
expires 7d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
# Denegar ejecución de PHP en uploads
|
||||
location ~ \.php$ {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
# API directory (sin directorio listing)
|
||||
location ^~ /api/ {
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass 127.0.0.1:9000;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
user www;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 2048;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
# Logging
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for" '
|
||||
'rt=$request_time uct="$upstream_connect_time" '
|
||||
'uht="$upstream_header_time" urt="$upstream_response_time"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
# Performance
|
||||
sendfile on;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
client_max_body_size 100M;
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1000;
|
||||
gzip_proxied any;
|
||||
gzip_comp_level 6;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/json application/javascript application/xml+rss
|
||||
application/rss+xml font/truetype font/opentype
|
||||
application/vnd.ms-fontobject image/svg+xml;
|
||||
|
||||
# Buffer sizes
|
||||
client_body_buffer_size 128k;
|
||||
client_header_buffer_size 1k;
|
||||
large_client_header_buffers 4 16k;
|
||||
|
||||
# Timeouts
|
||||
client_body_timeout 12;
|
||||
client_header_timeout 12;
|
||||
send_timeout 10;
|
||||
|
||||
# FastCGI cache (opcional)
|
||||
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=whatsapp_cache:10m
|
||||
max_size=100m inactive=60m use_temp_path=off;
|
||||
|
||||
# Include virtual hosts
|
||||
include /etc/nginx/http.d/*.conf;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
[www]
|
||||
user = www
|
||||
group = www
|
||||
listen = 9000
|
||||
listen.owner = www
|
||||
listen.group = www
|
||||
|
||||
pm = dynamic
|
||||
pm.max_children = 50
|
||||
pm.start_servers = 10
|
||||
pm.min_spare_servers = 5
|
||||
pm.max_spare_servers = 20
|
||||
pm.max_requests = 500
|
||||
pm.status_path = /fpm-status
|
||||
|
||||
; Logs
|
||||
access.log = /var/log/php-fpm-access.log
|
||||
catch_workers_output = yes
|
||||
php_admin_flag[log_errors] = on
|
||||
php_admin_value[error_log] = /var/log/php-fpm-error.log
|
||||
|
||||
; Security
|
||||
; Nota: curl_exec y curl_multi_exec son necesarios para WhatsApp API
|
||||
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen,parse_ini_file,show_source
|
||||
|
||||
; Performance
|
||||
request_terminate_timeout = 300s
|
||||
request_slowlog_timeout = 10s
|
||||
slowlog = /var/log/php-fpm-slow.log
|
||||
|
||||
; Environment variables
|
||||
env[HOSTNAME] = $HOSTNAME
|
||||
env[PATH] = /usr/local/bin:/usr/bin:/bin
|
||||
env[TMP] = /tmp
|
||||
env[TMPDIR] = /tmp
|
||||
env[TEMP] = /tmp
|
||||
@@ -0,0 +1,50 @@
|
||||
[PHP]
|
||||
; Performance
|
||||
memory_limit = 256M
|
||||
max_execution_time = 300
|
||||
max_input_time = 300
|
||||
post_max_size = 100M
|
||||
upload_max_filesize = 100M
|
||||
|
||||
; Error reporting
|
||||
display_errors = Off
|
||||
display_startup_errors = Off
|
||||
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
|
||||
log_errors = On
|
||||
error_log = /var/log/php-error.log
|
||||
|
||||
; Date
|
||||
date.timezone = America/Bogota
|
||||
|
||||
; Security
|
||||
expose_php = Off
|
||||
allow_url_fopen = On
|
||||
allow_url_include = Off
|
||||
|
||||
; Session
|
||||
session.save_handler = redis
|
||||
session.save_path = "tcp://redis:6379"
|
||||
session.gc_maxlifetime = 3600
|
||||
session.cookie_httponly = 1
|
||||
session.use_strict_mode = 1
|
||||
|
||||
; OPcache (importante para performance)
|
||||
opcache.enable = 1
|
||||
opcache.enable_cli = 0
|
||||
opcache.memory_consumption = 128
|
||||
opcache.interned_strings_buffer = 8
|
||||
opcache.max_accelerated_files = 10000
|
||||
opcache.max_wasted_percentage = 5
|
||||
opcache.validate_timestamps = 0
|
||||
opcache.revalidate_freq = 0
|
||||
opcache.fast_shutdown = 1
|
||||
|
||||
; Realpath cache (mejora performance de includes)
|
||||
realpath_cache_size = 4096K
|
||||
realpath_cache_ttl = 600
|
||||
|
||||
; Output buffering
|
||||
output_buffering = 4096
|
||||
|
||||
; Redis
|
||||
extension = redis.so
|
||||
@@ -0,0 +1,46 @@
|
||||
[program:nginx]
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startretries=3
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
priority=10
|
||||
|
||||
[program:php-fpm]
|
||||
command=/usr/local/sbin/php-fpm -F -R
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startretries=3
|
||||
stdout_logfile=/var/log/supervisor/php-fpm.log
|
||||
stderr_logfile=/var/log/supervisor/php-fpm-error.log
|
||||
priority=10
|
||||
|
||||
[program:whatsapp-worker]
|
||||
command=/usr/local/bin/php /var/www/html/worker.php --daemon
|
||||
process_name=%(program_name)s_%(process_num)02d
|
||||
numprocs=3
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startretries=10
|
||||
startsecs=5
|
||||
user=www
|
||||
directory=/var/www/html
|
||||
stdout_logfile=/var/log/supervisor/worker-%(process_num)02d.log
|
||||
stderr_logfile=/var/log/supervisor/worker-%(process_num)02d-error.log
|
||||
stdout_logfile_maxbytes=10MB
|
||||
stderr_logfile_maxbytes=10MB
|
||||
stdout_logfile_backups=5
|
||||
stopwaitsecs=30
|
||||
stopsignal=TERM
|
||||
priority=20
|
||||
|
||||
[program:cron]
|
||||
command=/usr/sbin/crond -f -l 2
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/var/log/supervisor/cron.log
|
||||
stderr_logfile=/var/log/supervisor/cron-error.log
|
||||
priority=30
|
||||
@@ -0,0 +1,20 @@
|
||||
[unix_http_server]
|
||||
file=/run/supervisor.sock
|
||||
chmod=0700
|
||||
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
logfile=/var/log/supervisor/supervisord.log
|
||||
pidfile=/var/run/supervisord.pid
|
||||
childlogdir=/var/log/supervisor
|
||||
loglevel=info
|
||||
user=root
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///run/supervisor.sock
|
||||
|
||||
[include]
|
||||
files = /etc/supervisor/conf.d/*.conf
|
||||
Reference in New Issue
Block a user