Category Archives: httpd - Page 4

Redirigir requests de un server a otro en Apache con mod_proxy

Dando vueltas por internet me encontré este pequeño artículo donde explican una forma sencilla de usar mod_proxy para redireccionar peticiones de un servidor Apache a otro.

Apache Web Server

Apache Web Server

En realidad no llego a entender por qué el autor no utilizó una redirección a nivel DNS, pero supongo que habría razones para ello. De todas formas, es interesante reproducir su sencilla guía.

Por supuesto que esto implica tener el mod_proxy de Apache habilitado.

Luego en el servidor A (el que habría de proxy) es cuestión de introducir estas líneas en el httpd.conf:

ProxyPass / http://192.240.2.93/
ProxyPassReverse / http://192.240.2.93/
ProxyPreserveHost On

La primera línea redirige la petición del servidor A al B. La segunda indica que va a ser un proxy reverso, modificando las cabeceras HTTP Location, Content-Location y URI en la respuesta, para que ésta vuelva al cliente a través del servidor A. Por último, la tercera línea preservará la cabecera Host para hacer redirecciones basadas en el dominio. Esto es porque el caso que explica el artículo original, lo que se quería hacer es que las peticiones enviadas al dominio foo.com (que entendemos que resuelve la IP del servidor A) sean procesadas por el servidor B.

Y en el servidor B (el que va a procesar efectivamente los requests) configurar el virtual host correspondiente:

<virtualhost *:80>
ServerName foo.com
DocumentRoot /var/www/foo

<directory "/var/www/foo">
Order allow,deny
Allow from all
</directory>

ErrorLog /var/log/apache2/foo.err
CustomLog /var/log/apache2/foo.log combined
</virtualhost>

Instalar Lighttpd + Apache 2.2 en Linux

Anoche me puse a jugar un rato con un VPS porque tenía ganas de instalar lighttpd (AKA lighty) junto con Apache, de manera de montar un escenario similar al que proponía Cesar hace un tiempo en el blog del Web & Beer. Según lo que comenta ese artículo, Lighty es una opción muy interesante para montar proxies que distribuyan automáticamente la carga entre distintos webservers para servir contenidos de distinto tipo (básicamente distinguiendo entre estático y dinámico).

Lighttpd

Lighttpd

Por lo tanto, me puse a jugar un poco en este VPS para montar en él un lighty y un Apache, el primero escuchando en el puerto 80 y el segundo en el 8080. El primero va a ser el que reciba los requests y sirva el contenido estático y el segundo el que procese los requests de contenido dinámico (php). Como dije, esto fue más que nada un juego, porque el proyecto para el que lo voy a implementar no lo amerita y de hecho quizás poner un proxy en un servidor solo (no como balanceador de distintos nodos, sino balancenado la carga internamente) probablemente no se justifique. Pero valió la pena para meterme un poco en el tema de lighty y armar una pequeña guía de instalación.

En este caso, por culpa del VPS, tuve que trabajar con CentOS (hubiera preferido Slackware, pero es lo que había). Sin embargo, procuré hacer la instalación compilando todo yo mismo, porque me resulta más entretenido y creo que da mejores resultados.

Instalación de Lighttpd

La instalación de lighttpd es bastante sencilla e intuitiva para cualquiera que haya compilado e instalado Apache o cualquier otro servidor en Linux.

En primer lugar, lógicamente, hay que descargar el software de la web oficial: http://www.lighttpd.net/download. A mi me gusta hacer esto en el directorio /usr/src.

# cd /usr/src
# wget http://www.lighttpd.net/download/lighttpd-1.4.20.tar.gz
# tar zxvf lighttpd-1.4.20.tar.gz
# cd lighttpd-1.4.20

Luego, suponiendo que tenemos instaladas las librerías que podamos llegar a necesitar (glib2, openssl, libpcre), pasamos a configurar y compilar. Si no tenemos las librerías podemos ir descargandolas de sus sitios oficiales y compilándolas, o instalarlas con yum.

Yo utilicé el siguiente configure para mi Lighty:

./configure \
    --prefix=/usr \
    --exec-prefix=/usr \
    --bindir=/usr/bin \
    --sbindir=/usr/sbin \
    --sysconfdir=/etc/lighttpd\
    --datadir=/usr/share \
    --includedir=/usr/include \
    --libdir=/usr/lib \
    --libexecdir=/usr/libexec \
    --localstatedir=/var \
    --sharedstatedir=/usr/com \
    --mandir=/usr/share/man \
    --infodir=/usr/share/info \
    --with-openssl

Luego compilamos e instalamos:

# make && make install

Ahora debemos crear el usuario con el que va a correr nuestro Lighty.

