Microordenadores - Desarrollos modernos para sistemas retro

Servidor de alto rendimiento con Nginx, PHP7, MariaDB y Redis en DragonFly BSD
25 de Diciembre de 2016

Cómo instalar un servidor web de alto rendimiento para aplicaciones que requieren PHP y base de datos con DragonFly BSD, un sistema que continúa la rama 4.x de FreeBSD enfocado en el rendimiento y a la innovación. Usaré una configuración minimalista sin ningún tipo de panel y Redis como motor de datos para reducir la carga sobre MariaDB y mejorar el rendimiento.

Continuando el anterior tutorial para instalar DragonFly BSD en un VPS, para poder sacarle provecho a este interesante sistema instalaré un servidor web para aplicaciones PHP que usan una base de datos MySQL. Necesitarás un servidor con 1GB de RAM con DragonFly instalado y un conocimiento básico de sistemas Unix o Linux. Aunque puede parecer complicado para novatos, es mucho más rápido de instalar y mantener comparado con paneles web como Plesk o cPanel, y sin desperdiciar los recursos de sistema. Este tutorial no es una guía exhaustiva de optimización, sino un punto de partida para configurar un sistema minimalista rápido y estable.

Instalación de MariaDB y Redis

MariaDB es un reemplazo libre de MySQL mantenido por los desarrolladores originales de MySQL. Aunque MariaDB no es 100% compatible con MySQL como se anuncia, servirá para la gran mayoría de aplicaciones.

# pkg search mariadb
# pkg ins mariadb101-client mariadb101-server redis
# echo 'mysql_enable="YES"' >> /etc/rc.conf
# echo 'redis_enable="YES"' >> /etc/rc.conf
# /usr/local/etc/rc.d/mysql-server start
# /usr/local/etc/rc.d/redis start
# mysql_secure_installation

mysql_secure_installation cambia los parámetros inseguros por defecto en MariaDB. Pulsa Enter en cada una de las preguntas:

  • Pide la contraseña actual de root de MySQL que por defecto está vacía.
  • Cambia la contraseña root de MySQL.
  • Elimina los usuarios anónimos de MySQL.
  • Desactiva acceso remoto root a MySQL.
  • Elimina la base de datos de pruebas y el acceso a ella.
  • Carga la nueva tabla de privilegios.
Enter current password for root (enter for none): Enter
Set root password? [Y/n] Enter 
Remove anonymous users? [Y/n] Enter
Disallow root login remotely? [Y/n] Enter
Remove test database and access to it? [Y/n] Enter
Reload privilege tables now? [Y/n] Enter

Cómo crear una base de datos y un usuario con acceso a ella

En este ejemplo crearé la base de datos foo y el usuario bar con acceso a ella con todos los privilegios, el procedimiento típico para instalar aplicaciones web que requieren base de datos. Para más información consulta la documentación de MariaDB y SQL.

% mysql -u root -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 9
Server version: 10.1.19-MariaDB FreeBSD Ports

Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create database foo;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> create user 'bar'@'localhost' identified by 'jo^GgeDe2^C}94';
Query OK, 0 rows affected (0.00 sec)

ariaDB [(none)]> grant all privileges on foo.* to 'bar'@'localhost';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> quit
Bye

La contraseña la genero con la herramienta jot de OpenBSD, que usa arc4random como fuente de números aleatorios:

$ jot -rc -s '' 32 33 127
B<6r=w22Iq32V'rFtS,Rh7;MpYdRSVl]

Instalación de Nginx y PHP7

Instalaré Nginx y PHP 7 con las extensiones necesarias para instalar Wordpress, una de las aplicaciones más usadas. Aclaro que no recomiendo el uso de Wordpress debido a su mala calidad, a su poca eficiencia y al mal código HTML y CSS que genera. Lo usaré como ejemplo de aplicación típica ineficiente para poner a prueba Redis.

# pkg ins nginx php70 php70-curl php70-mysqli php70-pdo php70-pdo_mysql php70-redis php70-session php70-zlib
# echo 'nginx_enable="YES"' >> /etc/rc.conf
# echo 'php_fpm_enable="YES"' >> /etc/rc.conf
# cp /usr/local/etc/php.ini-production /usr/local/etc/php.ini
# cat "cgi.fix_pathinfo = 0;" >> /usr/local/etc/php.ini
# /usr/local/etc/rc.d/php-fpm start

/usr/local/etc/nginx/nginx.conf

He hecho esta configuración de prueba de Nginx para que funcione con PHP en modo FastCGI a partir de la documentación de Wordpress y el ejemplo de configuración de Nginx. Es posible que haya algún error por lo que no recomiendo usarla en producción sin revisarla a fondo:

#user  nobody;
worker_processes  2;  # Número de cores

events {
    worker_connections  1024;
    multi_accept        on;
    use                 kqueue;  # En Linux se usa epoll
}

http {
    include          mime.types;
    default_type    application/octet-stream;
    sendfile        on;
    tcp_nopush      on;
    #keepalive_timeout  0;
    keepalive_timeout  65;

    server {
        server_name sam.casa;
        root /usr/local/www/sam.casa;
        index 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 ~ /\. {
                deny all;
        }
        location ~* /(?:uploads|files)/.*\.php$ {
                deny all;
        }
        location / {
                try_files $uri $uri/ /index.php?$args;
        }
        location ~ \.php$ {
                #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
                include fastcgi_params;
                fastcgi_intercept_errors on;
                #fastcgi_pass php;
                fastcgi_pass 127.0.0.1:9000;
                fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }
   }
}

Iniciando Nginx y permitiendo conexiones locales para FastCGI

# /usr/local/etc/rc.d/nginx start
# echo 'pass on lo0 from any to any' >> /etc/pf.conf
# pfctl -f /etc/pf.conf

Instalación de Wordpress

Como ejemplo de aplicación lenta instalaré Wordpress para comprobar cómo se comporta Redis. Para ello usaré el plugin Redis Object Cache, que se configura simplemente activándola desde el panel de control y . Observa que después de descargar el archivo he comprobado su checksum MD5, que aunque es un algoritmo débil, es el único método de comprobación que ofrece Wordpress.

% ftp https://es.wordpress.org/wordpress-4.7-es_ES.tar.gz
Requesting https://es.wordpress.org/wordpress-4.7-es_ES.tar.gz
100% |***********************************|  8268 KiB  247.75 KiB/s  
8466734 bytes retrieved in 00:33 (247.75 KiB/s)
% md5 wordpress-4.7-es_ES.tar.gz
MD5 (wordpress-4.7-es_ES.tar.gz) = 75d67f94bef8639488fa72211c02f96a
% tar zxf wordpress-4.7-es_ES.tar.gz
% su
# mv wordpress /usr/local/www/sam.casa
# chown -R www /usr/local/www/sam.casa/

Comprobando el número de consultas a la base de datos con la función get_num_queries() llama la atención que simplemente para la página principal Wordpress haga 32 consultas a la base de datos. Al usar Redis este número de consultas se reduce a unas 5 una vez que los datos se han cargado en su caché. Hay otro programa similar a Redis que es memcached el cual, aunque funciona bien, no me dió tan buenos resultados como Redis y al menos cuando lo usé no soportaba al funcionalidad de persistencia.

Más optimizaciones

Esta configuración me ha dado muy buenos resultados hace unos años cuando usaba Wordpress. Actualmente no tengo ningún sitio de este tipo en producción por lo que no puedo hacer mediciones en un entorno real. Para mejorar el rendimiento aún faltan más configuraciones:


Contenido relacionado: