Instalar WordPress desde cero en Ubuntu 16 (para torpes como yo)

Ahora que estoy volviendo a hacer mis cosas a mi manera, me ha dado por volver a montarme yo mismo los WordPress, de una forma que sea escalable, o al menos que en un futuro me permita crecer. Y para eso he decidido pasar de un hosting compartidos a un VPS.

Uso WordPress desde 2005 y en todos estos años he pasado por todo tipo de alojamiento web: hosting compartidos, dedicados, VPS, gestionados, sin gestionar… Normalmente depende de la cantidad de sitios que he de gestionar para tomar una decisión u otra.

Ahora que estoy volviendo a hacer mis cosas a mi manera, me ha dado por volver a montarme yo mismo los WordPress, de una forma que sea escalable, o al menos que en un futuro me permita crecer. Y para eso he decidido pasar de un hosting compartidos a un VPS. Esto me ha llevado a algunos problemas a la hora de realizar las migraciones, pero al fin y al cabo, hay que empezar por algún sitio.

Este manual está creado y funcionando en un VPS de 5$/mes de DigitalOcean (los de 512MB de RAM). Obviamente está organizado para poder escalar si es necesario, aunque con una máquina de estas, para un blog “normalito” hay más que suficiente, y 60 dólares al año es un precio razonable para tener tu sitio con un control del 100%.

NOTA 1: En esta documentación las IP que usaré son rangos de IP privada (por supuesto hay que sustituirlas por la IP pública que os de vuestro alojamiento) y como dominio usaré siempre example.com (que por supuesto tenéis que cambiar por vuestro dominio).

NOTA 2: Seguro que hay mil formas de hacer esto que os voy a explicar yo. Esta es una de ellas, que a mi me funciona, mejorable, seguro (y si alguien quiere, que comente y lo mejoramos)

Lo primero que recomiendo hacer es tener la máquina creada, y pedir la IPv6. Puestos ya, configurémoslo todo al 100%. Esto implica que una vez tengamos la IPv4 y la IPv6 lo que hay que hacer es configurar las DNS con las entradas siguientes:

@    A      172.16.0.0
www  A      172.16.0.0
@    AAAA   fd12:3456:789a:1::1
www  AAAA   fd12:3456:789a:1::1

Si habéis elegido DigitalOcean como proveedor, lo primero es instalar su sistema interno de estadísticas (esto se puede obviar en cualquier otro hosting):

$ curl -sSL https://agent.digitalocean.com/install.sh | sh

Lo siguiente es poner en hora la máquina:

$ timedatectl set-timezone UTC
$ timedatectl set-ntp on

Y actualizar el sistema:

$ apt-get -y update
$ apt-get -y upgrade
$ apt-get -y dist-upgrade
$ apt-get -y autoremove

Comencemos instalando algo de software base:

$ apt-get -y install software-properties-common curl vim unzip

Lo primero que vamos a montar es la base de datos. Para ello usaremos MariaDB 10.2

$ apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
$ add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://ams2.mirrors.digitalocean.com/mariadb/repo/10.2/ubuntu xenial main'
$ apt-get -y install mariadb-server
$ mysql_secure_installation

Lo primero que se hace es descargar e instalar, y posteriormente configurar. Es muy recomendable poner contraseña a la base de datos y eliminar todo aquello que no se vaya a utilizar.

Lo siguiente es la instalación del servidor web. Aunque he utilizado durante muchos años Apache HTTPD, en este caso propongo el uso de nginx.

$ apt-get -y install nginx

Y finalmente vamos a instalar PHP, en este caso la versión 7.

$ apt-get -y install php php-fpm
$ apt-get -y install php-common php-curl php-gd php-iconv php-json php-mbstring php-mcrypt php-mysqli php-xml php-xmlrpc

La instalación la hago en 2 pasos; primero la instalación base, del PHP-FPM y posteriormente algunas bibliotecas añadidas para que WordPress funcione sin problema.

Ahora que tenemos todo instalado, activamos los servicios

$ systemctl enable nginx.service
$ systemctl enable mysql.service
$ systemctl enable php7.0-fpm.service

En este punto podríamos tener un sitio web funcionando, pero hoy en día lo interesante es tener un sitio web segcurizado con certificados SSL/TLS, así que vamos a usar Let’s Encrypt para ello, y que actualice y haga todo sólo. Comenzamos generando una clave segura:

$ openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

E instalamos el software de gestión de los certificados

$ add-apt-repository ppa:certbot/certbot
$ apt-get -y update
$ apt-get -y install python-certbot-nginx

Aunque aún no tenemos ningún certificado, os recomiendo dejar ya el cron puesto para que se autorenueven 8se ejecuta una vez al día a las 0645 UTC; podéis cambiarlo, por supuesto):

$ crontab -e

Contenido a añadir:

45 6 * * * certbot renew --dry-run

Lo siguiente es activar los Firewall (por ahora abrimos el nginx 80/443 y el SSH 22):

$ ufw app list
$ ufw allow 'Nginx Full'
$ ufw allow 'OpenSSH'
$ ufw enable

Vamos a montar un servidor de correo que permita el envío de correo sólo interno, para los correos que se manden desde el propio WordPress. Este sistema estará cerrado a correos externos o cualquier otra cosa.

$ apt -y install mailutils
$ ufw allow 'Postfix'
$ ufw reload

Ahora que está instalado, vamos a configurarlo

$ vim /etc/postfix/main.cf

Contenido a modificar:

inet_interfaces = loopback-only
mydestination = $myhostname, localhost.$mydomain, $mydomain

Iniciaremos el servicio de correo

$ systemctl enable postfix

Ahora configuraremos el sistema para que tenga nuestra cuenta de correo como base:

$ vim /etc/aliases

Contenido a modificar/añadir:

postmaster:    root
root:          mi.correo@example.com

Y para aplicar la configuración, ejecutaremos:

$ newaliases

Para acabar la parte de configuración del servidor, lo que queda por hacer es limpiar la web por defecto:

$ rm /var/www/html/index.*

Y sustituirla por otra cosa que “no moleste mucho”:

$ vim /var/www/html/index.html

Contenido a crear:

<!DOCTYPE html>
<p>Hello World!</p>

En este momento, si visitas la web desde la IP, deberías ver un mensaje por pantalla que diga: Hello World!. A partir de aquí podríamos utilizar este sistema para todas las webs distintas que queramos.

Para comenzar lo que haremos es crear la base de datos:

$ mysql -u root -p

Accederemos con la contraseña que configuramos en su momento, y crearemos la base de datos:

CREATE DATABASE example CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;

Porteriormente crearemos un usuario que tenga permisos para controlar la base de datos:

GRANT ALL ON example.* TO 'exampleuser'@'localhost' IDENTIFIED BY 'examplepassword';

Y antes de salir, lo que haremos es refrescar los permisos:

FLUSH PRIVILEGES;

Recuerda que para salir del servidor de base de datos puedes escribir “quit”.

El siguiente bloque es el de subir el propio WordPress, el software; el objetivo es crear el lugar donde subiremos el software y dejarlo de forma ordenada.

