SafeChildren Banner

Havoc Oracle Solaris Experts
Mostrando entradas con la etiqueta web. Mostrar todas las entradas
Mostrando entradas con la etiqueta web. Mostrar todas las entradas

viernes, 30 de abril de 2010

Instalación de squid como proxy reverso para Apache HTTP

Introducción
En esta serie de artículos, vamos a ver las diferentes formas que hay para definir una estructura de Apache Tomcat para su puesta en producción. Veremos cómo podemos configurar Apache Tomcat con Apache HTTP mediante <mod_jk> y cómo poner <squid-cache> como frontend haciendo de proxy reverso.

Como es una serie y no un unico post iremos viendo cómo montar la infraestructura, desde lo más básico, hasta -en las últimas entregas- cómo ponerlo en producción.

En esta tercera entrega, vamos a utilizar como base un post que escribí sobre Cómo poner Squid Cache como proxy reverso y haremos algunas modificaciones para adaptarlo a nuestras necesidades. Principalmente, modificaremos el inicio de squid-cache para gestionarlo mediante Solaris SMF e incluiremos acl para evitar el acceso al contenido.

Además, con esta entrega ya tenemos todo lo necesario para poner en producción nuestro tomcat de forma correcta.

Instalación de Squid-Cache como Proxy Reverso
Descargaremos la última versión stable de squid-cache en su branch 2.7 y la instalaremos
$ /usr/sfw/bin/wget http://www.squid-cache.org/Versions/v2/2.7/squid-2.7.STABLE9.tar.gz
$ /usr/sfw/bin/gtar zxpf squid-2.7.STABLE9.tar.gz
$ cd squid-2.7.STABLE9
$ export CFLAGS="-m64 -O3"
$ ./configure 
  --prefix=/opt/www/squid-2.7 \
  --with-large-files \
  --with-pthreads \
  --with-maxfd=16000 \
  --disable-internal-dns \
  --enable-large-cache-files \
  --enable-storeio=ufs,aufs \
  --enable-devpoll \
  --enable-x-accelerator-vary \
  --enable-cache-digests \
  --enable-http-violations \
  --enable-snmp
$ make
# make install

Comprobamos que todo está correcto
$ ldd /opt/www/squid-2.7/sbin/squid
        libpthread.so.1 =>       /lib/64/libpthread.so.1
        libmd.so.1 =>    /lib/64/libmd.so.1
        libm.so.2 =>     /lib/64/libm.so.2
        libsocket.so.1 =>        /lib/64/libsocket.so.1
        libnsl.so.1 =>   /lib/64/libnsl.so.1
        libresolv.so.2 =>        /lib/64/libresolv.so.2
        libthread.so.1 =>        /lib/64/libthread.so.1
        libc.so.1 =>     /lib/64/libc.so.1
        libmp.so.2 =>    /lib/64/libmp.so.2
        libscf.so.1 =>   /lib/64/libscf.so.1
        libuutil.so.1 =>         /lib/64/libuutil.so.1
        libgen.so.1 =>   /lib/64/libgen.so.1
        libsmbios.so.1 =>        /usr/lib/64/libsmbios.so.1
$ file /opt/www/squid-2.7/sbin/squid
squid:     ELF 64-bit LSB executable AMD64 Version 1 [SSE2 SSE FXSR CMOV FPU], dynamically linked, not stripped

Configuración Squid-Cache
A continuación vamos a configurar squid-cache para utilizar nuestro syslog y poder gestionarlo a través de Solaris SMF.

Para hacer que squid-cache escriba en el syslog deberemos utilizar las opciones <-s> o, si queremos utilizar una facility diferente <-l facility>, en nuestro caso vamos a utilizar <local6> como nuestra facility
# vi /etc/syslog.conf
   #
   # SQUID Cache
   #
   local6.debug                                    /var/log/squid.log
Nota: recordar que debe ser un "tabulador" el separador entre <local6.debug> y </var/log/squid.log>
# touch /var/log/squid.log
# chmod 600 /var/log/squid.log
# chown root:root /var/log/squid.log
# svcadm restart system-log
A continuación configuraremos nuestro squid-cache para poder gestionarlo mediante Solaris SMF, para ello, deberemos importar el manifest de Squid Cache 2 para Solaris SMF y el method para Squid Cache 2. He creado dos archivos manifest uno con sólo manifest para squid como proxy reverso y otro con manifest para squid como proxy reverso y http proxy para que podáis utilizarlo en varias instalaciones -pero sólo uno de los dos al mismo tiempo-, en nuestro caso utilizaremos el de proxy reverso, además, deberemos crear -si no lo hemos hecho antes- el directorio </var/svc/manifest/application/cache>
# mkdir -p /var/svc/manifest/application/cache
# cd /var/svc/manifest/application/cache
# /usr/sfw/bin/wget http://blog.sfchildren.com/blogger/put-tomcat-online/squid-conf/squid2_reverse.xml
# mv squid2_reverse.xml squid_2.xml
# svccfg
svc:> validate squid_2.xml
svc:> import squid_2.xml
svc:> quit
# svcs squid_2
STATE          STIME    FMRI
disabled       11:48:01 svc:/application/cache/squid_2:reverse_proxy
Ahora el method 
# cd /lib/svc/method
# /usr/sfw/bin/wget http://blog.sfchildren.com/blogger/put-tomcat-online/squid-conf/squid2
# chmod 555 squid2
# chown root:root squid2

Creación y Configuración de project
Una vez importada la configuración para Solaris SMF, necesitamos crear los project que hemos definido en nuestro archivo <squid_2.xml> en la propiedad <method_context project='squid.reverse'>, en nuestro caso squid.reverse
# projadd -c 'SQUID Reverse Proxy' squid.reverse
# projmod -sK 'process.max-file-descriptor=(priv,8192,deny)' squid.reverse
# projmod -sK 'task.max-lwps=(priv,250,deny)' squid.reverse
Configuración <$SQUID_HOME/etc/squid.conf>
Vamos a utilizar una configuración básica de squid y sobre ella realizaremos los cambios necesarios, puedes encontrar más información aquí sobre la instalación de squid cache en Solaris 10.

