WordPress con HAProxy

Tener varios WordPress en subdominios, carpetas, y sin usar WordPress MultiSite, puede ser una necesidad que por alguna situación del proyecto es necesaria. Y para conseguirlo, necesitamos HAProxy.

Este tutorial ha sido creado en un VPS de Clouding.io. Puedes crear tu propio VPS desde 3€/mes.

Además, tienes la posibilidad de crear tu VPS con la imagen de WordPress en un clic.

COLABORACIÓN

Objetivo a conseguir

Planteemos una situación que, se podría dar, ya sea con varios WordPress o con varias tecnologías diferentes.

Por un lado, tenemos en //example.com/ un sitio web; por ejemplo, una web corporativa.

Por otro lado, tenemos en //example.com/tienda/ una tienda.

Y, por otro, tenemos en //example.com/educacion/ con un sistema de cursos.

Sí, lo más sencillo sería crear un WordPress MultiSite con todo, pero, por la razón que sea, no es posible, por lo que hay que montar 3 WordPress simples, distintos, en 3 servidores diferentes.

Si el sistema estuviera en 3 subdominios, sería muy fácil, ya que apuntaríamos las entradas A de las DNS a las 3 IPs distintas. Pero en este caso no es así.

Y aquí es donde entra HAProxy, la herramienta que estará por delante de nuestros sitios y que se encargará de mandar el tráfico.

Qué vamos a crear