$ mkdir /var/www/example.com/
$ cd /var/www/example.com/
$ wget https://wordpress.org/latest.tar.gz
$ tar xzvf latest.tar.gz
$ rm latest.tar.gz
$ mv ./wordpress/* ./
$ rm -rf ./wordpress/

Y posteriormente configuraremos los permisos de los ficheros y de su sistema:

$ chown -R www-data:www-data ./
$ find /var/www/example.com/ -type d -exec chmod 755 {} \;
$ find /var/www/example.com/ -type f -exec chmod 644 {} \;

El primero de estos comandos lo que hace es dar permisos a los ficheros como el nginx genera; el segundo da permisos a las carpetas y el tercero a los ficheros. En principio con estos permisos se debería poder trabajar sin problema.

Comenzaremos a configurar el WordPress con su fichero de configuración. Aunque el software de instalación permite generarlo, he preferido crear una plantilla base con ciertas configuraciones:

$ cp wp-config-sample.php wp-config.php
$ vim wp-config.php

Contenido:

<?php
define('DB_NAME', 'example');
define('DB_USER', 'exampleuser');
define('DB_PASSWORD', 'examplepassword');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', 'utf8mb4_unicode_ci');
// Crear esto con https://api.wordpress.org/secret-key/1.1/salt/
define('AUTH_KEY', 'xxxxx');
define('SECURE_AUTH_KEY', 'xxxxx');
define('LOGGED_IN_KEY', 'xxxxx');
define('NONCE_KEY', 'xxxxx');
define('AUTH_SALT', 'xxxxx');
define('SECURE_AUTH_SALT', 'xxxxx');
define('LOGGED_IN_SALT', 'xxxxx');
define('NONCE_SALT', 'xxxxx');
//
$table_prefix = 'example_';
define('WPLANG', 'es_ES');
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
define('SCRIPT_DEBUG', false);
define('WP_CACHE', true);
define('WP_SITEURL', 'https://www.example.com');
define('WP_HOME', 'https://www.example.com');
define('COOKIE_DOMAIN', 'www.example.com');
define('AUTOSAVE_INTERVAL', 30);
define('EMPTY_TRASH_DAYS', 7);
define('WP_POST_REVISIONS', false);
define('DISALLOW_FILE_EDIT', true);
define('FORCE_SSL_ADMIN', true);
define('WP_AUTO_UPDATE_CORE', true);
define('IMAGE_EDIT_OVERWRITE', true);
//
if(!defined('ABSPATH')) define('ABSPATH', dirname(__FILE__) . '/');
require_once(ABSPATH . 'wp-settings.php');
?>

He puesto como configuración de “CHARSET / COLLATE” la de “utf8mb4” que permitiría una gestión avanzada de idiomas “raros” (no occidentales, como el chino, japonés, cirílico, árabe…) sin problema. Obviamente aquí cada uno que configure los detalles como le parezca mejor. Esto es una plantilla que yo uso.

Ahora que tenemos el fichero, vamos a quitar permisos para que no pueda ser modificado o leído por terceros:

$ chown www-data:www-data wp-config.php
$ chmod 600 wp-config.php

El siguiente bloque es el que va a permitirnos tener sitios webs distintos. La primera vez hemos de reconfigurar el sitio web por defecto, que se supone que sólo será para cuando se acceda a las IP (o cuando haya algo configurado apuntando a esas IP pero no sea algo que tengamos en marcha).

$ cd /etc/nginx/sites-enabled/
$ rm default
$ cd /etc/nginx/sites-available/
$ rm default
$ vim default.conf

Contenido:

server {
  listen 80 default_server;
  #listen 443 ssl http2 default_server;
  server_name _;
  root /var/www/html;
  index index.html index.php;
  location = /favicon.ico {
    log_not_found off;
    access_log off;
  }
  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
  }
  location ~ /.well-known {
    allow all;
  }
  location ~ /\.ht {
    deny all;
  }
}

Activaremos el sitio web, para que funcione y posteriormente comprobaremos que el nginx dice que está todo correcto:

$ ln -s /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/
$ nginx -t

Lo que nos debería mostrar por pantalla un mensaje tal que:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Si todo va correctamente, ahora sí que crearemos un sitio web para el WordPress; lo crearemos en dos fases. La primera simplemente haremos que responda el sitio y que se puedan generar los certificados de seguridad. Posteriormente los activaremos.

$ vim example.com.conf

Contenido:

server {
  listen 80;
    listen [::]:80;
  server_name untor.com www.untor.com;
    root /var/www/untor.com;
  location ~ /.well-known {
    allow all;
  }
}

Activaremos el sitio y comprobaremos que la configuración es correcta y reiniciaremos el servicio:

$ ln -s /etc/nginx/sites-available/untor.com.conf /etc/nginx/sites-enabled/
$ nginx -t
$ systemctl restart nginx.service

Ahora crearemos el certificado y los ficheros necesarios para que vaya el HTTPS:

$ certbot --nginx certonly

Elegiremos las opciones y los certificados que se requieran, y una vez que estén creados, los añadiremos al fichero de configuración. Sustituiremos el que acabamos de crear por uno mucho más detallado:

$ vim example.com.conf

Contenido:

server {
  listen 80;
  listen [::]:80;
  server_name example.com www.example.com;
  return 301 https://www.example.com$request_uri;
}
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  #ssl on;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_ecdh_curve secp384r1;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  ssl_session_timeout 1d;
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
  resolver 208.67.222.222 valid=300s;
  resolver_timeout 5s;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;
  add_header Strict-Transport-Security max-age=15768000;
  ssl_dhparam /etc/ssl/certs/dhparam.pem;
  server_name example.com;
  return 301 https://www.example.com$request_uri;
}
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  #ssl on;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_ecdh_curve secp384r1;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  ssl_session_timeout 1d;
  ssl_stapling on;
  ssl_stapling_verify on;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
  resolver 208.67.222.222 valid=300s;
  resolver_timeout 5s;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;
  add_header Strict-Transport-Security max-age=15768000;
  ssl_dhparam /etc/ssl/certs/dhparam.pem;
  server_name www.example.com;
  root /var/www/example.com;
  index index.php;
  location / {
    try_files $uri $uri/ /index.php?$args;
  }
  location = /favicon.ico {
    log_not_found off;
    access_log off;
  }
  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
  }
  location ~* \.(bmp|bz2|cur|doc|docx|exe|gif|eot|gz|htc|ico|jpeg|jpg|mid|midi|mp3|mp4|ogg|ogv|otf|png|ppt|pptx|rar|rtf|svg|svgz|tar|tgz|ttf|wav|webm|woff|woff2|xls|xlsx|zip)$ {
    expires max;
    add_header Cache-Control "public";
    log_not_found off;
  }
  location ~* \.(atom|css|js|rss)$ {
    expires 1d;
    add_header Cache-Control "public";
  }
  location ~ /.well-known {
    allow all;
  }
  location ~ /\.ht {
    deny all;
  }
  location ~* wp-config.php {
    deny all;
  }
}

Si todo va bien, ahora deberíamos probar este fichero, y si nos da correcto, reiniciar el servidor web:

$ nginx -t
$ systemctl restart nginx.service

Ahora es el momento de irte a tu navegador web, y visitar https://www.example.com/ (el dominio que hayas configurado), y debería aparecerte el instalador de WordPress que te pedirá el nombre de tu sitio, tu usuario y contraseña, etcétera.

En principio el sistema ya está funcionando correctamente, y permitiría, usando estos últimos bloques, disponer de varios sitios web funcionando en paralelo. pero antes de acabar quiero hacer unos pequeños cambios a la configuración del PHP.

$ cd /etc/php/7.0/fpm/
$ vim php.ini

Sustituir:

error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT

Por:

error_reporting = E_ALL

Este cambio no debe afectar en principio a nada, ya que el muestreo de errores seguirá apagado, pero si en un momento determinado se ha de activar, lo mejor es que muestre absolutamente todos los errores habidos y por haber.

Sustituir:

upload_max_filesize = 2M

Por:

upload_max_filesize = 32M

Este cambio es bastante útil para el WordPress, ya que permitirá que se puedan subir ficheros (imágenes, adjuntos, etc…) -los llamados Media- de ese tamaño que pongamos. Por norma general si sólo usas imágenes 2 Megas puede ser una cifra correcta, pero si realmente trabajas con imágenes de calidad, ficheros PDF o similares, seguro que se queda corto, por lo que puedes subirlo a 32 Megas, 128 Megas, e incluso si tienes vídeos y los quieres subir así, a 1 Giga (o más). Tampoco recomiendo pasarse.

Sustituir:

;date.timezone =

Por:

date.timezone = UTC

Y ya mi TOC me lleva a configurar algo que genera a veces problemas en muchos sistemas, que es la hora. Al principio pusimos la máquina en hora UTC, y ahora configuramos el PHP para que siga también esa regla. Finalmente lo único que queda es aplicar los cambios, reiniciando el propio PHP.

$ systemctl restart php7.0-fpm.service

Y hasta aquí el sistema que configura una máquina Ubuntu 16 para uno o más WordPress, con sus certificados HTTPS, con un sistema integrado de caché (activando además la propia de WordPress), con una base de datos de última generación, con un PHP a su última versión… Comod ecía, seguro que hay más trucos, configuraciones y demás, pero esto ha de servir de base para una instalación de uno o varios WordPress, y que funciona.

Configuración Inicial de WordPress

Hoy en la WordPress Barcelona estoy dando una charla sobre la Configuración Inicial de WordPress. Es curioso porque hace 3 años cuando comenzamos las meetups en Barcelona, la primera de ellas (que también di yo) se llamaba La configuración perfecta y básicamente el concepto de la presentación era el mismo. En aquella ocasión había una carga técnica muy elevada que, como feedback de aquella ocasión, en esta he eliminado a la mínima expresión necesaria.

En esta presentación comienzo desde el momento en el que el WordPress ha sido instalado pero aún no has entrado, explicando detalles sbre el acceso HTTPS, actualizaciones, la configuración básica del propio sistema WordPress, los plugins básicos que debería llevar WordPress de srie instalados (no quiero que los lleve, pero sí que tú los instales), y cómo configurar cada uno de ellos de la mejor forma inicial.

Pues, a partir de aquí no me queda nada más que decir que si te interesa, puedes descargarte la presentación Configuración Inicial de WordPress (PDF 5.42 MB).

WordPress y algunos problemas de phishing / spam

Desde hace unos pocos meses cada vez más veo hackeos en los WordPress. No tengo muy claro si es un problema interno del propio WordPress o si es de algún plugin (sí que me he encontrado en algún caso problemas con algunas plantillas que no estaban actualizadas y que usaban software externo para subir ficheros).

La cuestión es que como a veces e difícil darse cuenta de si te han colado algún bicho, me propuse hace un par de días a hacer una pequeña y simple mejora que, en general, debe de funcionar. La idea es sencilla: no dejar funcionar el PHP en las carpetas de subida de ficheros.

En general los usuarios tienen configurada la carpeta /wp-content/uploads/ y todo lo que suele haber aquí son imágenes o ficheros binarios, pero nada ejecutable. Si este es el caso, se puede incluir un fichero .htaccess en esta carpeta con el siguiente contenido:

RewriteEngine off
RemoveHandler .php
RemoveType .php
php_flag engine off

Básicamente aquí se consiguen varias cosas: que no funcione el “mod_rewrite”, que PHP no pueda ejecutar los ficheros PHP y, de paso, directamente apagar el PHP en estas carpetas.

Seguramente este fichero se podrá subir en algunas otras carpetas dentro de toda la estructura, aunque mi recomendación es que sólo se aplique a las carpetas a las que el usuario tiene acceso (¡cuidado! que depende de cómo esta configuración se hereda en subcarpetas) y en las carpetas de caché.

WordPress Child Themes y WPO

Desde hace unas cuantas versiones de WordPress que está disponible la opción de los Child Themes. Este sistema una de las cosas que pide es que, la creación de este sistema tiene como base hacer un @import del CSS padre.

En este sentido, aunque los ficheros PHP sobre escriben los otros, por lo que no hay afectación directa sobre el WPO, sí que hay un detalle que no es del todo correcto, y es precisamente ese, el base para crear un hijo, el de hacer ese import.

Y es que los @import son una de las reglas “prohibidas” en cuanto a WPO. Así que… ¿qué solución tenemos para arreglar esto?. La primera de ellas es hacer un copy & paste de todo el contenido del fichero. ¿Problema? Que si hay una actualización de la plantilla padre la información de la plantilla hijo no se actualizará.

La otra opción, que es algo más elaborada, lo que viene a hacer es lo mismo pero de forma automatizada. Para empezar el fichero no será un CSS al uso, sino que será físicamente un fichero PHP. En esa carpeta tendremos que incluir un .htaccess que haga un “rewrite” del .CSS al .PHP. Con esto tenemos solventado que el sistema vea que eso es una hoja de estilos válida. El fichero .htaccess será algo tal que así:

RewriteEngine On
RewriteRule ^style.css style.php

Ahora lo siguiente es automatizar el fichero .CSS. Para ello debemos hacer un par de temas. Lo primero es pensar que es un fichero programado, de forma que hay que devolver el contenido en el formato correcto. Así, la primera línea del fichero será algo tal que:

header('Content-Type: text/css');

Lo siguiente será incluir el contenido del fichero CSS original. Por ejemplo:

$contenidocss = trim(file_get_contents('../twentyeleven/style.css'));
if($contenidocss) {
  echo $contenidocss;
}

Si lo juntamos todo, nos quedaría algo similar a esto en el fichero style.php:

<?php
header('Content-Type: text/css');
?>
/*
Theme Name:     Twenty Eleven Child
Theme URI:      http://example.com/
Description:    Child theme for the Twenty Eleven theme 
Author:         Your name here
Author URI:     http://example.com/about/
Template:       twentyeleven
Version:        0.1.0
*/
<?php
$contenidocss = trim(file_get_contents('../twentyeleven/style.css'));
if($contenidocss) {
  echo $contenidocss;
}
?>
// a partir de aquí van los cambios y nuestros retoques del CSS
body {
  font-family: Verdana;
}