Para poder hacer que squid funcione como proxy reverso debemos realizar los siguientes cambios -vamos a continuar con el ejemplo de la serie y tenemos un VirtualHost (www.test.com) :
  • visible_hostname _hostname_, debe ser nuestro dns público, es decir, <www.test.com>
  • http_port _localip_:80 defaultsite=_default_virtual_host_ accel vhost, aquí indicaremos a squid que queremos que haga de proxy reverso donde <localip> será nuestra IP y &lt:default virtual host> será nuestro virtual host por defecto, en nuestro caso <test.com>
Ahora viene algo un poco más complicado, pero intentaré explicarlo de forma sencilla. Vamos a hacer que squid utilice como caché padre <cache_peer> a nuestro servidor Apache HTTP, y por lo tanto, definiremos qué VirtualHost irá a cada Apache HTTP. 

El formato de  <cache_peer> es:
cache_peer hostname type http_port icp_port options
Donde <hostname> será el dns/ip de nuestro servidor Apache HTTP,  <type> será siempre parent, <http_port> será el puerto donde escucha nuestro Apache HTTP, <icp_port> lo estableceremos a 0 para que no utilice peticiones icp y por último, las opciones. En las opciones deberemos declarar un nombre único <name> para cada cache_peer y la opción <login=PASS> para indicarle a squid que si tiene una petición de login la envíe al padre, no la trate el.
Por lo tanto, para nuestro ejemplo -teniendo en cuenta que <htt1.test.com> es nuestro servidor Apache HTTP- quedará de la siguiente forma:
cache_peer http1.test.com parent 80 0 no-query originserver round-robin login=PASS name=primary
acl sites_public dstdomain www.test.com app1.test.com app2.test.com
cache_peer_access primary allow sites_public
cache_peer_access primary deny all
Y si quiero que el virtual host <app1.test.com> lo proces <http1.test.com> y que el virtual host <app2.test.com> lo procese <http2.test.com>? Bien, pues declararemos dos cache_peer, de esta forma
cache_peer http1.test.com parent 80 0 no-query originserver round-robin login=PASS name=app1
acl sites_public_app1 dstdomain app1.test.com
cache_peer_access app1 allow sites_public_app1

cache_peer http2.test.com parent 80 0 no-query originserver round-robin login=PASS name=app2
acl sites_public_app2 dstdomain app2.test.com
cache_peer_access app2 allow sites_public_app2

cache_peer_access app1 deny all
cache_peer_access app2 deny all
Tener en cuenta, que ahora los controles para denegar el acceso a la caché a los dominios que no son nuestros, debe ir en última posición

Como la configuración puede ser un poco dificil si se empieza desde cero, os dejo un archivo de configuración de ejemplo para squid cache como proxy reverso

Configuración DNS y Puesta en Marcha
Nuestro reverse proxy no debe tener resolución por dns -o mejor dicho, tiene que tener unos propios- por ello, una solución sencilla -en vez de montar un servidor dns exclusivo- si no tenemos muchos hosts es declararlos en nuestro </etc/hosts>

Pero, qué debemos declarar? Bueno todos los host que tengamos en nuestros <cache_peer>, es decir, nuestro servidores Apache http. Continuando con nuestro ejemplo, el archivo </etc/hosts> contendrá las siguientes entradas:
# vi /etc/hosts
  # reverse proxy
  172.26.17.20    www.test.com      www.test.com
  # real http server
  172.26.17.1     http1.test.com        http1.test.com
  172.26.17.2     http2.test.com        http2.test.com
Ya sólo nos queda verificar que las configuraciones están correctas, crear la caché de squid y activar el servicio.

Comprobamos la sintaxis del archivo <squid.conf>

# /opt/www/squid-2.7/sbin/squid -k parse
Creamos la estrucutra de la caché
# mkdir -p /opt/www/squid-2.7/var/cache
# mkdir -p /opt/www/squid-2.7/var/run
# cd /opt/www/squid-2.7/var/
# chmod -R 700 cache logs
# chown -R nobody:nobody cache logs
# /opt/www/squid-2.7/sbin/squid -z
2010/04/30 13:14:57| Creating Swap Directories
Activamos el servicio squid-cache utilizando Solaris SMF
# svcs squid_2
STATE          STIME    FMRI
disabled       12:47:56 svc:/application/cache/squid_2:reverse_proxy
# svcadm enable squid_2
# svcs -p squid_2
STATE          STIME    FMRI
online         12:48:23 svc:/application/cache/squid_2:reverse_proxy
               12:48:23     6164 squid
               12:48:23     6166 squid
               12:48:24     6167 dnsserver
               12:48:24     6168 dnsserver
               12:48:24     6169 dnsserver
               12:48:24     6170 dnsserver
               12:48:24     6171 dnsserver
               12:48:24     6172 unlinkd
Ahora vamos a comprobar que nuestra instalación está correcta, para ello, utilizaremos el comando <squidclient> para realizar una petición http
# /opt/www/squid-2.7/bin/squidclient -h www.test.com -p 80 -r http://www.test.com
HTTP/1.0 200 OK
Accept-Ranges: bytes
Last-Modified: Tue, 09 Mar 2010 17:06:21 GMT
Content-Length: 7777
Content-Type: text/html
Date: Fri, 30 Apr 2010 10:49:55 GMT
Server: Apache/2.2.15 (Unix) mod_jk/1.2.30
ETag: W/"7777-1268154381000"
Age: 1770
Connection: close
Podemos comprobar el registro de squid-cache en el archivo <access.log> para ver que, realmente ha ido por la caché
# tail /opt/www/squid-2.7/var/logs/access.log
172.26.17.20 - - [30/Apr/2010:13:25:51 +0200] "GET http://www.test.com/ HTTP/1.1" 200 8041 TCP_CLIENT_REFRESH_MISS:ROUNDROBIN_PARENT
Rotación Logs de Squid
Por último, vamos a hacer que squid rote los archivos de logs utilizando una entrada en nuestro crontab que llame a squid con la opción <-k rotate> -puedes ver cómo editar el crontab en Solaris, si tienes problemas-:
# export EDITOR=vi
# crontab -e
  ##########################################
  ## ROTATE SQUID LOG
  ##########################################
  00 0 * * * /opt/www/squid-2.7/sbin/squid -k rotate
