Atrás

Apache HTTP Server: servidor «proxy» inverso y balanceador de carga

Esta es la primera publicación formal desde que se fundó el sitio web, y he pensado inaugurarla con un tutorial para marcar el enfoque del mismo.

En este tutorial, se explicará cómo usar Apache HTTP Server como servidor «proxy» inverso y balanceador de carga.

Base inicial

Se empieza partiendo de un «VirtualHost» (Huesped Virtual) con un nombre de servidor, dirección de correo de administración, raíz de documentos y registros.

<VirtualHost *:80>

	ServerName masfloss.net
	ServerAdmin masfloss@riseup.net

	Protocols h2c http/1.1

	DocumentRoot /var/www/web

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

En este caso se usa de ejemplo el fichero por defecto de sitio 000-default, que es usado para el puerto 80 con conexión «HTTP» sin cifrar.

Ya inicialmente, por razones de rendimiento, se habilita el protocolo «HTTP/2», específicamente la versión para conexiones no cifradas definida como «HTTP/2 Clearnet», y abreviada como «h2c», a diferencia del usado por defecto «h2» que sí es para conexiones cifradas.

Esto está declarado en la línea que incluye la directiva Protocols y se indican en orden los protocolos soportados por el sitio web que queremos hospedar.

Para poder hacer uso de ello, hay que habilitar el módulo http2 con la orden a2enmod <NOMBREDELMODULO> con permisos de administración.

Servidor «proxy» inverso

Para poder hacer que Apache HTTP Server como servidor «proxy» inverso, debemos habilitar algunos módulos aprovechando la orden visualizada previamente para ello.

Específicamente, los que habría que habilitar mínimo serían:

  • proxy_http: permite la posiblidad de conexión a servidores de fondo por «HTTP».

  • proxy_html: permite reemplazar los enlaces del sitio web que estamos «proxyficando» por los de la dirección por la que nos conectamos a nuestro servidor proxy inverso.

Adicionalmente, los siguientes módulos serían necesarios para ciertos casos o recomendados:

  • proxy_http2: permite la posibilidad de conexión a servidores de fondo por «HTTP/2».

  • ssl: usado en conjunto con el módulo proxy_http y/o proxy_http2, habilita la posibilidad de conexión a servidores de fondo por «HTTPS».

  • headers: permite el establecimiento o modificación de cabeceras por parte del servidor web tanto a los clientes que se conectan como a los servidores de fondo.

Ahora, tocaría ver como quedaría reflejado en la configuración:

<VirtualHost *:80>

	ServerName masfloss.net
	ServerAdmin masfloss@riseup.net

	Protocols h2c http/1.1

	SSLProxyEngine On
	ProxyPreserveHost On
	ProxyRequests Off
	ProxyPass /server-status !
	ProxyPass / https://cualquierotroservidorweb.net
	ProxyPassReverse / https://cualquierotroservidorweb.net

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

Como se puede apreciar, se suprime la directiva DocumentRoot dado que el servidor va a pasar todas las peticiones de la raíz a los servidores de fondo y se añaden algunas otras explicadas a continuación:

  • SSLProxyEngine: al activarla, permite la conexión a servidores de fondo que usen «HTTPS», pero solo recomendado cuando nuestro servidor web no actúe como servidor «proxy» de redirección de peticiones, que no es el caso.

  • ProxyPreserveHost: al activarla, envía la cabecera a los servidores de fondo con el nombre de dominio desde el que se está realizando la conexión, de forma que permite a los servidores de fondo actuar como si estos estuviesen actuando sobre ese dominio directamente sin una conexión «proxyficada». Siendo este el caso, es innecesario que los servidores de fondo estén siendo apuntados mediante una URL con dominio, sino que bastaría apuntar a los mismos mediante dirección IP.

  • ProxyRequests: al desactivarla, se asegura que el servidor web no actúa como servidor «proxy» de resguardo de peticiones.

  • ProxyPass: en este caso se usa de dos formas:

    • La primera forma declara la directiva, establece una ruta de acceso alterna y hace uso del signo de exclamación. La idea es que esa ruta no sea traspasada a los servidores de fondo, sino que sea el propio servidor web el que la interprete.

    • La segunda forma declara la directiva, establece una ruta de acceso a la raíz e indica una dirección web. Esto «proxyfica» la conexión a la raíz de nuestro sitio web hacia los servidores de fondo de la dirección web indicada.

  • ProxyPassReverse: se declara de la misma manera que ProxyPass y simplemente se asegura de que nuestro servidor web actuando como servidor «proxy» inverso no es traspasado debido a redirecciones «HTTP» en los servidores de fondo de la dirección web indicada.