# adduser -m -d /var/www -s /sbin/nologin lighttpd

Creamos algunos directorios adicionales para ubicar los distintos archivos de logs y configuración.

# mkdir -p /etc/lighttpd
# mkdir -p /var/log/lighttpd
# chown -R lighttpd:lighttpd /var/log/lighttpd

Ahora vamos a crear nuestro archivo de configuración. Yo utilice uno de la guía en la que me basé para hacer esta otra guía y lo modifiqué según lo que yo necesitaba, para incorporar la configuración del proxy. También se pueden ver ejemplos en la página oficial del Lighttpd. Notese que lighttpd no instala un archivo de configuración por default, como sí lo hace Apache, porque casi sin configuración puede funcionar. De hecho en la página de Lighttpd se observa una configuración muy básica para un servidor de contenido estático en 8 líneas.

# cd /etc/lighttpd
# wget http://www.tail-f.com.ar/files/lighttpd.conf.txt
# mv lighttpd.conf.txt lighttpd.conf
# chown lighttpd:lighttpd lighttpd.conf
# vi lighttpd.conf

Teniendo la configuración de Lighty tal como la queremos, pasamos a copiar el script a nuestra carpeta /etc/init.d. Esta sería la parte del a guía más dependiente de la plataforma. Aquí también partí de un script que encontré en la misma guía y le saqué algunas cosas de unos módulos que yo no iba a utilizar.

Pueden descargar mi versión de aquí, pero lo que tenemos que destacar, son las siguientes líneas.