:wq

Conclusiones
Con esta entrega hemos concluido los requistos necesarios para poder poner nuestro tomcat en producción de forma eficiente. Ahora ya podemos explicar cómo se hace!

En las próximas entregas, veremos como configurar Solaris 10 utilizando zonas -para reverse proxy, http y j2ee- y cómo hacerlo con OpenSolaris y Crossbow. Esto nos servirá para ver las principales diferencias entre hacerlo con Solaris 10 y con OpenSolaris -es muy interesante-



<< Instalación de Apache HTTP como frontend de Tomcat
<< Instalación de Apache Tomcat como stand alone con VirtualHosts
 

Referencias

lunes, 19 de abril de 2010

Instalación de Apache HTTPD con Tomcat6 y Mod_JK

Introducción
En esta serie de artículos, vamos a ver las diferentes formas que hay para definir una estructura de Apache Tomcat para su puesta en producción. Veremos cómo podemos configurar Apache Tomcat con Apache HTTP mediante <mod_jk> y cómo poner <squid-cache> como frontend haciendo de proxy reverso.

Como es una serie y no un unico post iremos viendo cómo montar la infraestructura, desde lo más básico, hasta -en las últimas entregas- cómo ponerlo en producción.

Instalación de Apache HTTPD como frontend de Tomcat6 con Mod_JK
En esta ocasión vamos a ver cómo podemos utilizar Apache HTTP 2.2.x como frontend de nuestro Tomcat6. Para ello disponemos de varias soluciones, entre ellas:
  • Utilizar mod_proxy
  • Utilizar mod_jk 
Antes de comenzar, vamos a ver cuáles son las diferencias principales entre ambos métodos, y posteriormente explicaremos cómo son los pasos de instalación en ambos casos.
  • Técnica de Mod_Proxy:  Cuando utilizamos este método, todas las peticiones que entren en nuestro Apache HTTPD serán enviadas al Tomcat, es decir, tanto contenido estático como dinámico.
  • Técnica de Mod_JK: Cuando utilizamos este método, podemos discriminar qué queremos en Tomcat y que no queremos, es decir, podemos utilizar <*.jsp> para que sea tomcat quien lo procese, y el resto sea httpd quien lo gestion -contenido dinámico a tomcat, estático a httpd- Además, podemos gestionar cargas y failovers de nuestros balanceadores.
Una vez explicadas las diferencias, nos vamos a centrar en el uso de mod_jk ya que creo es una solución más robusta y nos permite más optimizaciones

Configuración Apache 2.2.x HTTPD en 64bits
Lo primero que vamos hace es decargar y compilar -yo voy a utilizar SunCC- el servidor http de Apache desde su web, si quieres puedes optar por Compilar Apache 1.3.x en 64bits sobre Solaris 10
$  wget http://www.eu.apache.org/dist/httpd/httpd-2.2.15.tar.gz
$ export CFLAGS="-m64 -O3"
$ export CC=cc
$ export LDFLGAS="-64"
$ ./configure 
   --prefix=/opt/www/apache2/64 \
   --enable-so \
   --enable-rewrite  \
   --enable-vhost-alias  \
   --enable-unique-id  \
   --enable-head  \
   --with-included-apr \
$ make
# make install
Instalación de Mod_JK 1.30 en 64bits
Al igual que antes, vamos a compilar Mod_JK en 64bits utilizando el compilador de SunCC -Sun Compiler Tools-
$ wget http://www.apache.org/dist/tomcat/tomcat-connectors/jk/source/jk-1.2.30/tomcat-connectors-1.2.30-src.tar.gz
$ gtar zxpf tomcat-connectors-1.2.30-src.tar.gz
$ cd tomcat-connectors-1.2.30-src/native
$ export CC=cc
$ export CFLAGS="-m64 -O2"
$ ./configure --with-apxs=/opt/www/apache2/64/bin/apxs
$ make
# make install
Configuración de Apache Mod_JK
A continuación vamos a configurar el módulo <mod_jk>, para ello, deberemos indicar en el archivo de configuración <$APACHE_HOME/conf/httpd.conf> que carge el módulo de mod_jk utilizando para ello "LoadModule" -en Apache 2.2 la ubicación es $APACHE_HOME/modules, en 1.3.x es $APACHE_HOME/libexec-
#############################################
# CARGA DE MODULOS JK
#############################################
LoadModule jk_module          modules/mod_jk.so

#################################################
## MOD_JK
#################################################
<IfModule mod_jk.c>
  JkWorkersFile conf/extra/modules/modjk.conf.d/modjk.conf
 JkLogFile logs/mod_jk.log
 JkLogLevel error
<IfModule>
Continuaremos con la creación del archivo de configuración <modjk.conf> que hemos definido en <JkWorkersFile> donde definiremos los nombres, puertos y demás parámetros de los tomcat que queremos utilizar.

El formato del archivo <JkWorkersFile> puedes encontrarlo en la documentación oficial de Apache Tomcat, pero os he preparado un JkWorkersFile de ejemplo con las principales propiedades para que no empeceis desde cero.

Configurar Apache Tomcat JK Connector
Ahora toca el turno a nuestra instalación de Apache Tomcat, para ello editaremos el archivo <$TOMCAT_HOME/conf/server.xml> y en el apartado <SERVICE> deberemos declarar un connector nuevo, pero esta vez, utilizará el protocolo <AJP/1.3>. El puerto debe ser el mismo que hemos puesto en el valor de la propiedad <Worker.Port>, por si alguno tiene dudas, aquí os dejo un archivo de configuración de Apache Tomcat Server.xml de Ejemplo:

    <Connector
        port="13201"
        protocol="AJP/1.3"
        redirectPort="8443"
        connectionTimeout="20000"
        bufferSize="8192"
        URIEncoding="UTF-8"
    />
