WordPress alimenta el 43% de internet. Eso lo convierte en el objetivo número uno de los hackers.
En un VPS tienes control total sobre la seguridad, pero también toda la responsabilidad. Un WordPress mal configurado es una puerta abierta.
Esta guía cubre todas las capas de seguridad: desde el servidor hasta la aplicación.
Por qué WordPress es tan atacado
Las estadísticas
| Dato | Cifra |
|---|---|
| Sitios WordPress | 43% de internet |
| Ataques diarios | 90.000+ intentos por sitio |
| Vulnerabilidades plugins | 98% de los hackeos |
| Contraseñas débiles | 8% de los hackeos |
Vectores de ataque comunes
- Plugins vulnerables: La causa principal
- Fuerza bruta: Intentos de login masivos
- xmlrpc.php: API antigua muy explotada
- Temas nulled: Con malware incluido
- Versiones desactualizadas: Vulnerabilidades conocidas
Capas de seguridad
La seguridad efectiva tiene múltiples capas:
Capa 1: Servidor (firewall, SSH, actualizaciones)
Capa 2: Web server (Nginx/Apache hardening)
Capa 3: PHP (configuración segura)
Capa 4: WordPress (core, plugins, temas)
Capa 5: Usuario (contraseñas, 2FA)
Capa 1: Seguridad del servidor
Firewall obligatorio
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Guía completa: Firewall en VPS
Fail2ban para WordPress
sudo apt install fail2ban -y
Crear filtro WordPress:
sudo nano /etc/fail2ban/filter.d/wordpress-login.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
^<HOST> .* "POST /xmlrpc.php
ignoreregex =
Crear jail:
sudo nano /etc/fail2ban/jail.local
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 300
bantime = 3600
sudo systemctl restart fail2ban
Guía completa: Fail2ban en VPS
Actualizaciones automáticas
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure unattended-upgrades
Capa 2: Configuración web server
Nginx - Bloquear archivos sensibles
# Bloquear acceso a archivos sensibles
location ~ /\.(htaccess|htpasswd|ini|log|sh|sql)$ {
deny all;
}
# Bloquear wp-config.php
location ~* wp-config.php {
deny all;
}
# Bloquear xmlrpc.php (si no lo usas)
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}
# Bloquear acceso directo a PHP en uploads
location ~* /wp-content/uploads/.*\.php$ {
deny all;
}
# Bloquear acceso a wp-includes
location ~* /wp-includes/.*\.php$ {
deny all;
}
# Bloquear readme y license
location ~* (readme|license)\.(html|txt)$ {
deny all;
}
Nginx - Limitar wp-admin por IP
location /wp-admin {
allow 203.0.113.5; # Tu IP
allow 10.0.0.0/24; # Red VPN
deny all;
location ~ \.php$ {
# config PHP-FPM
}
}
location = /wp-login.php {
allow 203.0.113.5;
allow 10.0.0.0/24;
deny all;
# config PHP-FPM
}
Nginx - Headers de seguridad
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
Apache - .htaccess seguro
# Bloquear xmlrpc
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
</Files>
# Proteger wp-config
<Files wp-config.php>
Order Allow,Deny
Deny from all
</Files>
# Bloquear acceso a includes
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
# Deshabilitar listado de directorios
Options -Indexes
# Headers de seguridad
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-Frame-Options "SAMEORIGIN"
Header set X-XSS-Protection "1; mode=block"
</IfModule>
Capa 3: PHP seguro
php.ini hardening
; Deshabilitar funciones peligrosas
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source
; Ocultar versión PHP
expose_php = Off
; Limitar recursos
max_execution_time = 30
max_input_time = 60
memory_limit = 256M
post_max_size = 64M
upload_max_filesize = 64M
; Sesiones seguras
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1
; Otros
allow_url_fopen = Off
allow_url_include = Off
PHP-FPM pool seguro
; /etc/php/8.3/fpm/pool.d/wordpress.conf
[wordpress]
user = www-data
group = www-data
listen = /run/php/php8.3-fpm-wordpress.sock
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
; Seguridad
php_admin_value[disable_functions] = exec,passthru,shell_exec,system
php_admin_flag[allow_url_fopen] = off
Capa 4: WordPress hardening
wp-config.php seguro
<?php
// Claves de seguridad únicas (genera en https://api.wordpress.org/secret-key/1.1/salt/)
define('AUTH_KEY', 'tu-clave-unica-aqui');
define('SECURE_AUTH_KEY', 'tu-clave-unica-aqui');
define('LOGGED_IN_KEY', 'tu-clave-unica-aqui');
define('NONCE_KEY', 'tu-clave-unica-aqui');
define('AUTH_SALT', 'tu-clave-unica-aqui');
define('SECURE_AUTH_SALT', 'tu-clave-unica-aqui');
define('LOGGED_IN_SALT', 'tu-clave-unica-aqui');
define('NONCE_SALT', 'tu-clave-unica-aqui');
// Forzar SSL en admin
define('FORCE_SSL_ADMIN', true);
// Deshabilitar editor de archivos
define('DISALLOW_FILE_EDIT', true);
// Limitar revisiones
define('WP_POST_REVISIONS', 5);
// Deshabilitar actualizaciones automáticas de plugins/temas (gestionar manualmente)
define('AUTOMATIC_UPDATER_DISABLED', false);
define('WP_AUTO_UPDATE_CORE', 'minor');
// Tabla prefix personalizado (no wp_)
$table_prefix = 'wp7x9k_';
// Debug solo en desarrollo
define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);
define('WP_DEBUG_DISPLAY', false);
Permisos de archivos
# Directorios: 755
find /var/www/wordpress -type d -exec chmod 755 {} \;
# Archivos: 644
find /var/www/wordpress -type f -exec chmod 644 {} \;
# wp-config.php más restrictivo
chmod 600 /var/www/wordpress/wp-config.php
# Propietario
chown -R www-data:www-data /var/www/wordpress
Deshabilitar xmlrpc.php
Si no usas la app móvil de WordPress ni Jetpack:
Opción 1: Nginx (recomendada)
location = /xmlrpc.php {
deny all;
}
Opción 2: Plugin Instala “Disable XML-RPC-API”
Opción 3: functions.php
add_filter('xmlrpc_enabled', '__return_false');
Ocultar versión WordPress
// functions.php
remove_action('wp_head', 'wp_generator');
function remove_version_strings($src) {
if (strpos($src, 'ver=')) {
$src = remove_query_arg('ver', $src);
}
return $src;
}
add_filter('style_loader_src', 'remove_version_strings', 9999);
add_filter('script_loader_src', 'remove_version_strings', 9999);
Cambiar URL de login
Con plugin “WPS Hide Login” o manualmente:
// functions.php (básico, mejor usar plugin)
function custom_login_url() {
return home_url('mi-acceso-secreto');
}
add_filter('login_url', 'custom_login_url');
Limitar intentos de login
Plugin recomendado: Limit Login Attempts Reloaded
O con código:
function check_attempted_login($user, $username, $password) {
if (get_transient('attempted_login')) {
$data = get_transient('attempted_login');
if ($data['tried'] >= 3) {
$until = get_option('_transient_timeout_attempted_login');
$time = time_to_go($until);
return new WP_Error('too_many_tried', sprintf(__('ERROR: Demasiados intentos. Espera %s.'), $time));
}
}
return $user;
}
add_filter('authenticate', 'check_attempted_login', 30, 3);
Capa 5: Usuarios y accesos
Contraseñas fuertes
- Mínimo 16 caracteres
- Mayúsculas, minúsculas, números, símbolos
- Única por sitio
- Usar gestor de contraseñas
2FA obligatorio
Plugins recomendados:
- Two Factor Authentication (gratuito)
- Wordfence (incluye 2FA)
- Google Authenticator
No usar “admin” como usuario
-- Cambiar nombre de usuario admin
UPDATE wp_users SET user_login = 'nuevo_usuario' WHERE user_login = 'admin';
UPDATE wp_users SET user_nicename = 'nuevo_usuario' WHERE user_nicename = 'admin';
Roles y permisos mínimos
| Rol | Para quién |
|---|---|
| Administrator | Solo tú |
| Editor | Gestores de contenido |
| Author | Escritores |
| Contributor | Colaboradores externos |
| Subscriber | Usuarios registrados |
Nunca des admin a quien no lo necesite.
Plugins de seguridad
Wordfence (recomendado)
- Firewall aplicación
- Escaneo malware
- 2FA
- Bloqueo de IPs
- Alertas en tiempo real
Configuración recomendada:
- Firewall: Extended Protection
- Scan: High Sensitivity
- 2FA: Todos los admins
- Login Security: Enable
Sucuri Security
- Firewall WAF (de pago)
- Escaneo malware
- Hardening automático
- CDN incluido
iThemes Security
- Hardening automático
- Detección de cambios
- 2FA
- Backups de base de datos
Comparativa
| Feature | Wordfence | Sucuri | iThemes |
|---|---|---|---|
| Firewall app | ✓ Gratis | Pago | ✓ |
| WAF cloud | Pago | ✓ | ✗ |
| Malware scan | ✓ | ✓ | ✓ |
| 2FA | ✓ | ✗ | ✓ |
| Precio | Free/Premium | Free/Premium | Free/Pro |
Recomendación: Wordfence free para empezar.
Backups: tu última defensa
Regla 3-2-1
- 3 copias de tus datos
- 2 tipos de almacenamiento diferentes
- 1 copia offsite (fuera del servidor)
Plugins de backup
UpdraftPlus:
- Backup automático
- Restauración fácil
- Cloud storage (Dropbox, Google Drive, S3)
Configuración recomendada:
- Archivos: Diario
- Base de datos: Diario
- Retención: 14 días
- Destino: Cloud externo
Backup desde servidor
#!/bin/bash
# /root/scripts/backup-wordpress.sh
FECHA=$(date +%Y%m%d)
WP_DIR="/var/www/wordpress"
BACKUP_DIR="/backups/wordpress"
DB_NAME="wordpress"
DB_USER="wp_user"
DB_PASS="password"
# Backup base de datos
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/db-$FECHA.sql.gz
# Backup archivos
tar -czf $BACKUP_DIR/files-$FECHA.tar.gz $WP_DIR
# Eliminar backups antiguos (30 días)
find $BACKUP_DIR -mtime +30 -delete
# Sincronizar a cloud (ejemplo con rclone)
rclone sync $BACKUP_DIR remote:backups/wordpress
Guía completa: Backups en VPS
Checklist de seguridad WordPress
Crítico (hacer hoy)
| Tarea | ✓ |
|---|---|
| WordPress actualizado | ☐ |
| Plugins actualizados | ☐ |
| Tema actualizado | ☐ |
| Contraseñas fuertes | ☐ |
| Backup funcionando | ☐ |
| SSL activo | ☐ |
Importante (esta semana)
| Tarea | ✓ |
|---|---|
| Firewall servidor activo | ☐ |
| Fail2ban configurado | ☐ |
| xmlrpc.php bloqueado | ☐ |
| Plugin seguridad instalado | ☐ |
| 2FA habilitado | ☐ |
| Permisos archivos correctos | ☐ |
Recomendado (este mes)
| Tarea | ✓ |
|---|---|
| Limitar acceso wp-admin por IP | ☐ |
| Cambiar URL de login | ☐ |
| Headers de seguridad | ☐ |
| Auditoría de plugins | ☐ |
| Eliminar temas/plugins sin usar | ☐ |
| wp-config.php hardening | ☐ |
Qué hacer si te hackean
1. No entres en pánico
2. Aísla el sitio
# Poner en mantenimiento
echo "<?php header('HTTP/1.1 503 Service Unavailable'); ?>" > /var/www/wordpress/index.php
3. Identifica el problema
# Buscar archivos modificados recientemente
find /var/www/wordpress -type f -mtime -2
# Buscar código sospechoso
grep -r "eval(" /var/www/wordpress
grep -r "base64_decode" /var/www/wordpress
4. Restaura desde backup limpio
5. Cambia todas las contraseñas
- WordPress admin
- Base de datos
- FTP/SFTP
- Hosting/VPS
6. Actualiza todo
7. Escanea con Wordfence/Sucuri
8. Refuerza seguridad
Preguntas frecuentes
¿Necesito plugin de seguridad si tengo firewall en servidor?
Sí. El firewall del servidor protege a nivel red. Los plugins protegen a nivel aplicación. Son complementarios.
¿Wordfence ralentiza mi sitio?
Puede añadir algo de carga. Usa caché agresivo y considera el firewall cloud de Sucuri para alto tráfico.
¿Debo pagar por seguridad premium?
Para sitios pequeños, las versiones gratuitas son suficientes. Para e-commerce o sitios críticos, considera premium.
¿Con qué frecuencia debo actualizar?
Actualizaciones de seguridad: inmediatamente. Otras: semanalmente, probando primero en staging.
Nuestra recomendación
Mínimo para cualquier WordPress:
- Actualizaciones al día
- Wordfence free instalado
- Backups diarios
- 2FA para admins
- xmlrpc bloqueado
Para e-commerce/sitios críticos: Añade WAF cloud (Sucuri/Cloudflare Pro) y monitorización 24/7.
¿No tienes tiempo? La administración gestionada incluye seguridad WordPress profesional.
Conclusión
La seguridad de WordPress en un VPS requiere atención en múltiples capas. No basta con un plugin; necesitas servidor seguro, configuración correcta y buenos hábitos.
Implementa este checklist progresivamente. Empieza por lo crítico hoy y completa el resto esta semana.
¿Quieres WordPress seguro sin complicaciones? Explora el hosting WordPress de Avantys con seguridad incluida.
Guías relacionadas
- Firewall en VPS: UFW e iptables
- Fail2ban: proteger tu VPS
- SSL con Let’s Encrypt
- Backups en VPS: guía completa
¿Quieres la guía completa con todos los casos de uso?
¿Quieres que lo hagamos por ti?
En Avantys gestionamos tu web, hosting y crecimiento digital de punta a punta. Tú a lo importante.