Con esto conseguiremos que el waterfall del sitio web no se vea bloqueado por culpa de ese @import en el CSS, que además siempre está al principio de las peticiones y no tiene ningún sentido.

Plugin para WordPress y Varnish

Acabo de parir… han sido 9 meses largos (en serio, he estado, ahora que lo pienso, 9 meses desarrollando cosas sobre este tema) pero han valido la pena porque hoy he subido al repositorio oficial mi primer plugin: WordPress Varnish as a Service.

Aunque en la página del repositorio no hay mucha información, he preparado una página interna sobre este mismo tema en el que hay algo más de información, como por ejemplo algunas funcionalidades, los idiomas a los que está traducido…

Hace unas semanas ya os comenté que estábamos preparando un servicio de Varnish para WordPress como Servicio que básicamente multiplica enormemente la velocidad de carga de las páginas (el WPO y el SEO, vamos). Y como contra prestación ha salido un bonito plugin.

Aunque ha habido varias versiones anteriores 8a lo mejor algún día las subo por tenerlas ahí almacenadas) la versión 1.0.1 funciona bien, es estable y hace lo que tiene que hacer. De todas formas en mi cabeza tengo bastante claro el roadmap hasta la versión 2.0. Además, seguramente lance otro plugin (complementario al del Varnish) para que WordPress funcione perfectamente sin problemas, ya que Varnish es un proxy y eso implica cosas…

