Posts tagged with “apache”

Tunear Apache con cabeza

Voy a cambiar un poco de temática, ya que no solo de MySQL vive el mundo 2.0 😉 Apache, el servidor web estándar en el ecosistema LAMP es uno de los grandes olvidados a la hora de hacer un buen tuning de nuestra plataforma. A continuación voy a explicar una serie de pasos recomendados para lograr el máximo rendimiento de nuestra máquina y al mismo tiempo evitar que esta se caiga bajo un gran pico de visitas. Ni copiar configuraciones de internet ni dejar los valores por defecto son buenas ideas 😉

A la hora de instalar Apache debemos elegir entre dos versiones, aunque generalmente lo elegirá nuestro gestor de paquetes.

  • Apache Worker

Incluido desde Apache 2.0. Utiliza menos memoria y tiene un mejor rendimiento. Se lanzan múltiples procesos y cada uno de estos pueden correr múltiples threads.

  • Apache Prefork

Es el MPM por defecto en Apache 1.3 y Apache 2.0. Es el instalado por defecto si hacemos uso de mod_php, ya que algunos módulos de PHP no son "thread safe". Tiene un rendimiento ligeramente peor que Worker y más consumo de memoria, pero se considera más seguro y estable. En este MPM se lanzan múltiples procesos y se ejecuta un thread por proceso.

Lo lógico sería utilizar Worker, pero vamos a basarnos en el típico ejemplo LAMP que incluye el soporte mod_php, aunque esto no sea lo más óptimo. Por dicha razón vamos a ver como deberíamos ajustar la configuración para un Prefork.

El principal parámetro hardware de nuestros frontales Apache será la memoria RAM. Aquí está todo claro, a más memoria RAM, más procesos se podrán lanzar y más peticiones se podrán atender. Por lo tanto, en primer lugar debemos saber el número de procesos que nuestra máquina puede llegar a soportar. Para ello podemos hacer uso de esta fórmula:

MaxClients = (RAM - tamaño_del_resto_de_procesos)/(tamaño_de_procesos_apache)

Para conocer el tamaño de los procesos de Apache podemos ejecutar un ps:

ps -ylC httpd --sort:rss

Es recomendable que los procesos de Apache ya hayan atentido algunas peticiones, de forma que podamos observar no solo el valor mínimo de memoria de los procesos, si no el máximo que alcanzan una vez atendidas las peticiones.

Entonces, pongamos el siguiente ejemplo:

  • El mayor tamaño que alcanza un proceso de Apache son 98 megas
  • El resto de procesos ocupan 250 megas.
  • Tenemos 32 gigas de ram
MaxClients = (32768 - 250) / 98

Por lo tanto, el número máximo de procesos Apache que se pueden arrancar son 331. Hay que tener en cuenta que esto sería un límite teórico antes de empezar a swapear. Para no estar rozando el límite recomiendo poner algo menos, 310. Con esto definimos claramente cuantos procesos podrán lanzarse para atender a las peticiones y será en función de la RAM que tengamos. Si reducimos el tamaño de los procesos de Apache podremos también aumentar el número de procesos que se pueden lanzar. Para ello, lo mejor es desactivar todos los módulos que no se vayan a utilizar.

En caso de recibir más peticiones de las que pueda atender las encolará y evitaremos que comience a swapear tirando la máquina abajo. Esta cola está definida por el parámetro ListenBacklog que tiene como valor por defecto 511. Como bien dice el manual de Apache, no se recomienda cambiar este valor a no ser que estemos sufriendo un ataque de flood SYN.

Asociado a este parámetro también tenemos ServerLimit, que viene a indicar el valor máximo que podremos poner en MaxClients. ServerLimit tiene por defecto 256, por lo que si aumentamos MaxClient a 310 también tendremos que aumentar ServerLimit al mismo número. De lo contrario el cambio en MaxClients no servirá de nada y estaremos limitados.

Además, tenemos que configurar los siguientes valores:

  • StartServers

Indica el número de procesos que arranca al iniciar el servicio. Este valor no se debe poner demasiado elevado o ralentizará mucho la puesta en marcha del servicio. Como modificar este valor no da ninguna mejora de rendimiento, lo dejamos en el valor por defecto 5.

  • MinSpareServers

Son el número de procesos IDLE que deben existir como mínimo en el servidor. Según vayan recibiendo peticiones Apache lanzará nuevos procesos para mantener este número mínimo. De esta forma los nuevos usuarios que se conecten a la web no tendrán que esperar a que Apache lance un proceso para ellos, si no que siempre se garantizará un mínimo, mejorando la respuesta del servicio. Aún así no es recomendado poner un valor exageradamente grande. Con 30 es suficiente.

  • MaxSpareServers