## Proxy
proxy.server = (".php" => ((
                                "host" => "127.0.0.1",
                                "port" => 8080
                          )),
                ".css" => ((
                                "host" => "127.0.0.1",
                                "port" => 80
                          )),
                ".jpg" => ((
                                "host" => "127.0.0.1",
                                "port" => 80
                          )),
                ".gif" => ((
                                "host" => "127.0.0.1",
                                "port" => 80
                          )),
                ".png" => ((
                                "host" => "127.0.0.1",
                                "port" => 80
                          )),
                ".flv" => ((
                                "host" => "127.0.0.1",
                                "port" => 80
                          )),
                ".js" => ((
                                "host" => "127.0.0.1",
                                "port" => 80
                          )),
                ".swf" => ((
                                "host" => "127.0.0.1",
                                "port" => 80

# --- stripped ---- #
## bind to port (default: 80)
server.port                = 80

En esas líneas vemos que se define un proxy, que de acuerdo a las extensiones de los archivos va a mandar los requests a una destinación u otra. En este caso, que solamente tenemos una máquina, los archivos .php se envían al puerto 8080, donde tendremos el Apache, y los demás al puerto 80 que es donde escuchará Lighty. Luego, al final vemos, justamente, la configuración para que Lighty bindee con el puerto 80.

# cd /etc/init.d
# wget http://www.tail-f.com.ar/files/lighttpd.init.txt
# mv lighttpd.init.txt lighttpd
# chmod +x lighttpd
# chkconfig --add lighttpd
# chkconfig lighttpd on

Y por último, estamos listos para iniciar nuestro nuevo servicio.

# service lighttpd start

Fuente: NixCraft.

Instalación de Apache

Apache Web Server

Apache Web Server

Vamos a ir, por último, a la instalación de Apache 2.2. Esto es bastante más estándar y, como el post está dedicado más que nada a Lighty, solamente voy a dejar mi configure y los pasos de instalación sin demasiada explicación.

Descargamos el Apache del sitio oficial y lo configuramos.

# cd /usr/src
# wget http://apache.dattatec.com/httpd/httpd-2.2.10.tar.bz2
# tar jxvf httpd-2.2.10.tar.bz2
# cd httpd-2.2.10

Esta es la configuración que elegí yo, basado en gran parte en la que viene por default con Directadmin.

# ./configure \
        --prefix=/usr \
        --exec-prefix=/usr \
        --bindir=/usr/bin \
        --sbindir=/usr/sbin \
        --sysconfdir=/etc/httpd/conf \
        --datadir=/usr/share \
        --includedir=/usr/include \
        --libdir=/usr/lib \
        --libexecdir=/usr/libexec \
        --localstatedir=/var \
        --sharedstatedir=/usr/com \
        --mandir=/usr/share/man \
        --infodir=/usr/share/info \
        --enable-so \
        --enable-dav \
        --enable-dav-fs \
        --enable-dav-lock \
        --enable-suexec \
        --enable-deflate \
        --enable-unique-id \
        --with-suexec-caller=apache \
        --with-suexec-docroot=/ \
        --with-suexec-gidmin=100 \
        --with-suexec-logfile=/var/log/httpd/suexec_log \
        --with-suexec-uidmin=100 \
        --with-suexec-userdir=public_html \
        --with-suexec-bin=/usr/sbin/suexec \
        --with-included-apr \
        --with-pcre=/usr/local \
        --includedir=/usr/include/apache \
        --libexecdir=/usr/lib/apache \
        --datadir=/var/www \
        --localstatedir=/var \
        --enable-logio \
        --enable-ssl \
        --enable-rewrite \
        --with-ssl=/usr \
        --enable-headers \
        --enable-expires

Luego compilamos e instalamos.

# make && make install

En este punto yo decidí crear un usuario httpd para el Apache, y luego ponerle a la carpeta /var/www como dueño al usuario lighttpd y como grupo httpd.

# adduser -m -d /var/www -s /sbin/nologin httpd
# chown -R lighttpd:httpd /var/www
# chmod -R 770 /var/www

Luego hay que editar la configuración de Apache, fundamentalmente para decirle que escuche en el puerto 8080. A continuación algunos elementos importantes de la configuración.

Listen 8080
User httpd
Group httpd
ServerName localhost:8080
ErrorLog "/var/log/httpd/error.log"
CustomLog "/var/log/httpd/access.log" common

Por último, hay que instalar el script en el /etc/init.d (yo obtuve el mío de otro servidor, pero en Google debe haber varias versiones, porque es algo muy común). Luego hay que darle los permisos de ejecusión, ejecutar el chkconfig como con Lighty, e iniciar el servicio.

# service httpd start

Luego sobre el mismo servidor instalé PHP y MySQL, pero no me quiero extender sobre la configuración de esos servicios para no desvirtuar este post. En todo caso, en un futuro, publicaré mi configuración habitual de PHP para quienes estén interesados.

Instalar extensiones de FrontPage en Directadmin

Me da cierta vergüenza tener que publicar este artículo por las tecnologías de las que voy a hablar: FrontPage y Apache 1.3. Pero entenderán que son cosas que aún se usan y cada tanto nos vemos obligados a lidiar con ellas.

Las extensiones de FrontPage son básicamente una serie de scripts que corren del lado del servidor y que, como su nombre lo indica, extienden la funcionalidad del FrontPage. A pesar de ser un producto de Microsoft, es compatible con Apache.

El tema es que, al menos en Directadmin, solamente es compatible con Apache 1.3. Según entiendo, las extensiones en sí se pueden instalar con Apache 2.x, pero el Directadmin solamente las soporta cuando se usa la versión 1.3.

Ahora bien, esta instalación no vamos a poder realizarla con Custombuild, sino que tenemos que recurrir al más antiguo CustomApache. Entonces los pasos serían los siguientes:

Descargar e instalar CustomApache:

cd /usr/local/directadmin
mkdir customapache
cd customapache
wget http://files.directadmin.com/services/customapache/build
chmod 755 build
./build update

Lo más sencillo ahora sería ejecutar build all, que va a instalar el Apache y las extensiones:

./build all

Si por alguna razón no se quiere compilar e instalar todo, se puede compilar Apache con:

./build apache_mod_ssl

Y luego habría que instalar las extensiones:

./build mod_frontpage

Por último, y esto es muy importante, hace falta habilitar las extensiones para que Directadmin muestre el correspondiente menú. Para ello es necesario editar el archivo /usr/local/directadmin/conf/directadmin.conf y poner el parámetro frontpage_on en 1.

frontpage_on=1

Luego se reinicia el servicio del Directadmin y listo:

service directadmin restart

Reduciendo el tráfico usando cache en Apache

Todos sabemos que en servidores de alta concurrencia el tema del tráfico es crítico. Reducir la cantidad de requests (pedidos) HTTP que hacen los clientes de un sitio muy visitado resulta clave para optimizar el rendimiento de nuestro servidor. Cada pedido implica una cantidad de ancho de banda que se consume (el pedido que va y la respuesta que vuelve) y procesamiento del lado del servidor y del cliente. Si logramos reducir la cantidad de los requests vamos a estar aliviando tanto el ancho de banda como la carga del servidor, con lo cual, vamos a poder atender a mayor cantidad de clientes con los mismos recursos.

Apache Web Server

Apache Web Server

Hay muchos aspectos en el diseño de la arquitectura de una aplicación que deben ser tenidos en cuenta para reducir la cantidad de requests. No podemos cubrir todos aquí, pero uno fundamental es el cache. El cache es, por lo general, una reproducción estática de un conjunto de información dinámica. Es decir, un almacenamiento temporal de una información que puede cambiar, durante un período de tiempo en el que se supone que no ha de hacerlo.

Por ejemplo, si yo tengo un conjunto grande de datos sobre los ingresos de los miembros de una familia y debo mostrar informes realizados sobre esos datos, tendría que hacer toda una serie de cálculos que mes a mes irían dando resultados distintos. Si yo sé que a lo largo de un mes, los datos de orígen no van a cambiar, puedo hacer un cache (una copia de los resultados ya calculados) para mostrarlos durante todo ese mes y no volver a hacer los cálculos.

Hay varios tipos de cache, que se pueden implementar en distintos segmentos de la arquitectura de una aplicación. En este caso nos ocuparemos del cache que se hace en el cliente HTTP (el browser) para evitar hacer consultas innecesarias al servidor (el Apache), con los beneficios que mencionamos más arriba.

Cuando cualquiera de nosotros visita un sitio web con un browser común, éste último se ocupa de hacer un request HTTP al servidor pidiendo el contenido de la URL que solicitamos (por ejemplo, el contenido del archivo http://www.tail-f.com.ar/index.php). Ahora bien, cuando recibe el contenido del archivo, si es HTML, es muy probable que éste incluya referencias a toda otra serie de archivos (imágenes, archivos de CSS, archivos de JavaScript, etc.). Automáticamente, y en forma totalmente transparente para nosotros, el browser va a hacer los requests de esos archivos, para bajar las imágenes y archivos que necesite para mostrarnos la página web a la que nosotros queremos acceder. Pero ¿qué sucede?, muchos de estos archivos, especialmente las imágenes, lo más probable es que no cambien casi nunca. El logo de la empresa dueña del sitio seguirá siendo el mismo y si yo actualizo la página o voy de la home a la sección de contacto, el logo que aparece en el encabezado se estaría descargando muchas veces. La gente que definió el protocolo HTTP ya tenía en mente este tipo de situaciones, entonces definió una serie de directivas que se envían en los headers de los mensajes HTTP, a través de las cuales el servidor le puede indicar al cliente si debe guardar ese archivo y por cuánto tiempo. De esta manera, al visitar la home del sitio por primera vez, el servidor puede decirme “este logo va a permanecer igual por todo un mes, así que guardalo y no me lo vuelvas a pedir hasta entonces”, y si yo soy obediente, lo haré, y nos haré un favor a los dos. Porque la próxima vez que vea que un HTML de este sitio me indica que tengo que poner la imagen logo.jpg en algún lado, la buscaré en mi disco rígido en vez de pedírsela al servidor, pudiendo mostrarla mucho más rápido al visitante.

¿Cómo se configura esto en Apache?

Hay dos módulos de Apache que nos servirán en este punto:

El primero permite manipular los headers (cabeceras) de los requests y responses que envía Apache. El segundo sirve para control uno de esos headers en particular, que es justamente el llamado “Expires”, que define el tiempo de expiración del archivo que se está mandando en un response.

Por lo tanto, aplicando unas reglas con expresiones regulares y estos dos módulos, en el httpd.conf de Apache o en un .htaccess, podemos definir cómo será el tratamiento de distintos tipos de archivos.

Por una cuestión de simplicidad yo lo he probado con un .htaccess, pero usarlo en el httpd.conf resultaría más óptimo aún, porque el procesamiento del .htaccess de por sí le quita rendimiento a Apache.

A continuación, dejo un ejemplo de configuración de un .htaccess en el cual se define que los archivos multimedia (sonido y video) deberán ser cacheados por un año, las imágenes por una semana, los archivos estáticos más comunes (html, css, js) cada 2 horas y los archivos dinámicos (php, cgi, pl) no deberán tener cache.

# Turn on Expires and set default to 0
ExpiresActive On
ExpiresDefault A0

# Set up caching on media files for 1 year (forever?)
<FilesMatch "\.(flv|ico|pdf|avi|mov|ppt|doc|mp3|wmv|wav)$">
ExpiresDefault A29030400
Header append Cache-Control "public"
</FilesMatch>

# Set up caching on media files for 1 week
<FilesMatch "\.(gif|jpg|jpeg|png|swf)$">
ExpiresDefault A604800
Header append Cache-Control "public"
</FilesMatch>

# Set up 2 Hour caching on commonly updated files
<FilesMatch "\.(xml|txt|html|js|css)$">
ExpiresDefault A7200
Header append Cache-Control "proxy-revalidate"
</FilesMatch>

# Force no caching for dynamic files
<FilesMatch "\.(php|cgi|pl|htm)$">
ExpiresActive Off
Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform"
Header set Pragma "no-cache"
</FilesMatch>

Fuente del código: AskApache.com