Además, he tenido el gusto de poder presentárselo a la gente de Varnish Software y junto a ellos y otras personas lo iré evolucionando al máximo.

Si alguien tiene sugerencias, quiere probar el Varnish como Servicio o cualquier otra cosa, buscad en el menú que pone “contacto” y os aparecerá mi correo 😉

Varnish para WordPress como Servicio

¿Tu WordPress va lento? ¿Te gustaría que volase? Pues esta es la idea que he estado planteando desde hace unos días… Hace cosa de un año que comencé a montar blogs con WordPress bajo Varnish. Al principio iba bien pero configurarlo y mantener las máquinas es algo complejo, a parte de que no todo el mundo puede permitirse montar y mantenerlo. Así que, tras muchas vueltas, pruebas, testeo de plugins y demás, he conseguido poder montar un sistema que, de forma sencilla, permita cachear y mantener un WordPress con Varnish.

El sistema es sencillo… sólo hay que subir 2 plugins: uno de ellos es para purgar (limpiar) la caché de Varnish cuando alguien publica algo, comenta, edita… así, cuando el blog cambie, se regenera la caché y los usuarios ven las cosas nuevas y actualizadas; el otro plugin es algo más genérico y hace referencia a la gestión de la IP, ya que al ser un web-proxy siempre devuelve la misma IP y eso genera problemas con el spam y similares.