Configuración VirtualHost de Apache
Por último, sólo nos queda indicar a Apache HTTPD Qué contenido debe ser procesado por Tomcat y cuál por él. Para ello, deberemos utilizar la propiedad <JkMount _mountpoint_ _worker_> donde mountpoint hace referencia a la expresión regular y worker al nombre del tomcat, por ejemplo, si queremos que todas las JSP y Servlet los procese nuestro worker router, haremos
JkMount /*.jsp router cluster1
JkMount /*servlet* cluster1
Por lo tanto, nuestro virtualhost deberá quedar así -ten en cuenta que es un ejemplo-
################################################
## WWW.TEST.COM
################################################
<VirtualHost *:80>
  JkMount /*.jsp cluster1
  JkMount /*servlet* cluster1
</VirtualHost>
Finalización de proceso
Ya tenemos configurado el sistema, sólo nos queda iniciar el Tomcat y el Apache, para probar que todo está como queremos.

Conclusión
En esta ocasión hemos visto cómo podemos poner un servidor Apache HTTPD haciendo de frontend de Tomcat y, esto nos va a permitir utilizar -por ejemplo- mod_rewrite para simular URL estáticas, además de proporcionarnos un LoadBalance que nos permitirá escalar nuestros aplicativos de forma sencilla.

Sin embargo, todavía esta configuración no es para ir a producción ya que no hemos tratado en ningún caso el uso de recursos, cargas, ... y, debemos separar las capas para establecer un punto de entrada (DMZ) el cual tengo un acceso muy controlado -utilizando IPFilter-

En la próxima entrega ya sí que veremos cómo establecer una configuración de producción -ahora que tenemos las bases- y veremos cómo utilizar la tecnología de zonas para encapsular nuestros servicios y hacerlos mucho más seguros.


<< Instalación de Apache Tomcat "Stand Alone"

Referencias

miércoles, 3 de marzo de 2010

Archivos de Configuración de Proxy Automática - Proxy PAC

Introducción
Hace un tiempo hablábamos de Cómo Utilizar los Archivos de Configuración Automática de Proxy (PAC), pero parece ser que este formato tiene algunos problemas -principalmente por las dudas que me han ido enviando- así que vamos a ver Cuáles son los problemas de una configuración automática (PAC) y cómo solucionarlas

Archivos PAC
Ya hemos hablado de cuál es su formato, pero vamos a hacer un pequeño repaso. Un archivo PAC, simplemente es una función JavaScript que devuelve si es necesario utilizar un Proxy -y cual- para una URL determinada.

El Problema
Nuestro principal problema viene dado con los equipos móviles, es decir, aquellos que necesitan diferentes configuraciones, veamos un ejemplo:

"Un equipo portátil que se conecta desde La Oficina, VPN y Wifi públicas"

Este equipo, deberá tener las siguientes configuraciones: Proxy 01 para la oficina, Proxy 02 para VPN y SIN Proxy para Wifi públicas

Si hemos definido un Archivo PAC que -por ejemplo- está en $HOME/proxy.pac tendremos un problema ya que no podemos identificar cuándo y dónde se encuentra <JavaScript Nos permite saber la IP local, pero cómo sabemos si esa IP es nuestra?>

La Solución

Para solucionar este problema está perl que nos va a aportar las funciones necesarias para poder crear un archivo PAC bajo demanda en función de quién y desde dónde -es cierto que cualquier lenguaje de script nos permite esto php, jsp, pero con yo he optado por perl-

Como podemos ver en el gráfico, necesitamos tener un DNS -o utilizar el archivo /etc/hosts- para resolver la dirección proxy.test.com de forma interna y un pequeño servidor Web -en mi caso Apache- capáz de ejecutar scripts.

Además, nuestro archivo de configuración <pac> estará ubicado en una dirección web y éste se creará mediante un script dinámicamente. Por último, necesitaremos que el DNS público resuelva también el host, en mi caso, la URL  es http://proxy.test.com/cgi-bin/proxy-conf.sf

Instalación del Sistema de Configuración
Lo primero que debemos hacer es Instalar Apache en Solaris 10 y le añadimos soporte para ejecución de <cgi>, para ello, editaremos el archivo $APACHE_HOME/conf/httpd.conf en la sección de <mod_mime.c> añadiremos la siguiente entrada
AddHandler cgi-script .sf
A continuación definiremos el VirtualHost
<VirtualHost *:80>
    ServerName proxy.test.com
    DocumentRoot /www/proxy.test.com
    ServerAdmin support@test.com
    # Script
    ScriptAlias /cgi-bin /www/proxy.test.com/cgi-bin
    ErrorLog logs/proxy.test.com-error_log
    CustomLog logs/proxy.test.com-access_log combined
</VirtualHost>
Verificamos y recargamos Apache
# /opt/www/apache-1.3.41/bin/apachectl configtest
Syntax OK
# /opt/www/apache-1.3.41/bin/apachectl restart
Creación del script en Perl
Vamos a crear un pequeño script en perl que, básimanente buscará la dirección IP origen, y en función de cuál sea, devolverá una respuesta a otra. En el ejemplo, si la dirección IP es 192.168.0.0/16 entonces, devolverá el proxy "PROXY-01.test.com", en caso contrario el acceso será DIRECT
# vi /www/proxy.test.com/cgi-bin/proxy-conf.sf
#!/usr/bin/perl -w
use strict;
use CGI qw(:standard);
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);

# #################################################
# PROYX-CONF.SF
#
# Description:
#       - script encargado de configurar los accesos de los clientes
#       hacia los diferentes proxy's y/o las excepciones necesarias
#
#       - la validacion de la configuracion se hace mediante el uso
#       de reglas.
# #################################################

# #################################################
# INFO SISTEMA
# #################################################
my ($cgiversion) = "ProxyAutoconf 3.0.0b_1 on Producction on 03.MAR.2008 by Urko";

# #################################################
# inicio del sistema de configuracion
# #################################################
## escribimos el tipo de archivo y las configuraciones necesarias
print "Content-type: application/x-ns-proxy-autoconfig\n\n";

# SOURCE_IP
my ($sourceip) = $ENV{REMOTE_ADDR};

# escribimos un pequeno comentario
print "// $cgiversion\n";
print "// (c) SafeChildren S.L. 2005-2010\n";

# generamos las cabeceras de la funcion
print "function FindProxyForURL(url, host) {\n";

# generamos el cuerpo en funcion de la IP origen
# si esta en la LAN 192.168.0.0/8
my($islan) = rindex($sourceip, "192.168");


if ( $islan >= 0) {
        print "return \"PROXY proxy-01.sfchildren.com:3128\";\n";
}else   {
        print "return \"DIRECT\";\n";
}

# generamos el fin de la funcion
print "\n}\n\n";
Ahora vamos a comprobar su funcionamiento, primero desde un host de la LAN <192.168.0.0/16> y luego desde Internet

$ wget http://proxy.sfchildren.com/cgi-bin/proxy-conf.cgi
--16:14:25--  http://proxy.sfchildren.com/cgi-bin/proxy-conf.cgi
           => `proxy-conf.cgi'
Resolving proxy.sfchildren.com... 10.4.7.17
Connecting to proxy.sfchildren.com|10.4.7.17|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/x-ns-proxy-autoconfig]

    [ <=>                                                     ] 184           --K/s

16:14:25 (10.26 MB/s) - `proxy-conf.cgi' saved [184]

$ more proxy-conf.cgi
// ProxyAutoconf 3.0.0b_1 on Producction on 03.MAR.2008 by Urko
// (c) SafeChildren S.L. 2005-2010
function FindProxyForURL(url, host) {
return "PROXY proxy-01.sfchildren.com:3128";

}
Y ahora desde una pública
$ wget http://proxy.sfchildren.com/cgi-bin/proxy-conf.cgi
--16:14:25--  http://proxy.sfchildren.com/cgi-bin/proxy-conf.cgi
           => `proxy-conf.cgi'
Resolving proxy.sfchildren.com... 193.24.37.17
Connecting to proxy.sfchildren.com|193.24.37.17|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [application/x-ns-proxy-autoconfig]

    [ <=>                                                      ] 184  --K/s

16:24:35 (1.59 MB/s) - `proxy-conf.cgi' saved [184]
$ more proxy-conf.cgi
// ProxyAutoconf 3.0.0b_1 on Producction on 03.MAR.2008 by Urko
// (c) SafeChildren S.L. 2005-2010
function FindProxyForURL(url, host) {
return "DIRECT";

}

Conclusión
Es cierto que el uso de Proxy PAC puede darnos algún que otro problema -principalmente con Java- pero si somos capaces de crear un entorno donde los usuarios no se vean afectados, esto nos ayudará mucho en nuestras tareas de administración.

Aunque en este post yo os he puesto un pequeño script, éste puede ser tan complejo como queramos, por ejemplo: En función de las Horas, Delegaciones, Usuarios, ... y de esta forma parametrizar de forma eficiente nuestras salidas a Internet.

A modo de anécdota sólo deciros que la implemntación de Java 1.5.x de ProxyPAC no era del todo correcta y fallaba, así que tuve que hacer un apaño para que si era Java devolviese el nombre del proxy sin más, era algo así -no está completo-
sub getRequestAgent () {
    my($agent) = $ENV{HTTP_USER_AGENT};
    my($isagent) = rindex($agent,"Mozilla");
  
    if ( $isagent != -1 ) {
      return "browser";
    } else {
      return "java";
    }
}
sub createFindProxyBody()
{
        my($arg1) = @_;
        my($browser) = &getRequestAgent();
        # si pone "java" entonces devolvemos el PROXY sin mas
        if ( $browser eq "java" ) {
            # ponemos el proxy de Java
                    print "return \"PROXY sol10-proxy-02.sfchildren.com:3128\";\n";
            return 0;
        }else {
                my($sourceIP) = $arg1;
                # esta aquí y no es JavaWS
                &createHTTPS();
                &createCommonExceptions($sourceIP);
                &createCommonRules($sourceIP);
            }       
}  


Referencias

miércoles, 17 de febrero de 2010

Solaris Network Cache and Accelerator, Cache Web a Nivel de Kernel - Parte 1

Introducción
Solaris Network Cache and Accelerator (NCA) es un sistema de caché a nivel de kernel. Se encarga de mantener las páginas más accedidas a nuestro servidor web en memoria incrementando el rendimiento de nuestros servidores Web.

Actualmente los servidores que soportan este funcionamiento optimizado en Solaris -sin cambios- son: Apache incluido en Solaris, Sun Web Server y Zeus. El funcionamiento se basa en la modificación del tipo de socket AF_INET por AF_NCA. No quiero entrar en mucho detalle de su funcionamiento, pero se basa en el uso de memoria compartida y un sistema de acceso rápido.

Y qué pasa con los Apaches -compilados- por nosotros que no tienen soporte nativo para AF_NCA? No hay problema. Simplemente deberemos precargar la bilbioteca /usr/lib/libnca_addr.so antes de ejecutar nuestros servicios (para 32bits) y /usr/lib/64/ncad_addr.so para 64bits.

Como hemos comentado en otras ocasiones, para precargar una biblioteca simplemente exportaremos la variable de entorno LD_PRELOAD_32 o LD_PRELOAD_64

Activar NCA
Para activar NCA, simplemente deberemos editar los archivos /etc/nca/nca.if y /etc/nca/ncakmod.conf y reiniciar la máquina. Veamos los sencillos pasos, lo primero que debemos hacer, es activar los interfaces en los cuales NCA va a escuchar -en el archivo /etc/nca/nca.if-. Los interfaces deben tener el archivo /etc/hostname._interface_ creado y dado de alta en el archivo /etc/hosts
# vi /etc/nca/nca.if
ce0
:wq
# ls -ltr /etc/hostname.ce0
-rw-r--r--   1 root     root          16 oct 15 13:35 /etc/hostname.ce0
# vi /etc/nca/ncakmod.conf
 status=enabled
 httpd_door_path=/var/run/nca_httpd_1.door
 nca_active=disabled
:wq
El módulo NCA, por defecto escucha en el puerto 80, pero podemos definir los puertos -y las IPs- en los que queremos que lo haga editando el archivo /etc/nca/ncalogd.conf
# cat /etc/nca/ncaport.conf
 ncaport=*/80
 ncaport=*/8080