Para este experimento vamos a crear lo siguiente:

  • Un HAProxy que gestione todo el tráfico, por delante.
  • Un WordPress en la carpeta raíz (//example.com/).
  • Un WordPress en una carpeta (//example.com/tienda/).

Cada una de estas partes la vamos a montar en un VPS distinto, aunque en realidad los WordPress podrían estar, en principio, en un alojamiento compartido si se quisiera, por ejemplo, de varias agencias que los gestionan.

Instalando los WordPress

Lo primero que prepararemos son los dos WordPress. Hay que tener en cuenta que el dominio para instalarlo no estará apuntando en las DNS (ya que apuntará a la máquina del proxy), así que tendremos que instalar los 2 WordPress, uno en la raíz y otro en la carpeta, sin acceso web.

Por otro lado, aunque se pueden montar certificados Let’s Encrypt, es probable que algunas validaciones den error.

En cualquier caso, puedes seguir los manuales de instalación de WordPress para ambos casos.

Instalando HAProxy

En este ejemplo vamos a utilizar:

  • Ubuntu 22
  • HAProxy 2.6

Instalación de HAProxy

No en todos los sistemas operativos está la versión más actual de HAProxy disponible, por lo que la cargaremos desde un repositorio alternativo.

add-apt-repository -y -s ppa:vbernat/haproxy-2.6

Y haremos la instalación.

apt-get -y install haproxy

Podemos validar que está la versión 2.6.x instalada.

haproxy -v

Vamos a tratarlo como un servicio, para que al iniciar la máquina siempre se encienda y esté disponible. Para ello necesitamos activar el demonio.

cat > /etc/default/haproxy << EOF
#CONFIG="/etc/haproxy/haproxy.cfg"
#EXTRAOPTS="-de -m 16"
ENABLED=1
EOF

Ahora que ya tenemos todo listo, vamos a activarlo y dejarlo funcionando.

systemctl stop haproxy
systemctl enable haproxy
systemctl start haproxy
systemctl status haproxy

Para guardar los logs, activaremos el sistema.

cat > /etc/rsyslog.d/haproxy.conf << EOF
$ModLoad imudp
$UDPServerRun 514
$UDPServerAddress 127.0.0.1
EOF
systemctl restart rsyslog

Certificados TLS temporales

Hasta que configuremos los certificados definitivos, necesitaríamos tener unos certificados temporales para ir tratando el sistema siempre como HTTPS.

Así que crearemos nuestro certificado temporal con OpenSSL.

openssl req -nodes -x509 -newkey rsa:2048 -keyout /etc/ssl/private/temporal.key -out /etc/ssl/private/temporal.crt -days 365 -subj "/C=ES/ST=Barcelona/L=Barcelona/O=IT/OU=IT/CN=example.com"

Y cuando los tengamos, crearemos el certificado que usará HAProxy.

cat /etc/ssl/private/temporal.key /etc/ssl/private/temporal.crt > /etc/ssl/private/temporal.pem

Configurando HAProxy

Antes de nada, haremos una copia de seguridad del fichero base de configuración.

cd /etc/haproxy
cp haproxy.cfg haproxy.cfg-original

Y haremos una primera configuración para controlar el HTTP y poder crear los certificados con Let’s Encrypt.

cat > /etc/haproxy/haproxy.cfg << EOF
global
  log /dev/log local0
  log /dev/log local1 notice
  chroot /var/lib/haproxy
  stats socket /run/haproxy/admin.sock mode 660 level admin
  stats timeout 30s
  user haproxy
  group haproxy
  daemon
  # Default SSL material locations
  ca-base /etc/ssl/certs
  crt-base /etc/ssl/private
  # See: https://ssl-config.mozilla.org/#server=haproxy&server-version=2.0.3&config=intermediate
  ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
  ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
  ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
  log global
  mode http
  option httplog
  option dontlognull
  timeout connect 5000
  timeout client  50000
  timeout server  50000
  errorfile 400 /etc/haproxy/errors/400.http
  errorfile 403 /etc/haproxy/errors/403.http
  errorfile 408 /etc/haproxy/errors/408.http
  errorfile 500 /etc/haproxy/errors/500.http
  errorfile 502 /etc/haproxy/errors/502.http
  errorfile 503 /etc/haproxy/errors/503.http
  errorfile 504 /etc/haproxy/errors/504.http
frontend wordpress-http
  bind 1.2.3.4:80
  acl letsencrypt-acl path_beg /.well-known/acme-challenge/
  use_backend letsencrypt-backend if letsencrypt-acl
  acl wordpress-tienda-acl path_beg /tienda/
  use_backend wordpress-tienda if wordpress-tienda-acl
  default_backend wordpress-www
backend letsencrypt-backend
  server certbot 127.0.0.1:8899
backend wordpress-www
  server wordpress-www 10.0.0.2:443 ssl verify none
backend wordpress-tienda
  server wordpress-tienda 10.0.0.3:443 ssl verify none
EOF

Comprobaremos que el código es válido.

haproxy -c -V -f /etc/haproxy/haproxy.cfg

Y, finalmente, reiniciaremos el sistema para validar que todo está funcionando.

systemctl stop haproxy
systemctl start haproxy
systemctl status haproxy

Algunos detalles a comentar de este código…

frontend wordpress-http
  bind 1.2.3.4:80
  acl letsencrypt-acl path_beg /.well-known/acme-challenge/
  use_backend letsencrypt-backend if letsencrypt-aclTambién
  acl wordpress-tienda-acl path_beg /tienda/
  use_backend wordpress-tienda if wordpress-tienda-acl
  default_backend wordpress-www

Aquí vemos la configuración del frontal (frontend). Podemos indicarle la IP pública (1.2.3.4) a la que ha de responder, si la máquina tiene varias, o si queremos que response a todo podemos sustituirla por un asterisco (*).

Para que las peticiones del Let’s Encrypt responsan correctamente, vamos a crear el sistema de forma que sea la propia máquina la que responsa.

Posteriormente, indicamos que, el subsitio «tienda» mande el tráfico als ervidor de la tienda, y que el subsitio (o el resto de tráfico) vaya al servidor principal «www».

Y aquí tendremos los tres backends:

backend letsencrypt-backend
  server certbot 127.0.0.1:8899

backend wordpress-www
  server wordpress-www 10.0.0.2:443 ssl verify none

backend wordpress-tienda
  server wordpress-tienda 10.0.0.3:443 ssl verify none

El primero de ellos «letsencrypt-backend» lo usaremos para que las peticiones de certificados sean contestadas por Let’s Encrypt (mediante certbot).

El segundo de ellos «wordpress-www», será el backend que responsa a todas las peticiones por defecto, y que corresponder´`ia al WordPress que hay en la carpeta raíz. En este caso ya indicamos la dirección IP, que va por HTTPS y que, para evitar problemas internos, no haga verificación del certificado privado que puedan tener los sitios. De esta forma, la conexión irá cifrada, con un certificado válido o autofirmado.

El tercero de ellos «wordpress-tienda», corresponderá al WordPress que haya en en backend de la tienda. El funcionamiento es el mismo que en el caso anterior.

Generando el certificado Let’s Encrypt

Como en cualquier otro momento, haremos la llamada a la generación, y en este caso, la validación se hará por el sistema que hemos configurado en el HAPRoxy.

certbot certonly --standalone -d example.com --non-interactive --http-01-port=8899

Una vez se hayan creado los ficheros, haremos como anteriormente y crearemos uno para que el HAPRoxy lo utilice.

cat /etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/example.com/privkey.pem > /etc/ssl/example.com.pem

Configuración final de HAProxy

Ahora que ya tenemos el certificado y los distintos sitios funcionando, haremos los últimos ajustes en el fichero de configuración.

vim /etc/haproxy/haproxy.cfg

Allí sustituiremos y añadiremos algunos bloques:

frontend wordpress-http
  bind 1.2.3.4:80
  acl letsencrypt-acl path_beg /.well-known/acme-challenge/
  use_backend letsencrypt-backend if letsencrypt-acl
  redirect scheme https

frontend wordpress-https
  bind 1.2.3.4:443 ssl crt /etc/ssl/example.pem
  acl wordpress-tienda-acl path_beg /tienda/
  use_backend wordpress-tienda if wordpress-tienda-acl
  default_backend wordpress-www

backend letsencrypt-backend
  server certbot 127.0.0.1:8899

backend wordpress-www
  server wordpress-www 10.0.0.2:443 ssl verify none

backend wordpress-tienda
  server wordpress-tienda 10.0.0.3:443 ssl verify none

Al frontend que responde al puerto HTTP (80), le seguiremos dando los datos para validar el certificado, pero le diremos que el resto del tráfico lo mande al HTTPS.

Crearemos un nuevo frontend que responsa únicamente al HTTPS (443). En este caso le indicaremos dónde está el certificado que acabamos de crear, y le daremos las indicaciones para que mande el tráfico a los backends correspondientes.

Y, finalmente, mantendremos los dos backends que ya teníamos previamente.

Ahora, una vez más, validaremos el fichero de configuración y reiniciaremos el HAProxy, para dejarlo funcionando.

haproxy -c -V -f /etc/haproxy/haproxy.cfg

systemctl stop haproxy
systemctl start haproxy
systemctl status haproxy

Probando los sitios

Una vez tengamos el HAProxy, significa que ya podemos acceder a nuestros distintos WordPress.

Si entramos en //example.com/tienda/ podremos acceder a uno de ellos, y si accedemos a //example.com/ tendremos acceso al otro.

Una forma simple de comprobar que realmente son dos WordPress independientes es ponerle a cada uno de ellos un tema distinto.


Sobre este documento

Este documento está regulado por la licencia EUPL v1.2, publicado en WP SysAdmin y creado por Javier Casares. Por favor, si utilizas este contenido en tu sitio web, tu presentación o cualquier material que distribuyas, recuerda hacer una mención a este sitio o a su autor, y teniendo que poner el material que crees bajo licencia EUPL.

Servicios de Administración de Sistemas WordPress

¿Tienes un sitio web con WordPress de alto tráfico? ¿Eres una Agencia con servidores con cPanel, Plesk u otro panel en los que mantienes WordPress para tus clientes?

Si es así y te interesa un servicio profesional de mantenimiento de infraestructura WordPress y de mejora del rendimiento de tus sitios web o los de tus clientes, contacta conmigo.