MySQL: Error "No space left on device" en /tmp Síntomas del problema Los usuarios reportan errores similares a estos en cPanel, phpMyAdmin y otras aplicaciones: Can't create/write to file '/tmp/#sql_911_0.MAI' (Errcode: 28 "No space left on device") Se experimentó un error mientras se obtenían los datos: Can't create/write to file '/tmp/#sql_1234_0.MAI' Diagnóstico paso a paso Verificar espacio en disco df -h Filesystem Size Used Avail Use% Mounted on /dev/sda1 20G 8.5G 10G 46% / tmpfs 2.0G 144K 2.0G 1% /tmp Salida para indicar que todo es normal Verificar inodos (la causa real) df -i Filesystem Inodes IUsed IFree IUse% Mounted on /dev/sda1 1310720 145230 1165490 11% / tmpfs 524288 524271 17 100% /tmp Observación : La salida indica el agotamiento al 100% de los inodos. Identificar los archivos problemáticos Al intentar listar /tmp con ls , obtendremos: ls /tmp -bash: /bin/ls: Argument list too long Por eso utilizamos find : find /tmp -maxdepth 1 -name 'sess*' | wc -l Resultado atípico: 288789 (cientos de miles de archivos) Causa raíz Acumulación masiva de archivos de sesión PHP ( sess_* ) que no se eliminan automáticamente, causando agotamiento de inodos en /tmp . Solución inmediata find /tmp -maxdepth 1 -type f -name 'sess*' -delete ¿Por qué usar find? Porque rm sess* falla con "Argument list too long" cuando hay miles de archivos. Prevención Configuración automática de limpieza Añadir al crontab de root: # Limpieza diaria de archivos temporales antiguos (>24h) 0 3 * * * find /tmp -type f -name "sess_*" -mtime +1 -delete >/dev/null 2>&1 Script para aplicar cambios PHP en todas las versiones de cPanel Contexto : En cPanel cada versión PHP tiene su propio archivo de configuración: /opt/cpanel/ea-php81/root/etc/php.ini /opt/cpanel/ea-php82/root/etc/php.ini /opt/cpanel/ea-php83/root/etc/php.ini Script automático para todas las versiones: #!/bin/bash # fix_php_gc_all_versions.sh # Script para corregir configuración de garbage collector en todas las versiones PHP de cPanel echo "=== Corrigiendo configuración PHP Garbage Collector ===" echo "Fecha: $(date)" echo # Buscar todas las versiones de PHP instaladas de forma eficiente PHP_VERSIONS=$(find /opt/cpanel -maxdepth 1 -name "ea-php*" -type d | grep -E "ea-php[0-9]+" | sort -V) if [ -z "$PHP_VERSIONS" ]; then echo "❌ No se encontraron versiones de PHP en cPanel (/opt/cpanel/ea-php*)" exit 1 fi echo "Versiones de PHP encontradas:" echo "$PHP_VERSIONS" | sed 's/.*ea-php/- PHP /' | sed 's/$//' echo for php_dir in $PHP_VERSIONS; do php_ini="$php_dir/root/etc/php.ini" version=$(basename "$php_dir" | sed 's/ea-php//') echo "--- Procesando PHP $version ---" if [ ! -f "$php_ini" ]; then echo "⚠️ No existe: $php_ini" continue fi # Crear backup cp "$php_ini" "$php_ini.backup.$(date +%Y%m%d_%H%M%S)" echo "✅ Backup creado" # Mostrar configuración actual current_prob=$(grep -E "^session\.gc_probability\s*=" "$php_ini" | cut -d'=' -f2 | tr -d ' ') current_div=$(grep -E "^session\.gc_divisor\s*=" "$php_ini" | cut -d'=' -f2 | tr -d ' ') echo " Configuración actual: gc_probability=$current_prob, gc_divisor=$current_div" # Aplicar cambios sed -i 's/^session\.gc_probability\s*=.*/session.gc_probability = 1/' "$php_ini" sed -i 's/^session\.gc_divisor\s*=.*/session.gc_divisor = 1000/' "$php_ini" # Verificar cambios new_prob=$(grep -E "^session\.gc_probability\s*=" "$php_ini" | cut -d'=' -f2 | tr -d ' ') new_div=$(grep -E "^session\.gc_divisor\s*=" "$php_ini" | cut -d'=' -f2 | tr -d ' ') echo " Nueva configuración: gc_probability=$new_prob, gc_divisor=$new_div" echo " ✅ PHP $version actualizado" echo done echo "=== Resumen ===" echo "✅ Cambios aplicados a todas las versiones PHP" echo "⚠️ Los cambios se aplicarán en nuevas sesiones PHP" echo # Comando de verificación echo "Verificar cambios:" echo "grep -E 'session\.gc_(probability|divisor)' /opt/cpanel/ea-php*/root/etc/php.ini" Version actualizada del script se mantiene en Git Lab Castris - Utilidades Uso del script: chmod +x fix_php_gc_all_versions.sh ./fix_php_gc_all_versions.sh Análisis de la configuración PHP problemática Configuración actual encontrada en servidores cPanel: session.gc_probability = 0 ; ⚠️ PROBLEMA: Numerador en 0 session.gc_divisor = 0 ; ⚠️ PROBLEMA: Denominador en 0 session.gc_maxlifetime = 1440 ; ✅ Correcto: 24 minutos (1440 segundos) Explicación del problema: El garbage collector de PHP funciona con esta fórmula: Probabilidad de limpieza = gc_probability / gc_divisor Con la configuración actual: 0 / 0 = indefinido → Garbage collector completamente desactivado Qué significa cada parámetro: gc_probability : Numerador de la probabilidad (cuántas veces de cada X) gc_divisor : Denominador de la probabilidad (el total X) gc_maxlifetime : Tiempo en segundos después del cual una sesión se considera "basura" Ejemplos de probabilidades: 1/100 = 1% → 1 de cada 100 peticiones ejecuta limpieza 1/1000 = 0.1% → 1 de cada 1000 peticiones ejecuta limpieza 0/0 = desactivado → Nunca se ejecuta limpieza automática Configuración PHP corregida Para servidores de producción (recomendado): session.gc_probability = 1 ; Cambiar de 0 a 1 session.gc_divisor = 1000 ; Cambiar de 0 a 1000 (0.1% probabilidad) session.gc_maxlifetime = 1440 ; Mantener actual Para servidores de desarrollo/bajo tráfico: session.gc_probability = 1 ; Cambiar de 0 a 1 session.gc_divisor = 100 ; Cambiar de 0 a 100 (1% probabilidad) session.gc_maxlifetime = 1440 ; Mantener actual Justificación de los valores: Producción (1/1000) : Menor impacto en rendimiento, suficiente con alto tráfico Desarrollo (1/100) : Mayor frecuencia de limpieza necesaria con poco tráfico Monitoreo de inodos Script para alertas: #!/bin/bash # # check_tmp_inodes.sh # Checks the inode usage on /tmp and sends an alert if it exceeds a threshold. # # Ensure the script stops if any command fails set -euo pipefail # --- CONFIGURATION --- # Path to the main configuration file # Check repo for crons/.check_tmp_inodes.cfg file demo # Not edit this file, copy the crons/.check_tmp_inodes.cfg file to /root/.check_tmp_inodes.cfg CONFIG_FILE="/root/.check_tmp_inodes.cfg" # --- FUNCTIONS --- # Function to log errors and exit # Usage: error_exit "Error message" error_exit() { echo "ERROR: $1" >&2 exit 1 } # --- MAIN SCRIPT --- # 1. Check if the configuration file exists and load it if [ ! -f "$CONFIG_FILE" ]; then error_exit "Configuration file not found at $CONFIG_FILE" fi # Load variables from the configuration file # shellcheck source=/dev/null source "$CONFIG_FILE" # 2. Verify that the necessary variables are defined if [ -z "${EMAIL_TO-}" ] || [ -z "${THRESHOLD-}" ]; then error_exit "EMAIL_TO and THRESHOLD variables must be defined in $CONFIG_FILE" fi # 3. Get the current inode usage # 'tail -n1' is used to be more robust on systems where 'df' might have more than 2 lines USAGE=$(df -i /tmp | tail -n1 | awk '{print $5}' | sed 's/%//') if ! [[ "$USAGE" =~ ^[0-9]+$ ]]; then error_exit "Could not retrieve a numeric value for inode usage. Got: '$USAGE'" fi # 4. Compare usage with the threshold and send an alert if necessary echo "INFO: Current inode usage on /tmp: ${USAGE}% (Alert threshold: >${THRESHOLD}%)" if [ "$USAGE" -gt "$THRESHOLD" ]; then # Build the message body HOSTNAME=$(hostname -f) BODY="ALERT on server: $HOSTNAME Inode usage in the /tmp directory has exceeded the ${THRESHOLD}% threshold. Current usage: ${USAGE}% It is recommended to check the contents of /tmp to free up inode space. " # Send the email echo "$BODY" | mail -s "$EMAIL_SUBJECT" "$EMAIL_TO" echo "ALERT: Threshold exceeded. Notification email sent to $EMAIL_TO." else echo "INFO: Inode usage is within normal limits." fi exit 0 Este script se mantiene en Gitlab Castris - Utilidades Configuración de directorios temporales seguros Problema con la configuración actual /home/user/tmp → enlace simbólico a /tmp (cPanel) Todos los usuarios comparten el mismo espacio de inodos Solución recomendada Configurar directorios temporales individuales: // En configuración PHP por usuario session.save_path = "/home/USERNAME/temporal" upload_tmp_dir = "/home/USERNAME/temporal" Monitoreo continuo Comando para verificar estado actual echo "Espacio: $(df -h /tmp | awk 'NR==2 {print $5}')" echo "Inodos: $(df -i /tmp | awk 'NR==2 {print $5}')" echo "Archivos sess: $(find /tmp -maxdepth 1 -name 'sess*' 2>/dev/null | wc -l)" Señales de alerta temprana Uso de inodos > 80% en /tmp Más de 10,000 archivos sess_* Quejas de usuarios sobre lentitud en aplicaciones web Severidad : Crítica - Afecta disponibilidad de MySQL y aplicaciones web Impacto : Todos los usuarios del servidor Tiempo de resolución : 2-5 minutos con la solución inmediata Aviso Esta documentación y su contenido, no implica que funcione en tu caso o determinados casos. También implica que tienes conocimientos sobre lo que trata, y que en cualquier caso tienes copias de seguridad. El contenido el contenido se entrega, tal y como está, sin que ello implique ningún obligación ni responsabilidad por parte de Castris Si necesitas soporte profesional puedes contratar con Castris soporte profesional .