VPS con Git

Última actualización: 17 de marzo de 2020

Si alguna vez te has planteado contribuir a WordPress, existen muchas formas de hacerlo. Desde aquí te planteamos los primeros pasos para ello con la creación de una máquina virtual en la que sincronizar WordPress con su Git, de forma que siempre esté al día.

Esta configuración es correcta si quieres disponer de una versión de desarrollo de WordPress que puede ser útil para desarrollar y probar tus plugins o themes.

Requisitos

Lo primero que necesitaremos para montar un sistema de desarrollo es una cuenta de Git y una máquina donde instalar la versión de desarrollo de WordPress.

Git

Te recomendamos crear una cuenta directamente en Github, donde se encuentra el repositorio principal de WordPress. A partir de este crearemos nuestro sistema de pruebas y desarrollo.

Infraestructura

En principio se puede montar el sistema en cualquier tipo de máquina, ya sea una virtual, un Docker o un VPS. En este caso, para que esté al alcance de todos y sin requisitos mínimos, usaremos un VPS de cualquier proveedor. Si te interesa, puedes encontrar algunos VPS para desarrolladores.

En este caso hemos usado una máquina con 1 CPU, 2 GB de RAM y 10 GB de disco SSD. Con la mitad de recursos debería funcionar sin problema. Lo que vamos a mostrar se basa en un Ubuntu 18 LTS. Usaremos PHP 7.4, MariaDB 10.4 y otros servicios.

Hacer un fork del WordPress de Github

Lo primero a hacer es entrar en el Github de WordPress y pulsar en el botón Fork que hay en la esquina superior derecha.

Pulsamos en el botón Fork para crear una copia en nuestra cuenta.

Esto te acaba creando algo del estilo a https://github.com/javiercasares/WordPress.

Creamos una máquina

Como comentaba antes, podemos crear una máquina en cualquier sitio. Puede ser en un VPS de una empresa de hosting, o puede ser un Docker que tengamos en local. También hay opciones de usar el propio sistema de Vagrant. En este caso crearemos la máquina desde cero con nuestra configuración medianamente personalizada.

Como sistema operativo de este ejemplo vamos a usar Ubuntu 18 LTS.

Actualización del sistema

Lo primero que haremos es poner al día el sistema.

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

Una vez esto, pondremos en hora el sistema.

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

Además, instalaremos algunas herramientas básicas.

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

Servidor de Base de Datos

Para la base de datos vamos a usar MariaDB 10.4; esta versión tiene un gran cambio en cuanto al sistema de claves con respecto a su versión predecesora, por lo que, para evitar problemas, vamos a usar esta última versión.

Lo primero será descargar e instalar el servidor de base de datos.

$ curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version="mariadb-10.4"
$ apt -y update
$ apt -y install mariadb-server mariadb-client
$ systemctl restart mysql.service

Ahora que tenemos la base de datos instalada, ejecutaremos el sistema de configuración por primera vez.

$ mysql_secure_installation

Aquí se nos darán algunas opciones y preguntas. Prepara tu contraseña de root de la base de datos y guárdala bien.

Enter current password for root (enter for none):
Switch to unix_socket authentication [Y/n] n
Change the root password? [Y/n] y
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

Una vez hayamos contestado las preguntas, reiniciaremos la base de datos para dejarla funcionando.

$ systemctl restart mysql.service

Servidor Web

Para el servidor web vamos a utilizar nginx. Este servidor web funciona muy bien con WordPress a la hora de desarrollar o mantener sitios grandes, aunque no permite el uso de los ficheros .htaccess (se ha de configurar previamente, sin que los usuarios o plugins puedan cambiar la configuración).

$ add-apt-repository ppa:ondrej/nginx
$ apt -y update
$ apt -y install nginx
$ systemctl stop nginx.service
$ systemctl enable nginx.service
$ systemctl start nginx.service

Servidor PHP

Para que WordPress funcione necesitaremos instalar PHP, el intérprete del código. En este caso usaremos la versión de PHP 7.4. Además, instalaremos las extensiones recomendadas, lo que supondrá un trabajo extra de configuración.

Instalación base de PHP

Comenzaremos con el núcleo de PHP y de PHP-FPM, además de las extensiones básicas que vienen pre-compiladas.

$ add-apt-repository ppa:ondrej/php
$ apt -y update
$ apt -y install php7.4 php7.4-fpm php7.4-curl php7.4-gd php7.4-mbstring php7.4-xml php7.4-zip php7.4-mysql php7.4-mysqlnd php7.4-bcmath php7.4-gmp php7.4-tidy php7.4-dev php-pear pkg-config imagemagick libmagickwand-dev
$ pecl channel-update pecl.php.net