Una vez configurado esto, lo bueno es que se puede probar antes de ponerlo en producción. Simplemente te cambias la IP de tu fichero de host y compruebas si todo funciona correctamente. Una vez probado, se cambian las DNS del dominio y ya está, todo listo.

Una cosa buena también que tiene este sistema es que, si por lo que sea, el Varnish empezase a hacer e tonto o quieres dejar de usar el servicio, vuelves a poner tus DNS como antes, quitas los plugins y ya está, todo vuelve a la normalidad.

¿Te gustaría probarlo? Pues si te interesa puedes escribirme (si me adelantas el dominio en que lo quieres probar, mejor que mejor) y te escribo con todos los pasos. Por ahora vamos a dar una semana de pruebas a aquellos que lo quieras testear en su sitio (ya sea por fichero de host o en producción) y a partir de ahí valdrá 120 euros/año u 80 euros/semestre.

¿Qué cosas buenas tiene usar este sistema? Primero que tu sitio estará cacheado y que soportará picos de tráfico sin problema; que cuando un robots de búsqueda te visite verá que la web va rápida y te indexará más rápido; por norma general el tráfico SEO aumenta a las 4 semanas de usar este sistema… además, sigues teniendo el control de todo en todo momento.

Y para muestra, un par de pruebas… Las he realizado desde el sitio Web Page test, primero apuntando a la IP del servidor directamente y luego apuntando a la del servidor con Varnish. El sitio desde el que se han hecho las pruebas es París con conexión de Cable.

Enlaces a los resultados de la Prueba Directa y a la Prueba con Varnish.

