Error 502 Bad Gateway en Nginx. Posibles soluciones

Me han preguntado varios lectores sobre el mismo problema: se encuentran con un error 502, Bad Gateway o puerta de enlace, devuelto por un servidor Nginx. ¿Dónde se produce este error? Pues en el punto en que el servidor Nginx se comunica con otra aplicación o servicio ¿Y por qué se da? Por muchos motivos: que uno de los dos esté caído, que no se «aclaren» con el protocolo (mala configuración), etc. Puede darse cuando Nginx funciona como proxy de Apache, con problemas derivados de la configuración del buffering o del tiempo de espera de respuesta, cuando Nginx funciona como puerta de enlace con otra aplicación o cuando Nginx funciona con el daemon PHP-FPM.

Lo primero, tanto en el caso del daemon de PHP-FPM, como en el de usarlo como proxy de Apache o como puerta de enlace para otro servicio es reiniciar dichos servicios. En la mayoría de los casos el error surge porque el servicio se ha detenido por algún motivo, y con el reinicio se soluciona. En caso de que ocurra reiteradamente entonces investigad por qué ese servicio «casca» de forma tan habitual. Seguramente en los logs del servidor esté mucha de la información que necesitaréis para encontrar la solución.

Aunque la caída del servicio es lo más habitual no es la única opción. En otro artículo ya hablamos de configurar los valores del tiempo para timeout de FastCGI en IIS, en Nngix podemos hacer esto editando el archivo nginx.conf, dentro del bloque http (esto es un ejemplo copiado de la documentación oficial de Nginx, cada caso deberá adaptarse a sus necesidades):

http {
...
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
...
}

En caso de que estéis usando Nginx como proxy deberéis añadir unas líneas como estas en el archivo nginx.conf:

proxy_connect_timeout       600;
proxy_send_timeout          600;
proxy_read_timeout          600;
send_timeout                600;

Para el caso de PHP-FPM debes asegurarte, revisando el fichero http://www.conf de configración de Nginx, de que está bien configurado el puerto en que el servicio debe estar «a la escucha». Generalmente es una de estas dos opciones:

listen = /var/run/php5-fpm.sock
#o si no
listen = 127.0.0.1:9000

Si no está configurado así probad una de esas dos opciones y reiniciad el servicio.

Otra causa de este problema venía derivado del uso de APC Cache, y se solucionaba dejando de usarlo y pasándose a Xcache. De esto hará cosa de un año, puede que a día de hoy ya no genere problemas, pero a saber.

Y a más de uno le ha comenzado el problema tras actualizar algunos paquetes de PHP en su servidor. El problema viene porque en esa actualización los permisos de lectura-escritura-ejecución del socket han sido modificados, y el servidor no puede acceder a ellos porque no está en el mismo grupo. Para solucionar esto tienes que tocar varios archivos. El primero nginx.conf, donde comprobaremos que esto esté tal cual:

user nginx;

Luego nos vamos a /etc/php-fpm.d/www.conf y lo configuramos así

listen = /tmp/php5-fpm.sock
listen.owner = nginx
listen.group = nginx

Y tras esto reiniciamos tanto el servicio de nginx como el de php-fpm.

Estos son los principales problemas y soluciones que he ido encontrando por la red, espero que os sirvan de ayuda.

Scripts para parar, arrancar y reiniciar Apache y MySQL en Ubuntu

Muchos desarrolladores tenemos en nuestro equipo un entorno LAMPP para testear nuestros trabajos web. Como generalmente uso el ordeador para trabajar tengo configurado que arranquen con el equipo por defecto tanto MySQL como Apache, ya que rara vez estoy ON en mi equipo y no estoy trasteando con algo de código.

Pero a veces, para virtualizar o para trabajar con algún editor de vídeo me veo obligado a tener toda la memoria posible para que la cosa no se torne inusable
. Cierto que son sólo dos líneas en el terminal… pero con cada script las dejo en una sola:

Script para parar Apache 2 y MySQL:

#!/bin/bash/

sudo apache2ctl -k stop
sudo /etc/init.d/mysql stop

Script para arrancar Apache2 y MySQL

#!/bin/bash/

sudo apache2ctl -k start
sudo /etc/init.d/mysql start

Y finalmente, script para reiniciarlos

#!/bin/bash/

sudo apache2ctl -k restart
sudo /etc/init.d/mysql restart

Te dará una serie de warnings, pero ni caso, funciona (compruébalo intentando conectar con MySQL o intentando ver algunha página en local).

En fin, por hoy nada más.

Configurar servidor Apache para que nos muestre los errores de nuestro PHP