Instalación de ImageMagick

Esta extensión permite la gestión de imágenes mejoradas sobre GD.

$ pecl install imagick
$ echo 'extension=imagick.so' >> /etc/php/7.4/mods-available/imagick.ini
$ ln -s /etc/php/7.4/mods-available/imagick.ini /etc/php/7.4/fpm/conf.d/30-imagick.ini

Instalación de XDiff

Esta extensión permite la aplicación de patch que incluyen diferencias de ficheros.

$ cd /usr/src
$ wget http://www.xmailserver.org/libxdiff-0.23.tar.gz
$ tar -xzf libxdiff-0.23.tar.gz
$ rm -rf libxdiff-0.23.tar.gz
$ cd libxdiff-0.23
$ ./configure
$ make
$ make install
$ pecl install xdiff
$ echo 'extension=xdiff.so' >> /etc/php/7.4/mods-available/xdiff.ini
$ ln -s /etc/php/7.4/mods-available/xdiff.ini /etc/php/7.4/fpm/conf.d/30-xdiff.ini

Instalación de APCu

Esta extensión mejora el sistema de caché del código PHP.

$ cd
$ pecl install apcu
$ echo 'extension=apcu.so' >> /etc/php/7.4/mods-available/apcu.ini
$ ln -s /etc/php/7.4/mods-available/apcu.ini /etc/php/7.4/fpm/conf.d/30-apcu.ini

Instalación de Redis

También instalaremos la extensión del servidor de caché Redis.

$ pecl install redis
$ echo 'extension=redis.so' >> /etc/php/7.4/mods-available/redis.ini
$ ln -s /etc/php/7.4/mods-available/redis.ini /etc/php/7.4/fpm/conf.d/30-redis.ini

Configuración de PHP

Para el desarrollo, haremos algunos cambios en el fichero de configuración de PHP, sobre todo para dar más margen de maniobra a la memoria y a la visualización de errores por pantalla y a la hora de hacer pruebas.

Lo primero que haremos será abrir el fichero de configuración.

$ vim /etc/php/7.4/fpm/php.ini

Y allí haremos algunos cambios en la configuración.

max_execution_time = 60
memory_limit = 256M
error_reporting = E_ALL
display_errors = On
post_max_size = 32M
upload_max_filesize = 32M
date.timezone = UTC

NOTA: Se configura el que se muestren errores ya que se da por hecho que esta máquina es para desarrollo.

Una vez esto, configuraremos PHP-FPM para que se active automáticamente con el sistema.

$ systemctl stop php7.4-fpm.service
$ systemctl enable php7.4-fpm.service
$ systemctl start php7.4-fpm.service

Servidor de caché Redis

Instalaremos el servidor Redis y le daremos algunos cambios a la configuración para que no se sature.

Primero lo instalaremos y lo sincronizaremos con PHP.

$ apt -y install redis-server php-redis

Abriremos el fichero de configuración.

$ vim /etc/redis/redis.conf

Y haremos algunos cambios en la configuración.

maxmemory 256mb
maxmemory-policy allkeys-lru

Finalmente lo reiniciaremos, junto a PHP para que se aplique su extensión.

$ systemctl stop redis-server.service
$ systemctl enable redis-server.service
$ systemctl start redis-server.service
$ systemctl restart php7.4-fpm.service

Servidor de certificados TLS

Hoy en día todos los sitios deberían funcionar bajo HTTPS, por lo que para hacer más real y parecido el entorno de desarrollo usaremos un certificado de Let’s Encrypt. Para esto necesitaremos que el sitio tenga un hostname / dominio público. Normalmente los proveedores de VPS suelen ponerle un hostname a las máquinas, por lo que podemos usar ese.

Generaremos una cláve única además de instalar el sistema de Certbot para nginx.

$ openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
$ add-apt-repository ppa:certbot/certbot
$ apt -y update
$ apt -y install python-certbot-nginx

Y para que no se nos olvide, configuraremos una tarea programada que actualice automáticamente el certificado. Para ello abriremos el editor de crones.

$ crontab -e

Y allí añadiremos la ejecución, cada día a las 06:45.

45 6 * * * certbot renew

Servidor de cortafuegos / firewall

Instalaremos unas pocas medidas de seguridad. Para comenzar, como sólo vamos a acceder a la máquina por SSH y por Web, cerraremos todo excepto estos dos servicios.

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

Finalización de la configuración

En principio ya tenemos todo lo que necesitamos instalado, por lo que, antes de seguir, vamos a hacer una actualización completa del sistema (de nuevo) para eliminar software antiguo o incompatible con todo el que hemos instalado.

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

Configuración del sitio