Balanceador de carga

Partiendo de la configuración realizada para convertir Apache HTTP Server en un servidor «proxy» inverso, se puede transicionar hacia un balanceador de carga.

Para ello, se necesita activar, al menos, el módulo proxy_balancer que permite que Apache HTTP Server actúe como balanceador de carga.

Opcionalmente, se recomienda habilitar proxy_hcheck que permite evaluar la disponibilidad de los servidores de fondo y marcarlos como caídos en caso de no estar disponibles, y, al menos, uno de los módulos para las estrategias de distribución de carga de los dispuestos a continuación:

  • lbmethod_byrequests: distribuye la carga teniendo entre los servidores de fondo basándose en una configuración de peticiones compartidas calculada según la demanda de trabajo esperada a realizar por cada servidor de fondo y la prioridad de cada servidor de fondo para suplir dicha demanda de trabajo.

  • lbmethod_bytraffic: distribuye la carga teniendo en cuenta la cantidad de tráfico, en bytes, que se quiere que cada servidor de fondo maneje.

  • lbmethod_bybusyness: distribuye la carga teniendo en cuenta la cantidad de peticiones que cada servidor de fondo tiene asignadas actualmente. Cada nueva petición es asignada automáticamente a aquel servidor de fondo con el número más bajo de peticiones activas.

Existe otro módulo experimental de distribución de carga llamado lbmethod_hearbeat que requiere el módulo heartmonitor para escuchar las peticiones de los servidores de fondo, que deben tener, a su vez, el módulo heartbeat. Con ello, se puede repartir la carga en base a la preparación de cada servidor de fondo, a diferencia de las otras estrategias.

Una configuración de base teniendo en cuenta esto, quedaría reflejada de la siguiente manera:

<VirtualHost *:80>

	ServerName masfloss.net
	ServerAdmin masfloss@riseup.net

	Protocols h2c http/1.1

	Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED

	ProxyHCTemplate get5 hcmethod=GET hcinterval=5 hcpasses=1 hcfails=2 hcuri=/

	<Proxy balancer://masfloss>

		BalancerMember https://cualquierotroservidor.net route=masfloss1 hctemplate=get5
		BalancerMember https://cualquierotroservidor2.net route=masfloss2 hctemplate=get5

		ProxySet lbmethod=bybusyness stickysession=ROUTEID nofailover=On

	</Proxy>

	SSLProxyEngine On
	ProxyPreserveHost On
	ProxyRequests Off
	ProxyPass / balancer://masfloss/
	ProxyPassReverse / balancer://masfloss/

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

En esta nueva configuración se añaden nuevas directivas y se modifican otras explicadas a continuación:

  • Header: permite establecer cabeceras «HTTP» y, en este caso, es usada para crear una «cookie» llamada «ROUTEID» cuyo valor es establecido teniendo en cuenta el nombre de la ruta del servidor de fondo escogido para el balanceo, y que es modificada usando la variable de entorno que detecta el cambio de ruta del balanceador.

  • ProxyHCTemplate: es específica del módulo proxy_hcheck, y simplemente, tras llamarla, asignamos un nombre y seguidamente establecemos la configuración de comprobación que queremos evitar repetir manualmente en cada servidor de fondo que sea miembro del balanceador. Las variables internas de la misma están definidas a continuación:

    • hcmethod: permite definir el método para realizar la comprobación que puede ser uno de «HTTP» como GET o, directamente, TCP.

    • hcinterval: permite definir el intervalo de tiempo entre comprobaciones en segundos.

    • hcpasses: permite definir el número de comprobaciones correctas para que el servidor de fondo sea marcado como disponible para enviar peticiones.

    • hcfails: permite definir el número de comprobaciones erróneas para que el servidor de fondo sea marcado como no disponible para enviar peticiones.

    • hcuri: define la ruta a la que realizar las peticiones de la URL de cada servidor de fondo.

  • Proxy: se declara como una etiqueta, y, en este caso, especifica una ruta con protocolo de balanceador. Esta ruta es auto-definida y puede tener el nombre que se considere. Dentro se usan otras dos directivas:

    • BalancerMember: establece cada servidor de fondo que es miembro del balanceador y sus parámetros adicionales. En este caso definimos el nombre de la ruta para la «cookie» y la plantilla de comprobación a usar definida previamente.

    • ProxySet: permite establecer configuraciones específicas de la directiva Proxy. Se hace uso de variables para ello:

      • lbmethod: define el método de distribución de carga, siendo en este caso bybussyness que requiere el módulo lbmethod_bybussyness.

      • stickysession: define el nombre de la «cookie» para el mantenimiento de la ruta por cada sesión de conexión, evitando saltos entre cada petición realizada en una misma sesión de un cliente.

      • nofailover: define la sesión de conexión no admitirá fallos y, por tanto, romperá la misma en caso de que el servidor de fondo esté en estado de error o deshabilitado.

  • ProxyPass y ProxyPassReverse: se modifican apuntando a la raíz de la ruta del balanceador definido previamente y se suprime aquella referente a la ruta /server-status que sólo fue referenciada de ejemplo previamente.