Es el número máximo de procesos IDLE que existirán en el servidor. Si este número se supera, Apache empezará a cerrar procesos. Poner un valor que sea el doble de MinSpareServers suele dar buenos resultados, siempre y cuando MinSpareServers no tenga un valor absurdamente grande. 60 será suficiente.

  • MaxRequestsPerChild

Con el fin de evitar posibles posibles fugas de memoria en la programación, se suele establecer el número de peticiones máximas que atenderá un proceso antes de morir. Poner un valor pequeño reducirá el rendimiento, ya que Apache tendrá que estár continuamente matando y lanzando nuevos procesos. Un valor recomendado por defecto es 100000, el cual es correcto.

Por lo tanto, el tuning quedaría de la siguiente manera:


StartServer 5
MinSpareServer 30
MaxSpareServer 60
MaxClients 310
MaxRequestsPerChild 10000

Además es recomendable bajar los timeous para evitar tener procesos sin hacer nada.

Timeout 30

Timeout esperará 30 segundos antes de cerrar una petición. Esperará para tres cosas (copy/paste del manual):

1- La cantidad de tiempo que tarda en recibir una petición GET.

2- La cantidad de tiempo entre la recepción de paquetes TCP packets en una petición POST o PUT.

3- La cantidad de tiempo entre ACKs en transmisiones de paquetes TCP en las respuestas.

Por defecto el valor es 300, el cual bajo mi experiencia es realmente exágerado.

KeepAliveTimeout 5

Muchos clientes no ven con buenos ojos la bajada del KeepAliveTimeout, pero tiene una buena razón. En prefork, una petición se queda asociada a un proceso durante todo el KeepAlive, por lo que tener un valor muy alto terminará por agotar las conexiones en algunos picos de carga. En algunos casos incluso es posible aumentar el rendimiento deshabilitando por completo el KeepAlive, pero eso ya dependerá de la página y la programación de la misma. El valor por defecto es 15.

Con estos consejos tendrás una configuración mucho mejor que la de defecto y completamente ajustada a tu máquina. Si ves que el número máximo de clientes es muy poco y no puedes atender todas las peticiones, no lo aumentes a lo loco, mete más máquinas en el balanceador o aumenta la RAM. Lo más importante como ya he indicado es poner valores realistas. En sistemas con mucha carga evitar la swap es la diferencia entre poder acceder a la máquina por SSH o tener que ir al centro de datos a dar un botonazo.

Además es importante tunear los frontales teniendo en cuenta el backend. Si tu MySQL no puede gestionar por memoria más de 200 conexiones, es una estupidez poner en apache 310. Todo tiene que estar equilibrado.

Mejorando la seguridad de WHM/Cpanel con Suhosin

Suhosin es un sistema de protección para PHP que se encarga de, entre otras cosas, comprobar la seguridad de las funciones ejecutadas, localizar los fallos de seguridad típicos en la programación y evitar que puedan ser explotados. En la misma web indican que instalando Suhosin te puedes evitar tener que pensar en la programación segura, Suhosin se encargaría de todo. No se si será para tanto... 😉 En este post veremos una de sus utilidades, bloquear funciones peligrosas que no queremos que se puedan ejecutar en nuestro hosting compartido.

Al tratarse de una extensión de PHP tendremos que usar EasyApache para compilarlo para disponer de el en nuestros WHM. Daré por supuesto que esta parte ya está hecha. Una vez con el soporte habilitado y Apache reiniciado procedemos a bloquear funciones. Para ello debemos editar el php.ini y añadir una línea como la siguiente:

suhosin.executor.func.blacklist = "exec,shell_exec,system,passthru,proc_open,popen,proc_terminate,
show_source"

De esta forma, dichas funciones quedarán prohibidas y no se podrán llamar desde las páginas web que nuestros clientes suban.

Esto, en un mundo feliz e ideal, se dejaría configurado y no nos preocuparíamos más. Pero claro, en un mundo ideal el cliente no te crearía un centenar de incidencias y tus compañeros developers no te llamarían constantemente preguntando porque no pueden hacer un exec desde PHP.

Si por ejemplo tenemos un dominio el cual no queremos limitar, se tendrá que modificar el virtualhost siguiendo el método de WHM http://docs.cpanel.net/twiki/bin/view/EasyApache3/InsideVHost que se resume en:

Tenemos las carpetas:

/usr/local/apache/conf/userdata/std/2/

/usr/local/apache/conf/userdata/ssl/2/

/usr/local/apache/conf/userdata/std/1/

/usr/local/apache/conf/userdata/ssl/1/

2 indica que la versión de Apache que se está utilizando es 2, 1… pues Apache1.

ssl se aplicará al virtualhost con ssl, std sin ssl.

Imaginemos entonces que tenemos apache2, y el usuario se llama Google, la web que alojamos google.es y solo nos interesa http, sin ssl.

Entonces creamos la siguiente carpeta:

