Autor: Joel Barrios Dueñas
Correo electrónico: darkshram en gmail punto com
Sitio de Red: https://www.alcancelibre.org/
Licencia de este documento: Creative Commons Reconocimiento-NoComercial-CompartirIgual 2.1
© 1999-2024 Joel Barrios Dueñas. Usted es libre de copiar, distribuir y comunicar públicamente la obra y hacer obras derivadas bajo las condiciones siguientes: a) Debe reconocer y citar al autor original. b) No puede utilizar esta obra para fines comerciales (incluyendo su publicación, a través de cualquier medio, por entidades con fines de lucro). c) Si altera o transforma esta obra o genera una obra derivada, sólo puede distribuir la obra generada bajo una licencia idéntica a ésta. Al reutilizar o distribuir la obra, tiene que dejar bien claro los términos de la licencia de esta obra. Alguna de estas condiciones puede no aplicarse si se obtiene el permiso del titular de los derechos de autor. Los derechos derivados de usos legítimos u otras limitaciones no se ven afectados por lo anterior. Licencia completa en castellano. La información contenida en este documento y los derivados de éste se proporcionan tal cual son y los autores no asumirán responsabilidad alguna si el usuario o lector hace mal uso de éstos.
Wordpress es sin duda alguna el CMS más popular del mundo. Fue publicado por primera vez el 27 de mayo de 2003 con el enfoque de servir como sistema gestor de contenidos para cualquier tipo de sitio Web. es software libre publicado bajo los términos de la licencia GNU/GPL versión 2.0.
Está desarrollado en el lenguaje PHP para entornos que ejecuten MySQL o MariaDB como motores de bases de datos y Apache o Nginx como servidor Web.
Buena parte del éxito y adopción de Wordpress como CMS es la enorme comunidad de desarrolladores y diseñadores y el enorme ecosistema de complementos y plantillas libres y comerciales. Y es por todo ésto que dos terceras partes de todos los sitios de Web actuales utilizan Wordress.
Al tratarse de un software tan popular, es obvio que también es uno de los principales objetivos de la delincuencia informática. Por tanto instalarlo de manera segura es importante para cualquier administrador de sistemas.
Sitio Web: https://wordpress.org
(1)Aunque Wordpress funciona perfectamente con las versiones más recientes de PHP, lamentablemente muchos complementos para éste sólo son compatibles con hasta PHP 7.4, por tanto y mientras el ecosistema de extensiones se actualiza, se recomienda preferir utilizar PHP 7.4, salvo que se tenga la certeza de que todos los complementos a utilizar son compatibles con PHP 8.0 o versiones posteriores.
Wordpress puede funcionar con la configuración estándar de PHP y una configuración sencilla de Nginx. Se utilizará el puerto 8014
―como ejemplo hipotético― para la instancia de PHP-FPM. Se utilizará un usuario sin privilegios denominado nombreyapellido
―como ejemplo― y su directorio de inicio correspondiente para la configuración del anfitrión virtual. El sitio Web con Wordpress se accederá desde el navegador Web como https://nombreyapellido.net
o bien https://www.nombreyapellido.net
―como ejemplo.
Es indispensable que el nombre de anfitrión utilizado ―en el ejemplo de este documento será https://nombreyapellido.net
o https://www.nombreyapellido.net
― esté resuelto en la zona del dominio correspondiente en un servidor DNS ― si necesita que el sitio Web esté disponible desde cualquier ubicación― o bien al menos en el archivo /etc/hosts
― que sólo estará disponible desde el mismo sistema― ya que de otro modo será imposible acceder al instalador desde el navegador Web.
Acceda al sistema como usuario root
.
Ejecute lo siguiente para instalar todo el software requerido para los procedimientos descritos en este documento:
dnf -y install wget2 nginx php-bcmath php-dba php-enchant php-fpm php-gd php-gmp php-intl php-json php-mbstring php-mysqlnd php-opcache php-pdo php-pdo-dblib php-process php-pspell php-soap php-sodium php-tidy php-xml php-xmlrpc
Si aún le falta hacerlo, active e inicie los servicios nginx
y php-fpm
:
systemctl enable --now php-fpm
systemctl enable --now nginx
Genere el usuario nombreyapellido
:
useradd -c "Nombre y Apellido" nombreyapellido
passwd nombreyapellido
Genere el directorio /home/nombreyapellido/public_html
y otros directorios que serán de utilidad para el anfitrión virtual:
mkdir -p \
/home/nombreyapellido/{public_html,private,uploads,tmp,.config,.local,.ssh}
Asigne pertenencia a estos directorios para el usuario y grupo nombreyapellido
:
chown nombreyapellido:nombreyapellido \
/home/nombreyapellido/{public_html,private,uploads,tmp,.config,.local,.ssh}
Cambie los contexto de SELinux para /home/nombreyapellido/tmp
y sus subsecuente contenido a httpd_sys_rw_content_t
:
semanage fcontext -a -t httpd_sys_rw_content_t "/home/nombreyapellido/tmp"
semanage fcontext -a -t httpd_sys_rw_content_t "/home/nombreyapellido/tmp(/.*)?"
Haga lo mismo para la eventual existencia de /home/nombreyapellido/public_html/wp-content
:
semanage fcontext -a -t httpd_sys_rw_content_t "/home/nombreyapellido/public_html/wp-content"
semanage fcontext -a -t httpd_sys_rw_content_t "/home/nombreyapellido/public_html/wp-content(/.*)?"
Cambie los permisos de /home/nombreyapellido
a fin de permitir que Nginx pueda acceder hacia el directorio public_html
y el resto de los directorios creados:
chmod 755 /home/nombreyapellido
Restaure los contextos de SELinux para todo el contenido de /home/nombreyapellido
:
restorecon -Rv /home/nombreyapellido
Si además tiene configurado OpenSSH para sólo permitir acceso de usuarios con jaula a través de SFTP, cambie la pertenencia del directorio /home/nombreyapellido
al usuario root
, cambie el intérprete de mandatos del usuario nombreyapellido
a /usr/sbin/nologin
y añada al usuario nombreyapellido
al grupo sftpusers
.
chown root:root /home/nombreyapellido
usermod -s /usr/sbin/nologin -G sftpusers nombreyapellido
La base de datos para el ejemplo de este documento se denominará wpnombreyapellido
. Para las credenciales de acceso de esta base de datos se utilizará el usuario wpnombreyapellido
con la contraseña Us3Un4Bu3n4C0ntr4s3ñ4
.
Acceda como root
al intérprete de MySQL o MariaDB:
mysql -uroot -p
Proceda a crear una nueva base de datos con un nombre que pueda ser asociado al usuario. Mientras menos predecible sea el nombre de la base de datos, mejor.
create database dbnombreyapellido;
Conceda permisos de acceso a esta nueva base de datos a un usuario con contraseña:
grant all on dbnombreyapellido.* to wpnombreyapellido@localhost identified by 'Us3Un4Bu3n4C0ntr4s3ñ4';
Refresque los privilegios y salga de el intérprete de MySQL o MariaDB:
flush privileges;
exit;
Hay tres archivos que se recomienda crear. Se asume que ha leído, estudiado y practicado los procedimientos del documentos titulado Configuración de Nginx, disponible en la sección de manuales de AlcanceLibre.org para entender el objetivos de éstos.
Genere o edite un archivo denominado /etc/nginx/default.d/common-configs.conf
:
vim /etc/nginx/default.d/common-configs.conf
Añada o valide esté presente el siguiente contenido:
# Ocultar la versión de Nginx.
server_tokens off;
# Denegar el acceso a cualquier archivo .ht* o .git*, aunque no
# los use Nginx.
location ~/\.(ht|git) {
deny all;
}
# Establecer el tipo mime predeterminado para el directorio
# /.well-known
location '/.well-known' {
default_type "text/plain";
}
# Indicar a los servidores cache que este tipo de contenidos
# expiran a los 14 días
location ~* \.(js|css|png|jpg|jpeg|gif|swf|xml|txt)$ {
expires 14d;
}
# Si olvidamos poner un archivo favicon.ico, indicar a Nginx que
# omita registrar la actividad relacionada con este archivo y
# además indicar a los servidores cache que este archivo expira
# tras año.
location = /favicon.ico {
log_not_found off;
access_log off;
expires 1y;
}
# Si olvidamos poner un archivo robots.txt, indicar a Nginx que
# omita registrar la actividad relacionada con este archivo.
location = /robots.txt {
log_not_found off;
access_log off;
}
Genere o edite un archivo denominado /etc/nginx/default.d/gzip.conf
:
vim /etc/nginx/default.d/gzip.conf
Añada o valide esté presente el siguiente contenido:
# Activar el soporte de compresión gzip
gzip on;
# Activar para archivos que tengan o no compresión gzip
gzip_vary on;
# Comprimir sólo archivos de al menos 1024 bytes. Con archivos
# menores hay pocos pocos beneficios y elevaría innecesariamente
# el uso del CPU y memoria.
gzip_min_length 1024;
# Activar compresión para conexiones a través de proxy
gzip_proxied expired no-cache no-store private auth;
# Tipos específicos de archivos a comprimir
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml;
# Desactivar para MS Internet Explorer
gzip_disable "MSIE [1-6]\.";
Genere o edite un archivo denominado /etc/nginx/default.d/headers.conf
:
vim /etc/nginx/default.d/headers.conf
Añada o valide esté presente el siguiente contenido:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy: "default-src 'self' https://code.jquery.com https://cdnjs.cloudflare.com https://analytics.google.com https://fonts.gstatic.com";
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
Nginx requiere la siguiente configuración para location /
en el anfitrión virtual:
# Explicación de la inclusión de los siguientes tres archivos en
# https://www.alcancelibre.org/manuales/configuracion-de-nginx
include /etc/nginx/default.d/common-configs.conf;
include /etc/nginx/default.d/gzip.conf;
include /etc/nginx/default.d/headers.conf;
location / {
index index.html index.htm index.php;
# Esto es indispensable para el soporte de `URLs bonitos`
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:8014;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_VALUE "memory_limit=128M \n upload_max_filesize=128M \n post_max_size=128M;
}
De modo que la configuración del anfitrión virtual sea similar a lo siguiente:
# Este es un ejemplo de configuración de Nginx para Wordpress
server {
listen 443 http2 ssl;
server_name nombreyapellido.net www.nombreyapellido.net;
root /home/nombreyapellido/public_html;
access_log /var/log/nginx/nombreyapellido-access_log main;
error_log /var/log/nginx/nombreyapellido-error_log notice;
ssl_certificate /ruta/del/archivo/del/certificado.crt;
ssl_certificate_key /ruta/del/archivo/de/firma.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Se recomienda que client_max_body_size tenga el mismo valor que
# memory_limit, post_max_size y upload_max_filesize en la instancia
# de PHP-FPM.
client_max_body_size 128M;
# Explicación de la inclusión de los siguientes tres archivos en
# https://www.alcancelibre.org/manuales/configuracion-de-nginx
include /etc/nginx/default.d/common-configs.conf;
include /etc/nginx/default.d/gzip.conf;
include /etc/nginx/default.d/headers.conf;
location / {
index index.html index.htm index.php;
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass 127.0.0.1:8014;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Se recomienda que memory_limit, post_max_size y
# y upload_max_filesize tengan el mismo valor que
# client_max_body_size.
fastcgi_param PHP_VALUE "memory_limit=128M \n upload_max_filesize=128M \n post_max_size=128M";
}
}
Genere un archivo de configuración para el anfitrión virtual dentro de /etc/nginx/conf.d/
o bien modifique la configuración de un anfitrión virtual existente:
vim /etc/nginx/conf.d/nombreyapellido.conf
Valide que la configuración realizada sea válida:
nginx -t
Recargue servicio nginx
para aplicar los cambios:
systemctl reload nginx
Asumiendo que puede utilizar el puerto 8014
para la instancia de PHP-FPM, ejecute lo siguiente para autorizar en SELinux que PHP-FPM pueda utilizar el puerto 8014
:
semanage port -a -t http_port_t -p tcp 8014
Genere un nuevo archivo de configuración dentro de /etc/php-fpm.d/
denominado nombreyapellido.conf
:
vim /etc/php-fpm.d/nombreyapellido.conf
Añada la siguiente configuración recomendada para php-fpm. Por favor, modifique a su conveniencia.
[nombreyapellido]
user = nombreyapellido
group = nombreyapellido
listen = 127.0.0.1:8014
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 9999
pm.start_servers = 1
pm.min_spare_servers = 1
pm.max_spare_servers = 5
php_admin_value[upload_tmp_dir] = /home/nombreyapellido/tmp
php_admin_value[session.save_path] = /home/nombreyapellido/tmp
; Ocultar la versión de PHP
php_value[expose_php] = Off
; Defina la zona horaria que le corresponda.
php_value[date.timezone] = America/Mexico_City
php_value[file_uploads] = On
; Recomendaciones para mejor funcionamiento.
php_value[max_execution_time] = 7200
php_value[request_terminate_timeout] = 300
php_value[max_input_time] = 180
php_value[max_input_vars] = 2000
php_value[output_buffering] = off
Reinicie el servicio php-fpm
para aplicar los cambios:
systemctl restart php-fpm
Acceda como usuario regular:
su -l nombreyapellido -s /bin/bash
Descargue el paquete *.tar.gz
de la versión más reciente de Wordpress al Español desde es.wordpress.org/download/releases/ dentro de ~/uploads/
:
wget2 \
-P ~/uploads \
https://es.wordpress.org/wordpress-6.5.5-es_ES.tar.gz
Descomprima el archivo dentro de ~/uploads
:
tar zxvf \
~/uploads/wordpress-6.5.5-es_ES.tar.gz \
-C ~/uploads
Mueva contenido de ~/uploads/wordpress
directamente dentro de ~/home/nombreyapellido~/public_html
:
mv ~/uploads/wordpress/* ~/public_html/
Restaure los contextos de SELinux:
restorecon -Rv ~/public_html/
Copie el archivo de ejemplo wp-config-sample.php
como wp-config.php
:
cp -a ~/public_html/wp-config-sample.php ~/public_html/wp-config.php
Acceda hacia https://api.wordpress.org/secret-key/1.1/salt/ para obtener un juego único y aleatorio de firma digitales. Copie dichos datos.
Edite el archivo /home/nombreyapellido/public_html/wp-config.php
vim ~/public_html/wp-config.php
Configure los siguientes parámetros de wp-config.php
<?php
// Defina las credenciales de acceso a la base de datos
define( 'DB_NAME', 'dbnombreyapellido' );
define( 'DB_USER', 'wpnombreyapellido' );
define( 'DB_PASSWORD', 'Us3Un4Bu3n4C0ntr4s3ñ4' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8' );
define( 'DB_COLLATE', '' );
// Ejemplo de las firmas digitales. Puede generar firmas digitales nuevas
// y aleatorias desde https://api.wordpress.org/secret-key/1.1/salt/
define('AUTH_KEY', '{Kn,1?Mmr;cNWU,}>zW_L-4~t4=B8bd*z_)s|+$=a*fd48!ftwfHI/p..2hh oAB');
define('SECURE_AUTH_KEY', 'aE Z|:ZL8dBG13yq)QGw-`YImYqTy!-#cHo?wkO77A l}q+Ve#z@HR=niQ-|_L K');
define('LOGGED_IN_KEY', 'g4(}U a-im%# gt WG+M[tM[qqmcn#c9l5y:}NfBIFP%)k-wy>If6< v :sPPcBM');
define('NONCE_KEY', 'i8CfLZx9hQtEEi_U]J{o4?KRFe!=_E+xGh!UIb1B:w/wPU%RV<ayGdTe34{37:j9');
define('AUTH_SALT', '+p9%3`w{7I?SM hw~MS_Z 69r_SyG^nVyX+nV>#?O4* bl)=ud$+/wLC8lZ|s<NK');
define('SECURE_AUTH_SALT', ']:9Ny,9fXiB9B%.WS-)>TI{Vg2|+NO{A@melLAS>&gUmQD#.;#OV]+{9<1b^Bb,_');
define('LOGGED_IN_SALT', 'c<xyI8E/VWXSQ Z0k/@>F=>(H<k?]jI[pE+g}-_ ~kHm`r)G|Cvmcvul~t$+=!O6');
define('NONCE_SALT', '@Wu[e${&y?oD%{gFZsN&2vc1|g^oh*e]#s5+I-6kB^^-`+Dq4!_,I:1*k:%O5.-)');
# Defina un prefijo para las tablas de la base de datos. Jamás use `wp_`,
# puesto que es el prefijo que utilizarán la mayoría de los programas
# diseñador para vulnerar Wordpress
$table_prefix = '4lg0_';
define( 'WP_DEBUG', false );
/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
Guarde los cambios y salga del editor de texto.
Salga de la cuenta de usuario regular.
exit
Acceda hacia https://nombreyapellido.net
con cualquier navegado Web estándar para completar la instalación.
La instalación de Wordpress consiste en un único clic con el ratón y sólo requiere definir el título del sitio Web, un usuario administrador, contraseña, su cuenta de correo electrónico y si se desea permitir a los motores de búsqueda indexar los contenidos del sitio.
Sugerencia: cambie el nombre del acceso a wp-admin
a otro que sea menos predecible para mejorar la seguridad.