Un poco de sistemas y un poco de PHP mezclado en esta entrada, porque aunque sean tareas muy básicas no está demás comentarlas.

Lo primero es decir que esto NUNCA debe hacerse en un servidor de producción, JAMÁS. Es decir, esta configuración es una ayuda para el programador, por lo que lo recomendable es hacerlo en el servidor de desarrollo/local. Mostrar los errores en producción supondrá una debilidad en la seguridad de la página, así que recuerda: Sólo para desarrollo.

Apache Foundation

Una vez dicho esto, comentar también que si instaláis Apache en un servidor Linux, o si utilizáis XAMPP en Windows, por defecto vendrá con la detección de errores desconectada. En ese caso si tenéis un fallo se mostrará una página en blanco. Este es el comportamiento adecuado en producción, pero en vuestro equipo de desarrollo lo más cómodo es que os muestre el error y en qué línea se ha detectado.

Para cambiar la configuración tenéis que iros a buscar el archivo de configuración de PHP (php.ini), que en Ubuntu por defecto está en etc/php5/apache2/php.ini y en XAMPP podéis acceder a él desde el panel de control principal. Si no lo encontráis basta con que hagáis una página que imprima la función phpinfo() y ahí veréis la ruta completa al archivo (aparece como Loaded Configuration File).

Una vez abierto el archivo con un editor de texto os vais a buscar la instrucción display_errors, que estará por defecto en Off y la cambiáis por On. Vamos que quedará display_errors = On y, tras esto, guardáis los cambios en el archivo. Tras eso reiniciáis el servicio (en XAMPP desde el panel, en Ubuntu con sudo/etc/init.d/apache2 restart) y ya debería estar cantándoos los errores. En todo caso, ejecutad un script con algún fallo que sepáis dónde está (tipo dejaros fuera una coma en la primera fila o un paréntesis sin abrir) para ver que todo funciona correctamente.

Con esto habréis configurado ya vuestro servidor para que detecte los errores, lo que será una enorme ayuda a la hora de desarrollar páginas PHP.

Instalar el módulo para DNIe en un servidor Apache

Estos días estoy realizando el curso de INTECO de desarrollo de aplicaciones del DNIe (os recomiendo que si estáis en paro os paséis por la sección de formación de su web, hay múltiples cursos gratis, que quieras que no ayudan a engordar el CV y a ampliar conocimientos) y, como ejercicio práctico, me he puesto a instalar el módulo para autenticación con DNIe en un servidor Apache.

La idea es instalar el módulo mod_ssl para que apache trabaje con certificados digitales para la autenticación cliente/servidor.

La idea es descargar el módulo, guardarlo en la carpeta /libexec de Apache y ejecutar estos comandos:

cd usr/local/modssl
./configure\
-- with-apache=../apache\
-- with-ssl=../openssl\
-- enable-shared=ssl\

make
make install

Se recompila y reinstala Apache con la opción –enable-module=modssl y ya está. A partir de ahora, para arrancar Apache con ssl se ejecutará el comando

/usr/local/apache/bin/apachectl startssl

Tras esto toca configurar el Apache. Debéis buscar el fichero http.conf, donde estarán todas las directivas de MOD_SSL para su gestión.

La configuración de SSL estará entre una etiqueta ifDefine SSL, dentro de la cual debéis comprobar si está habilitado el protocolo SSL (SSLEngine on). Comprobad por allí que está definido el certificado de servidor y su clave privada (SSLCertificateFile /usr/local/apache/conf/ssl.crt/certificatSERV.crt para el certificado y SSLCertificateKeyFile /usr/local/apache/conf/ssl.key/clausSERV.key ). Luego hay que indicar el directorio donde se guarda la CA (autoridad de certificación) del DNIe, directiva que se utiliza para comprobar si se confía en el emisor del certificado cliente. Busca SSLCACertificateFile acraiz-dnie.cer y SSLCACertificatePath /usr/local/apache/conf/ssl.crt/, el primero es el nombre del certificado y el segundo la dirección donde debe estar guardado. Para cargar el resto de Autoridades de Certificación subordinadas en las cuales se confiará, el procedimiento es el siguiente:

  • Ubicar el certificado en el directorio antes indicado en formato PEM
  • Crear un nombre simbólico de la forma “hash.N” para cada certificado. Se puede hacer con el comando Makefile que proporciona el mismo mod_ssl

Para acabar comprueba que la autenticación del cliente está habilitada (SSLVerifyClient require) y la profundidad de verificación, que para el caso del DNIe se encuentra en las CA subordinadas y la CA Raiz (SSLVerifyDepth 2).

Con todo esto ya tienes el módulo instalado para usar una conexión segura SSL en tu Apache, usando el DNIe para la verificación.