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.

Deja un comentario