:wq
Por último, podemos activar -no es obligatorio- el sistema de Log, editando el archivo /etc/nca/ncalogd.conf y pondremos la variable status=enabled y reiniciaremos la máquina para que los cambios tengan efecto.
# vi /etc/nca/ncalogd.conf
 status=enabled
 logd_path_name="/var/nca/log"
 logd_file_size=1000000
:wq
# reboot
Conclusiones
En esta primera parte hemos visto cómo activar NCA es realmente sencillo. En las siguientes partes, veremos si el Caché a nivel de kernel, es una solución aplicable a nuestra arquitectura.

Es muy importante tener en cuenta que si activamos NCA, es muy recomendable -si tenemos un volumen muy elevado de peticiones- que la dediquemos exclusivamente como servicio Web, o al menos, que intentemos limitar el número de procesos  de kernel para evitar sustos.

Referencias

miércoles, 16 de diciembre de 2009

Instalar Apache HTTP 64bits SunCC Solaris 10

Introducción
En esta ocasión vamos a ver cómo podemos Compilar Apache HTTP Server en 64bits utilizando SunCC en Solaris 10. Esto es debido en gran parte a un problema que os conté hace un tiempo sobre Problemas de Compilación Apache HTTP Server con GCC en Solaris 10 y que se debían a un bug de GCC en Solaris.