/usr/local/apache/conf/userdata/std/2/google/google.es/

Y dentro un fichero loquequieras.conf con el siguiente contenido:

php_admin_value suhosin.executor.func.blacklist "show_source"

Esta configuración añadirá dicha línea al VirtualHost de google. De forma que todos los demás tienen las restricciones arriba indicadas, mientras que google solamente show_source. Es necesario indicar al menos una función, no vale dejarlo vacio.

Una vez hecho, le decimos a whm que regenere el httpd.conf

/scripts/verify_vhost_includes
/usr/local/cpanel/bin/apache_conf_distiller --update
/scripts/rebuildhttpdconf

Trasparencias del curso "Apache Avanzado"

  • Instalación desde código fuente
  • Instalación desde binarios
  • Directivas de configuración
  • SSL
  • Certificados de cliente
  • VirtualHost
  • NameVirtualHost
  • Balanceo de carga
  • Optimización del servicio
  • Mod_Cache
  • Mod_Rewrite
  • Mod_Security
  • Mod_Proxy
  • Apache Benchmark

Múltiples VirtualHost en SSL en una única IP (SNI)

Resumiendo mucho el funcionamiento de los VirtualHost en Apache, se puede decir que el cliente (nuestro navegador) envía al servidor el nombre del dominio al que deseamos acceder y Apache lo busca en sus configuraciones para entregarte la web. De esta forma en un solo servidor podemos tener alojados múltiples páginas web, cada una con su VirtualHost.

GET /blog/ HTTP/1.1
Host: miguelangelnieto.net
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; es-ES; rv:1.9.0.6) Gecko/2009020911 Firefox/3.0.6
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: es,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

Pero la cosa cambia si las webs deben ser transmitidas mediante HTTPS, esto es, estableciendo una conexión SSL. Gracias a esta tecnología es posible que todo el tráfico entre el servidor y nuestro navegador vaya cifrado y esta es la raíz del problema. Al tener todos los datos cifrados, el servidor no puede saber que dominio está pidiendo el navegador, por lo que los VirtualHost en base a nombres (dominios) pierden utilidad. Para paliar este problema, se ponían múltiples IPs en el servidor y se asignaba cada IP a un VirtualHost. De esta forma, cada web HTTPS tenia como destino una IP distinta y así el servidor era capaz de darte la web que estabas buscando. Esto es, se pasaba de tener VirtualHost por nombre a tenerlos por IP. Si tenías dos páginas web esto no era problema, pero si tenías 200... acelerarías la implantación de IPV6 y eso no es bueno 😉

Para solucionar este problema se publicó en 2006 el RFC 4366. En resumen, TLS pasaba a tener extensiones a nivel cliente y servidor. Una de las cuales permite que el cliente en el establecimiento de la conexión (antes de comenzar el cifrado) pueda indicar el dominio al que desea acceder. La que nos hace la magia es SNI. Para que esto funcione es necesario cumplir una serie de requisitos:

  • OpenSSL 0.9.8f o posterior con extensiones TLS (enable-tlsext)
  • Apache compilado con dicho OpenSSL
  • Navegadores Mozilla Firefox 2.0, Opera 8.0 Internet Explorer 7.0, Google Chome, Safari 3.2.1

Para activar esta extensión añadimos la siguiente línea a httpd.conf:

SSLStrictSNIVHostCheck on

Una vez hecho configuraríamos nuestros VirtualHost SSL como si fuesen los de toda la vida (sin SSL).

Listen 443
NameVirtualHost *:443
<VirtualHost *:443>
        ServerName test1.irontec.com
        ServerAlias test1.irontec.com
        DocumentRoot /var/www/test1
        Options FollowSymLinks
        <Directory /var/www/test1>
        AllowOverride All
        </Directory>
        ErrorLog /var/log/apache2/test1error.log
        CustomLog /var/log/apache2/test1access.log combined env=!client-ip-request
        SSLEngine on
        SSLCertificateFile /etc/ssl/test.pem
        SSLCertificateKeyFile /etc/ssl/test.key
</VirtualHost>
<VirtualHost *:443>
        ServerName test2.irontec.com 
        ServerAlias test2.irontec.com 
        DocumentRoot /var/www/test2
        Options FollowSymLinks
        <Directory /var/www/test2>
        AllowOverride All
        </Directory>
        ErrorLog /var/log/apache2/test2error.log
        CustomLog /var/log/apache2/test2access.log combined env=!client-ip-request
        SSLEngine on
        SSLCertificateFile /etc/ssl/test.pem
        SSLCertificateKeyFile /etc/ssl/test.key
</VirtualHost>

Si vemos el siguiente error en los logs de Apache es que nuestro navegador no es compatible:

[error] No hostname was provided via SNI for a name based virtual host

Y listo, ya puedes tener múltiples VirtualHost con SSL en una única IP 😀