Como detalle, que no lo he podido capturar al 100%, el sistema hace 2 peticiones, la primera normal, luego refresca y usa la caché del navegador, y luego vuelve a repetir lo mismo. En el caso del acceso duirecto, WordPress ha de generar completamente la página, que tarda aproximadamente unos 2,5 segundos. Luego, en cualquier caso, el refresco es rápido, y tarda muy poco. Cuando estos e hace con Varnish delante, la primera ocasión tarda lo mismo, pero cuando vaciamos la caché del navegador como ya no se genera la página, tarda tan sólo 1,5 segundos.

Directo Varnish
lectura 1 2.575s 2.765s
caché 1 1.238s 0.435s
lectura 2 2.172s 1.416s
caché 2 1.245s 0.315s

En general, como los usuarios navegarán por las versiones de “lectura 2” (la lectura 1 sólo se ejecutará cuando haya contenido nuevo o se vacíe la caché), los datos muestran que el blog carga entre un 60% y un 75% más rápido. Os dejo con algunos otros gráficos:

En estos datos se ven los tiempos de respuesta que han obtenido mejor valoración en las 2 pruebas realizadas…

Acceso directo:

Acceso por Varnish:

Aquí se muestra en una valoración simple los resultados que dan Google Page Speed y Yahoo! YSlow…

Acceso directo:

Acceso por Varnish:

Y finalmente un checklist de todas las peticiones que se han relalizado…

Acceso directo:

Acceso por Varnish:

En fin, creo que es bastante obvio que usar Varnish es una gran ventaja competitiva con respecto a los sitios que no lo tienen…

Otra prueba interesante es hacer un test de estrés. La idea es hacer crecer las peticiones simultáneas al sitio… el test lleva un 50% de visitas desde Dublín (IE) y un 50% de visitas desde Palo Alto (CA, US), hasta las 100 conexiones simultáneas. Las gráficas son bastante clarificadoras…

Enlaces a los resultados de la Prueba Directa y a la Prueba con Varnish. Creo que las gráficas hablan por sí solas…

Tiempos de carga por página:

Clientes 15 31 51 70 85 100
Directo 1.63s 2.71s 3.98s 17.26s 21.18s 26.54s
Varnish 1.27s 1.14s 1.20s 1.28s 1.48s 1.27s

Acceso directo:

Acceso por Varnish:

¿Te gustaría probarlo? Pues si te interesa puedes escribirme (si me adelantas el dominio en que lo quieres probar, mejor que mejor) y te escribo con todos los pasos. Por ahora vamos a dar una semana de pruebas a aquellos que lo quieras testear en su sitio (ya sea por fichero de host o en producción) y a partir de ahí valdrá 120 euros/año u 80 euros/semestre.

Tras la WordCamp Sevilla 2011

Como ya sabéis muchos de vosotros este fin de semana he estado en la WordCamp Sevilla 2011. Las WordCamp son los eventos oficiales de WordPress en los que suele ir gente de Automattic, la empresa que hay detrás de este grandísimo software, además de usuarios y desarrolladores de la plataforma.

Durante el fin de semana estuve dando un par de charlas, una sobre Google Panda y WordPress, en la que comenté como reducir la cantidad de URL que genera WordPress perdiendo el mínimo tráfico posible, y sabiendo que en la nueva versión el propio sistema, a sabiendas de esto, va a incorporar mejoras de forma automática para que no afecte negativamente. La otra charla, de un nivel técnico más elevado, trató sobre WordPress Performance Optimization, comentando dos temas principales: la infraestructura para montar algo que soporte cientos de miles de visitas diarias y otra parte con plugins (y más sencillo de implementar) que ayuden a mejorar el rendimiento y la seguridad de la plataforma.

El evento fue durante dos días (sábado y domingo) el primer día dedicado más a aquellos que utilizan la plataforma y el segundo a los que administran o desarrollan sobre la plataforma. ¿Cosas que he aprendido? Pues el tema de los Child Themes, algo bastante sencillo que se aplicó hace poco, pero, como me he dedicado más desde WordPress 3 al rendimiento que al desarrollo de temas se me había pasado. A parte de eso, la seguridad, ataques y demás que cada vez hay más, mantener pocos plugins y bien testeados y que todo lo que se desarrolle sea internacionalizable.