Continuando con la serie de Optimización de Páginas Web en Solaris, me he encontrado con otro problema, esta vez con el módulo mod_gzip que produce un core dump cuando se ejecuta compilado con GCC en 64bits. La verdad es que he probado de todo pero no he sido capáz de hacer funcionar este módulo con el servidor Apache HTTP en 64bits sobre Solaris compilado con GCC, sin embargo, cuando se compila con SunCC, el módulo mod_gzip funciona correctamente, por eso, he creado este pequeño post.

Al parecer, el problema viene con la biblioteca expat y cualquier módulo que utilice esta biblioteca, creará un coredump y el servidor nos devolverá una página en blanco <se caerá>. He estado compilando sobre diferentes arquitecturas <SPARC, x86> y, en ambos casos, se producía el mismo error. El servidor funcionaba correctamente hasta que se activaba el módulo mod_gzip

Requisitos
Para poder compilar Apache HTTP Server con SunCC, obviamente, es necesario tener instalado el Sun Studio Developer Tools y para instalarlo, deberemos seleccionar <al igual que con Java> el formato de instalación.

Una vez tengamos instalado nuestro SunCC, debemos incluir el directorio <bin> en nuestro PATH para que encuentre <cc> antes que <gcc>, por ejemplo, podemos editar nuestro .profile para que contenga:
PATH=$PATH:/opt/SUNWspro/bin:/usr/sfw/bin:/usr/ccs/bin:/usr/local/bin
export PATH
Comprobamos que tenemos el entorno correcto, como podéis comprobar, yo tengo la versión 5.9 del Sun Studio Compiler, pero también funciona con la última versión
$ which cc
/opt/SUNWspro/bin/cc
$ which gcc
/usr/sfw/bin/gcc
$ which make
/usr/ccs/bin/make
$ which gmake
/usr/sfw/bin/gmake
$ cc -V
cc: Sun C 5.9 SunOS_i386 Build40_1 2007/02/08
usage: cc [ options] files.  Use 'cc -flags' for details
Instalación de Apache
Vamos a seguir los mismos pasos que realizamos en Compilación de Apache HTTP Server con Mod Security y Mod Bandwidth en 64bit sobre Solaris, pero vamos a modifcar los siguientes valores:
  • En esta ocasión, no será necesario exportar la variable de entorno LD_LIBRARY_PATH
  • Asignaremos el valor de <cc> a la variable CC en el configure en vez de <gcc>
Una vez descargado y descomprimido el servidor, podemos comenzar a configurarlo con los siguientes valores:
$ export CC="cc"
$ export CFLAGS="-O2 -m64"
$ ./configure \
      "--with-layout=Apache" \
      "--enable-module=rewrite" \
      "--enable-module=expires" \
      "--enable-module=headers" \
      "--enable-module=mmap_static" \
      "--add-module=src/modules/extra/mod_bandwidth.c" \
      "--permute-module=BEGIN:bandwidth" \
      "--activate-module=src/modules/extra/mod_security" \
      "--enable-module=security" \
      "--disable-module=status" \
      "--enable-module=so" \
      "--prefix=/opt/www/64/apache-1.3.41" \
     "$@"
Una vez configurado, haremos un <make> y <make install> para finalizar la instalación.

Conclusiones
Después de horas de pruebas, no pude más que llegar a la conclusión de que el bug de GCC es más molesto de lo que a simple vista puede parecer. El problema no es que no se pueda solucionar, sino que como se produce en tiempo de ejecución, puede darse con cualquier módulo que instales y, por lo tanto, deje de funcionar tu servidor http.

Compilar Apache HTTP Server, Mod_JK, Mod_Gzip y los demás módulos necesarios para nuestro servidor Web, no suelen suponer mayor problema hacerlo con GCC o con SunCC, y por lo tanto, ahora que SunCC es free es una opción alternativa.

En el siguiente post veremos Cómo compilar Mod Gzip en Apache 1.3.41 64bits con SunCC en Solaris 10

Referencias

lunes, 30 de noviembre de 2009

Cálculo de Rendimiento de Apache 1.3.41 64bits vs 1.3.41 32bits en Solaris 10

Introducción
Continuando con la serie de Optimización de Páginas Web en Solaris, en esta ocasión vamos a ver qué diferencias de rendimiento podemos tener con la versión compilada de Apache 1.3.41 en 64bits y en 32bits, para ello continuaremos desde el punto anterior de Compilación de Apache 1.3.41 64bits en Solaris

Para ello, vamos a configurar solo el valor de la propiedad <Listen> del archivo de configuración $APACHE_HOME/conf/httpd.conf