Gestor del balanceador de carga

Para finalizar, quedaría habilitar el gestor del balanceador, que permite visualizar el estado de los servidores de fondo de los miembros del mismo y, a su vez, realizar cambios no persistentes, revertidos al reiniciar el servidor web o recargar la configuración, en tiempo de ejecución de los parámetros de cada uno de los miembros del balanceador así como este mismo.

Adicionalmente, para evitar la exposición del balanceador de carga, se añade una autentificación básica.

<VirtualHost *:80>

	ServerName masfloss.net
	ServerAdmin masfloss@riseup.net

	Protocols h2c http/1.1

	Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED

	ProxyHCTemplate get5 hcmethod=GET hcinterval=5 hcpasses=1 hcfails=2 hcuri=/

	<Proxy balancer://masfloss>

		BalancerMember https://cualquierotroservidor.net route=masfloss1 hctemplate=get5
		BalancerMember https://cualquierotroservidor2.net route=masfloss2 hctemplate=get5

		ProxySet lbmethod=bybusyness stickysession=ROUTEID nofailover=On

	</Proxy>

	<Location /balancer-manager>

        SetHandler balancer-manager

        AuthType Basic
        AuthName "+FLOSS ID"
        AuthBasicProvider file
		AuthUserFile /var/www/.auth

		<RequireAll>

			Require all granted
			Require valid-user

		</RequireAll>

	</Location>

	SSLProxyEngine On
	ProxyPreserveHost On
	ProxyRequests Off
	ProxyPass /balancer-manager !
	ProxyPass / balancer://masfloss/
	ProxyPassReverse / balancer://masfloss/

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

En esta nueva versión de la configuración, se añaden unas pocas directivas adicionales, mayoritariamente por necesidad del sistema de autentificación básica, y se vuelve a añadir otra:

  • Location: es una directiva en forma de etiqueta que establece una ruta declarada en el propio nombre partiendo de la raíz del sitio web hospedado, siendo en este caso la nueva ruta para el gestor del balanceador de carga. Internamente definimos otra serie de directivas para ello:

    • SetHandler: permite establecer el aplicativo que se va a gestionar dicha ruta. En este caso debe ser el gestor del balanceador de carga definido como balancer-manager.

    • AuthType: define el tipo de autentificación para acceder a la ruta, siendo en este caso Basic por el sistema de autentificación básica.

    • AuthName: en el sistema de autentificación básica permite definir un nombre identificativo para el mensaje de solicitud de autentificación.

    • AuthBasicProvider: es específica del sistema de autentificación básica, y permite definir la forma en la que se gestionan las credenciales de acceso, siendo en este caso file por ser un fichero.

    • AuthUserFile: es específica al seleccionar un proveedor de autentificación básica basado en fichero, y define simplemente la ruta del fichero.

    • RequireAll: es una directiva en forma de etiqueta que establece reglas de acceso a aplicar a todo cliente que acceda a dicha ruta. Internamente se definen las reglas siguientes:

      • Require all granted: indica que todo cliente tiene acceso a la ruta.

      • Require valid-user: indica que las credenciales de acceso deben ser válidas.

  • ProxyPass: siendo específica la que define que la ruta /balancer-manager no será proxyficada a los servidores de fondo.

Finalmente, el fichero definido por la directiva AuthUserFile es creado con la orden htpasswd -c /var/www/.auth <NOMBREDEACCESO> definiendo con posterioridad al ejecutar dicha orden con un nombre de acceso correspondiente la contraseña del mismo.

Para credenciales de acceso adicionales, se ejecutaría la misma orden sin la opción -c que crearía el fichero de nuevo reemplazando el anterior si existiese en dicha ruta.


Redacción: EchedeyLR