Una de las cosas que comenté en mi presentación fue sobre la desaparición de MyISAM en las futuras versiones de MySQL, concretamente (por las últimas noticias que tengo) a partir de la versión 5.6 ya sólo vendrá INNOdb, algo que considero muy razonable, ya que las bases de datos deben ser relacionales. Esto implica un cambio de paradigma en WordPress donde las tablas no están relacionadas. Como experiencia personal, INNOdb aún no soporta FullTEXT (parece que la siguiente versión lo hará) por lo que se puede migrar de MyISAM a INNOdb teniendo en cuenta esta pérdida. Este sitio ya tiene aplicado este tipo de base de datos y lo cierto es que mejora ciertamente el rendimiento y al estar relacionada evita ciertas cagadas a la hora de eliminar contenidos.

Como último detalle para futuras WordCamp en España propondría a los organizadores tener alguna sala para hacer talleres de 2-3 horas, muy en plan práctico. Me parece genial meter charlas de media hora que son muy dinámicas pero, creo, que eso evita poder enseñar muchas cosas con código interesantes para que la gente pueda aplicarlo. Hacer un taller de 3 horas (montar un WordPress desde cero y configurarlo, plugins esenciales y configuración, escalar WordPress, creación de Child Themes…) podría estar bien para aquellos que tiene un nivel muy muy bajo o muy muy alto de la plataforma, aunque fuera pagando un extra de algunos euros para subvencionar los ponentes (que no es lo mismo dar una charla de media hora que hacer unos talleres).

Algunos ya sabréis que a finales de noviembre está previsto que se organice una WordCamp en Madrid, así que, si no falla nada, por allí nos veremos.

WordPressformance Optimization #WordCampSev 2011

Ayer ya di la charla de Google Panda y WordPress y hoy ha tocado la charla de WordPress Performance Optimization, que he reducido a WordPressformance.

La charla de hoy ha tratado de cómo montar una infraestructura más organizada en sitio que necesitan alto rendimiento, ya que está claro que montar un WordPress en la misma máquina el Apache, SQL y PHP pues como que no es lo mejor…

Así que nada, aquí os dejo la presentación en PDF para los que queráis descargarla.

WordPress y Google Panda #WordCampSev 2011

Entre hoy y mañana se está celebrando el WordCamp Sevilla 2011 y voy a dar 2 charlas… la primera de ellas se llama WordPress y Google Panda y, como ya podéis supones habla de la relación que hay entre el nuevo algoritmo Google Panda y WordPress (.org).

Os dejo la presentación descargable en PDF.

Como comentario a destacar (que he de analizar en una versión de pruebas que tengo) es que me han comentado que WordPress 3.3 incluirá grandes mejoras en cuanto a qué indexa y que no indexan los buscadores en determinadas URL de WordPress. Habrá que verlo y en base a eso analizar hacia dónde va el SEO de WordPress.

WordCamp Sevilla 2011

Hace más de 6 años que utilizo WordPress… concretamente desde la versión 1.5 cuando lancé OJObuscador allá por mediados de junio de 2005. Había utilizado muchos CMS, pero desde aquel momento todos los proyectos que he tenido que lanzar (sin contar los de desarrollo propio) han sido lanzados con WordPress.

Ahora que WordCamp vuelve a España he creído conveniente devolver un par de trucos a la comunidad… además ambos van relacionado con temas que me gustan, como son el WPO y el SEO, por lo que todo perfecto. Los próximos 8 y 9 de Octubre estaré por Sevilla.

Las charlas son las siguientes:

  • WordPress y Google Panda: La idea es comentar algunas cosas que WordPress no acaba de hacer correctamente y que a Google no les gusta, pero con un plugin y unos pequeños cambios se puede arreglar de forma simple. Será el Sábado 8.
  • WordPressformance Optimization: He creído divertido este concepto, en el que básicamente explicaré una infraestructura y configuración de servidores que permite que WordPress pueda soportar cientos de miles de visitas diarias sin parpadear. Será el Domingo 9.

Como siempre, todo lo que explicaré estará descargable (supongo que en esta entrada o en otra, además de en la propia web del WordCamp Sevilla 2011) y, si no me equivoco, grabarán en vídeo las presentaciones, por lo que podréis ver más adelante lo que explico delante de vuestro ordenador. Además han abierto un canal de twitter @WordCampSev desde el que puedes seguir todo lo relacionado con el mismo.

Si alguien tiene alguna consulta o sugerencia que quiere que comente y me la quiere decir antes de ir al evento, que lo haga y lo intento meter en las presentaciones (aunque ya las tengo casi acabadas). Y recordad que sólo vale 15 euros y que si tienes pasta podrías estirarte y patrocinar el evento, o colaborar aportando material.