Definición de las métricas de la prueba
Para realizar la prueba de rendimiento se han utilizado tres versiones de Apache HTTP 1.3.41 en Solaris x86_64 sobre una máquina virtual en MacOS X. Los detalles de la configuración son los siguientes:
  • Host: Virtual Box 3.0.10 r54097 Sobre MacOS X
  • Guest:  Solaris 10 10/09 s10x_u8wos_08a X86
  • Memoria: 2048 Megabytes
  • Versión Apache: Apache 1.3.41
Opciones de Compilación de Apache
He realizado tres compilaciones, dos en 32 bits y una en 64bits con los siguientes parámetros:
  • 32bits sin Opciones:
./configure \
"--with-layout=Apache" \
"--enable-module=rewrite" \
"--enable-module=expires" \
"--enable-module=headers" \
"--enable-module=mmap_static" \
"--enable-module=rewrite" \
"--add-module=src/modules/extra/mod_bandwidth.c" \
"--permute-module=BEGIN:bandwidth" \
"--activate-module=src/modules/extra/mod_security" \
"--enable-module=security" \
"--disable-module=status" \
"--enable-module=so" \
"--prefix=/opt/www/32/apache-1.3.41" \
"$@"
  • 32bits Configure con CFLAGS="-O2"
CFLAGS="-O2" \
./configure \
"--with-layout=Apache" \
"--enable-module=rewrite" \
"--enable-module=expires" \
"--enable-module=headers" \
"--enable-module=mmap_static" \
"--enable-module=rewrite" \
"--add-module=src/modules/extra/mod_bandwidth.c" \
"--permute-module=BEGIN:bandwidth" \
"--activate-module=src/modules/extra/mod_security" \
"--enable-module=security" \
"--disable-module=status" \
"--enable-module=so" \
"--prefix=/opt/www/32/apache-1.3.41" \
"$@"
  • 64bits Configure con CFLAGS="-m64 -O2"
CFLAGS="-O2 -m64" \
./configure \
"--with-layout=Apache" \
"--enable-module=rewrite" \
"--enable-module=expires" \
"--enable-module=headers" \
"--enable-module=mmap_static" \
"--enable-module=rewrite" \
"--add-module=src/modules/extra/mod_bandwidth.c" \
"--permute-module=BEGIN:bandwidth" \
"--activate-module=src/modules/extra/mod_security" \
"--enable-module=security" \
"--disable-module=status" \
"--enable-module=so" \
"--prefix=/opt/www/64/apache-1.3.41" \
"$@"
Herramientas de Testing
Se han utilizado las herramientas de Apache Benchmark, que se encuentra en $APACHE_HOME/bin/ab y Apache JMeter. Para hacer una prueba más realista se han realizodo tres métricas con Apache Benchmark (una detrás de otra), y se ha calculado la media con los datos de conexión, rendimiento, etc. La definición de los parámetros son los siguientes:
  • Apache Benchmark (32bits)
$ /opt/www/32/apache-1.3.41/bin/ab -n 10000 -c 15 http://localhost:8000/
  • Apache Benchmarck (64bits)
$ /opt/www/apache-1.3.41/bin/ab -n 10000 -c 15 http://localhost:8080/
  • Apache JMeter (32bits y 64bits)
Número de Hilos: 15
Contador del Bucle: 10000
Resultados Obtenidos
A continuación vamos a ver los gráficos de resultados de las pruebas de Apache Benchmark (recordar que se han realizado tres métricas y luego la media)

Apache 1.3.41 32bits sin Optimizaciones


Apache 1.3.41 32bits con Optimización -O2


Apache 1.3.41 64bits con Optimización -O2 -m64


Comparativa de las tres gráficas: 32 vs 32plus v2 64


Resultados de JMeter 32bits



Resultados de JMeter 64bits


Conclusiones
Aunque este test es bastante sencillo, podemos ver como la compilación en 64bits de Apache nos proporciona un mayor rendimiento, además, con el simple hecho de incluir <-O2> ya obtenemos una mejoría con la configuración por defecto.

Esto, que a simple vista es obvio, puede hacernos ver la importancia de compilar nuestros aplicativos en la arquitectura en la que queramos ejecutarlo, y en la medida de lo posible, evitar los paquetes precompilados para los entornos de producción.

En la siguiente entrega, veremos cómo podemos ir configurando Apache HTTP Server para obtener mayor rendimiento utilizando mod_expires y mod_gzip.

Referencias

martes, 24 de noviembre de 2009

Cálculo de Rendimiento utilizando Apache JMeter - Parte 1

Instalación
En este primer post vamos a ver cómo utilizar JMeter para establecer un "Base Time Line" para nuestros cambios de configuración.

Apache JMeter es un aplicativo diseñado para obtener métricas de rendimiento de una forma automática y repetible. Ésto que parece no es muy importante, sí que lo es. Una de las cosas que debemos eliminar de nuestro vocabulario cuando empecemos a realizar pruebas de carga son: "parece que, más rápido, más lento, ..." todas estas expresiones no nos sirven ya que dependen de muchos factores, aunque el mayor problema es que son subjetivas y dependientes de una/varias personas.

JMeter nos ofrece datos "la página tarda 2,7 seg" ya no depende de si es "rápido" o "lento" son "2,7 seg", si hacemos un cambio y JMeter ofrece "2,9 seg", el cambio hace que el sistema responda más lento.

Debemos tener en cuenta que JMeter no es un navegador y por lo tanto, no va a procesar los código JavaScript, me explico, JMeter no va a procesar los document.write del código HTML. Por ejemplo, el siguiente bloque de código no será interpretado por JMeter y por lo tanto, las latencias de render no se computarán.
<script type='text/javascript'>new BannerManager('http://openads.test.com/').getBanner(106,'banner106',true,-1,false,'null');script>
<script type='text/javascript'>new BannerManager('http://openads.test.com/').getBanner(107,'banner107',true,-1,false,'null');script>
  
<script type="text/javascript">
     var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
     document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
script>
Una vez aclarado el funcionamiento de JMeter, vamos a ver cómo configurar una batería de pruebas para simular el acceso a nuestras webs.