Ahora que ya tenemos todo listo a nivel de sistema y herramientas, lo que haremos será configurar el software para que podamos trabajar con él como si de un sitio web normal y corriente se tratase, aunque con esa versión de desarrollo.

Lo primero que haremos será eliminar el sitio web por defecto que trae el sistema y lo sustituiremos por uno que de poca información.

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

Aquí añadiremos el siguiente código HTML por defecto.

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

Lo mismo haremos con el fichero robots.txt

$ vim /var/www/html/robots.txt

En el que bloquearemos su rastreo.

User-Agent: *
Disallow: /

Ahora que tenemos el sitio por defecto corregido, vamos a retocar la configuración de nginx para poder trabajar de forma más adecuada con nuestro sitio de desarrollo. Primero eliminaremos la configuración por defecto y la sustituiremos por una retocada.

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

Y sustituiremos la configuración por la siguiente.

user www-data;
pid /run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;
include /etc/nginx/modules-enabled/*.conf;
events {
  multi_accept on;
  worker_connections 65535;
  use epoll;
}
http {
  charset utf-8;
  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  server_tokens off;
  log_not_found off;
  types_hash_max_size 2048;
  client_max_body_size 64m;
  keepalive_timeout 65;
  server_names_hash_bucket_size 128;
  server_names_hash_max_size 1024;
  # MIME
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
  # logging
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;
  # ssl
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers on; 
  # gzip
  gzip on;
  gzip_vary on;
  gzip_proxied any;
  gzip_comp_level 9;
  gzip_disable "msie6";
  gzip_buffers 16 8k;
  gzip_min_length 1100;
  gzip_types application/atom+xml application/javascript application/json application/x-javascript application/xml application/xml+rss image/svg+xml text/css text/javascript text/plain text/xml;
  # more
  include /etc/nginx/conf.d/*.conf;
  include /etc/nginx/sites-enabled/*;
}

Además, añadiremos una configuración para trabajar con PHP y WordPress.

$ vim wordpress_fastcgi.conf

Que contendrá lo siguiente.

fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
fastcgi_buffers 256 16k;
fastcgi_buffer_size 128k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors off;
fastcgi_split_path_info ^(.+.php)(/.+)$;
try_files $fastcgi_script_name =404;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_ADMIN_VALUE open_basedir=$document_root/:/usr/lib/php/:/tmp/;
fastcgi_param PATH_INFO $path_info;
set $path_info $fastcgi_path_info;
include fastcgi.conf;

Una vez tengamos esto, deberíamos poder reiniciar nginx sin problema y dejarlo en marcha.

$ nginx -t
$ nginx -s reload

A partir de aquí vamos a hacer una copia del software de WordPress dependiendo de la cuenta de Git que hemos creado previamente. En este caso vamos a montar todo el sistema en la carpeta /webs/ desde la raíz del sistema, pero se puede hacer sobre cualquiera.

$ mkdir /webs/
$ cd /webs/
$ git clone https://github.com/javiercasares/WordPress.git
$ cd /webs/WordPress/

Ahora que tenemos el software clonado, vamos a hacer que sea navegable como de cualquier sitio web se tratase.

$ cd /etc/nginx/sites-available/
$ vim WordPress.conf

Donde crearemos una configuración mínima.

server {
  listen 80;
  listen [::]:80;
  server_tokens off;
  server_name example.com;
  root /webs/WordPress;
  index index.php index.html;
  location = /favicon.ico {
    log_not_found off;
    access_log off;
  }
  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }
  location ~ /.well-known {
    allow all;
  }
  location ~ /\.ht {
    deny all;
  }
}

Y reiniciaremos nginx para que se apliquen los cambios.

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

Ahora hemos de crear e instalar el certificado TLS para disponer de un sitio con HTTPS.

$ certbot --email hello@example.com --agree-tos --authenticator webroot --installer nginx

Cuando nos pregunte por la tura de nuestro software, le diremos que está en la carpeta correspondiente.

/webs/WordPress

Ahora hemos de crear la base de datos para nuestro sitio web. Necesitaremos la contraseña de root que configuramos previamente.

$ mysql -u root -p

Necesitarás una contraseña para esta base de datos exclusiva para nuestro WordPress de desarrollo. Por favor, crea tu propia contraseña que sea algo segura.

CREATE DATABASE wordpress CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin;
GRANT ALL ON wordpress.* TO 'wordpress'@'localhost' IDENTIFIED BY '__PASSWORD__';
GRANT ALL ON wordpress.* TO 'wordpress'@'127.0.0.1' IDENTIFIED BY '__PASSWORD__';
FLUSH PRIVILEGES;
quit

Ahora que tenemos el certificado TLS y la base de datos, vamos a crear nuestro sitio con toda la configuración segura, además de cierta configuración específica para WordPress.

$ cd /etc/nginx/sites-available/
$ vim WordPress.conf

Aquí podremos sustituir la configuración inicial básica por una más avanzada.

# All HTTP traffic will be sent to HTTPS
server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  return 301 https://example.com$request_uri;
  access_log off;
}
# REAL SITE
server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  # SSL
  ssl_dhparam /etc/ssl/certs/dhparam.pem;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:128m;
  ssl_session_tickets off;
  # SSL modern configuration
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_prefer_server_ciphers on;
  ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
  # SSL OCSP Stapling
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 208.67.222.222 8.8.8.8 valid=300s;
  resolver_timeout 2s;
  # Security headers
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
  #logs
  access_log /var/log/nginx/WordPress-access.log combined buffer=64k flush=5m;
  error_log /var/log/nginx/WordPress-error.log;
  #CONFIG
  server_name example.com;
  root /webs/WordPress;
  index index.php;
  # ROOT
  location / {
    try_files $uri $uri/ /index.php;
  }
  # ROOT PHP
  location ~ \.php$ {
    include wordpress_fastcgi.conf;
  }
  location ~ wp-config {
    deny all;
  }
  # HIDDEN FILES
  location ~ /\.well-known {
    allow all;
  }
  location ~ /\.ht {
    deny all;
  }
  # WEB FILES
  location ~ /favicon.(ico|png) {
    log_not_found off;
    access_log off;
  }
  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }
  # STATIC CACHES
  location ~* \.(aac|avi|bmp|bz2|cur|docx?|eot|exe|flv|gif|gz|heic|htc|ico|jpe?g|m4a|midi?|mov|mp3|mp4|mpe?g|ogg|ogv|otf|pdf|png|pptx?|rar|rtf|svgz?|tar|tgz|tiff?|ttc|ttf|txt|wav|webm|webp|wmv|woff|woff2|xlsx?|zip)$ {
    expires max;
    add_header Cache-Control "public";
    log_not_found off;
    access_log off;
  }
  location ~* \.(atom|css|js|rss)$ {
    expires 7d;
    add_header Cache-Control "public";
    log_not_found off;
    access_log off;
  }
  location ~* \.(?:eot|otf|ttf|woff|woff2)$ {
    add_header Access-Control-Allow-Origin "*";
  }
  location ~* \/wp-admin\/load-(?:scripts|styles)\.php {
    if ( $query_string ~* "^.{512,}$" ) {
      return 444;
    }
  }
}

Reiniciaremos nginx y accederemos a la carpeta de nuestro nuevo WordPress.

$ nginx -t
$ nginx -s reload
$ cd /webs/WordPress/

Instalación de WordPress

Ahora que ya tenemos todo listo a nivel de sistemas para tener un WordPress listo para moestrar errores y problemas, comenzaremos la instalación como de cualquier WordPress se trata. Para ello simplemente accederemos a la dirección web de nuestro hostname / dominio que hayamos configurado previamente.

Configuramos Git con un stream para WordPress

Ahora hemos de configurar nuestro software para que se pueda mantener al día con el código fuente de desarrollo de WordPress. Hay que recordar que esta versión del software suele ser una alpha o beta, por lo que las probabilidades de que haya errores son grandes, y por tanto de seben reportar en el Trac de WordPress.

Comenzaremos viendo qué datos remotos tenemos.

$ cd /webs/WordPress/
$ git remote -v

Nos debería aparecer algo parecido a esto:

origin  https://github.com/javiercasares/WordPress.git (fetch)
origin  https://github.com/javiercasares/WordPress.git (push)

Añadiremos otra fuente, la del Git principal.

$ git remote add wordpress https://github.com/WordPress/WordPress.git
$ git remote -v

Esto nos devolverá que tenemos varias fuentes, tal que así.

origin  https://github.com/javiercasares/WordPress.git (fetch)
origin  https://github.com/javiercasares/WordPress.git (push)
wordpress  https://github.com/WordPress/WordPress.git (fetch)
wordpress  https://github.com/WordPress/WordPress.git (push)

A partir de este momeno, podemos ir actualizando y sincronizando nuestro código, ejecutando una actualización de Git y, de paso, de todo el sistema.

$ apt -y update && apt -y upgrade && apt -y dist-upgrade && apt -y autoremove
$ cd /webs/WordPress/
$ git pull wordpress master

Y hasta aquí tenemos una instalación desde cero del Git principal de desarrollo de WordPress, donde podemos analizar o verificar nuestros desarrollos para futuras versiones.

Si entras en la dirección URL, te pedirá rellenar los datos como cualquier instalación normal. otra opción es crear tu propio fichero wp-config.php y que la instalación comience a funcionar.