Instalación de JMeter
JMeter es una aplicación Java y necesita de JVM 1.5+ para poder ejecutarse. La instalación simplemente es descomprimir el archivo tar.gz en la ubicación que nosotros queramos ($JMETER_HOME)

Lanzar JMeter
Antes de lanzar JMeter vamos a analizar si las pruebas que vamos a llevar a cabo van a ser muy complejas, ya que si así fuera, necesitaremos ampliar la memoria asignada por defecto a JMeter.

JMeter se inicia con un tamaño máximo de memoria de 512Mb, y aunque en la mayoría de los casos es suficiente, yo suelo configurarlo para que abra con 1024Mb.

Para modificar el parámetro de memoria, simplemente incluiremos una variable de entorno llamada JVM_ARGS donde se le asignan los parámetros de la máquina virtual, por ejemplo
$ export JVM_ARGS="-server -Xms1024m -Xmx1024m"
$ jmeter.sh
También podemos editaremos el archivo $JMETER_HOME/bin/jmeter y cambiar el valor de HEAP para asignarle los valores que deseemos, en mi caso 1024m
# This is the base heap size -- you may increase or decrease it to fit your
# system's memory availablity:
HEAP="-Xms1024m -Xmx1024m"
Una vez configurado nuestro JMeter, ejecutaremos el script de arranque $JMETER_HOME/bin/jmeter.sh y se nos mostrará nuestro entorno de trabajo que se ve a continuación



Como podemos observar, JMeter nos ofrece dos categorías dentro del árbol principal
  • Plan de Pruebas
  • Banco de Trabajo
En esta primera parte, vamos a ver cómo configurar un nuevo plan de pruebas, y en la segunda parte veremos cómo podemos utilizar el Banco de Trabajo


Nota: En JMeter no existe el botón Guardar y por lo tanto, cuando hagamos un "Focus Lost" del componente éste quedará guardado.

Configurar un Nuevo Plan de Pruebas
Lo primero que debemos hacer es añadir un Grupo de Hilos, para ello seleccionaremos Plan de Pruebas y haciendo click con el botón derecho Añadir->Grupo de Hilos. Esto representará a nuestros usuarios, es decir, si queremos comprobar cómo responde nuestro aplicativo con 50 usuarios concurrentes, en la propiedad Número de Hilos deberemos poner 50.

Para establecer un Base Time Line debemos establecer el valor de Número de Hilos a 1, y Contador del Bucle a un valor superior a 1, de esta forma, podemos obtener la media de ejecución con un sólo usuario y, de esta forma, tomaremos este dato como nuestro punto de partida.
Cuanto mayor sea el valor de Contador del Bucle mejor será la precisión, ya que obtendremos más muestras y por lo tanto la media será más realista.

Ahora seleccionaremos nuestro Grupo de Hilos y con el botón derecho Añadir->Elementos de Configuración->Valores por Defecto para Petición HTTP. Esto nos permitirá incluir los valores generales de la petición como: Nombre del Servidor, Puerto, Protocolo y Encoding.

 Seleccionamos Grupo de Hilos y con el botón derecho Añadir->Muestreador->Petición HTTP y, como hemos introducido Valores por Defecto simplemente deberemos editar el valor de la propiedad Path.

Por último, introduciremos un Listener que nos proporcionará los valores de la muestra, en este primer ejemplo vamos a introducir un Árbol de Resultados, para ello, seleccionaremos Grupo de Hilos y botón derecho Añadir->Listener->Ver Árbol de Resultados

Ya sólo nos queda guardar la prueba, Archivo->Guardar Como ... y podemos ejecutarla utilizando el menú Lanzar->Arrancar y ver el resultado en Ver Árbol de Resultados.

Como podéis ver, el funcionamiento de JMeter es sencillo y la creación de planes de pruebas no es muy complicado, en cuatro clicks hemos obtenido un plan de pruebas, sin embargo la información que obtenemos con este Sencillo Plan no nos aporta mucho, vamos a ver cómo hacer un plan más realista. Podéis descargar esta prueba sencilla de JMeter HTTP

Instalar nuevo Listener

Antes de comenzar con el plan de pruebas vamos a instalar un Listener que nos mostrará de forma gráfica, y más amena, el rendimiento y tiempo de respuesta de nuestro muestreador. Para ello, debemos descargar e instalar Better JMeter Graphs, después reiniciaremos el JMeter. Una vez hecho esto, tendremos un nuevo Listener llamado Statistical Aggregate Report

Configurar un Plan de Pruebas Más "Complicado"
Al igual que hemos hecho en la Prueba Sencilla de JMeter para HTTP añadiremos un Grupo de Hilos, añadiremos también Valores por Defecto para Petición HTTP, ahora viene algún cambio, seleccionamos Grupo de Hilos y con el botón derecho Añadir->Elemento de Configuración->Gestor de Cookies HTTP.

Los usuarios no hacen siempre las mismas iteraciones, es decir, Home->Pagina1->Pagina2->Home, y por lo tanto, si queremos hacer un plan de prueba que pueda simular  a un usuario, debemos tener en cuenta esto, por ello, JMeter nos ofrece el Controlador Lógico Random Order, así que seleccionamos Grupo de Hilos y con el botón derecho del ratón Añadir->Controlador Lógico->Random Order.

Ahora vamos a introducir los muestreadores HTTP dentro de nuestro controlador lógico, para ello, seleccionamos Controlador Random Order y con botón derecho Añadir->Muestreador->Petición HTTP y aquí pondremos la primera página. Deberemos repetir este proceso para todas las páginas que queremos muestrear.

Por último, vamos a añadir nuestro Listener seleccionando Grupo de Hilos y con el botón derecho Añadir->Listener->Statistical Aggregate Report, guardamos la prueba y ejecutamos. Podéis descargar la Prueba JMeter HTTP Multiples Páginas


Conclusión
En esta primera parte hemos visto cómo movernos con JMeter y las opciones que nos aporta, además, tenemos el resultado en formato gráfico al incluir el listener alternativo.

En la siguiente parte, veremos cómo podemos crear pruebas mucho más complejas y cómo establecer valores de control en los muestreadores

Referencias