WordPress Multisite permite gestionar varios sitios desde una sola instalación: todos comparten el núcleo, los plugins, los temas y la base de usuarios, pero cada sitio tiene su propio contenido, ajustes y administradores. Es útil para redes de marcas, sitios por idioma o departamentos de una misma organización. En este tutorial convertirás un WordPress existente en una red Multisite en Ubuntu 24.04 con Nginx y PHP-FPM, en modo subdominio o subdirectorio, le añadirás HTTPS y gestionarás los sitios con WP-CLI.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath, con al menos 2 GB de RAM.
  • Un usuario no root con privilegios sudo.
  • WordPress ya instalado y funcionando en /var/www/wordpress con Nginx, PHP 8.3-FPM y MySQL o MariaDB. En los ejemplos se usa example.com como dominio: sustitúyelo por el tuyo.
  • Acceso al panel DNS de tu dominio.

Subdominios o subdirectorios

Antes de empezar decide el tipo de red, porque cambiarlo después es laborioso:

TipoURL de los sitiosDNSCertificado TLS
Subdominiostienda.example.comRegistro comodín *.example.comCertificado comodín (validación DNS-01)
Subdirectoriosexample.com/tiendaNada adicionalCertificado normal

Ten en cuenta dos detalles:

  • En una red de subdirectorios, las entradas del sitio principal pasan a tener el prefijo /blog/ en sus enlaces permanentes para no chocar con los nombres de los sitios. Si tu sitio principal ya tiene tráfico y enlaces indexados, los subdominios evitan ese cambio.
  • En ambos casos puedes asignar después un dominio propio a cualquier sitio de la red (por ejemplo otramarca.com), como se explica en el paso 7.

Paso 1: Hacer una copia de seguridad

La conversión modifica wp-config.php y crea tablas nuevas en la base de datos. Haz una copia de ambos antes de tocar nada. Sustituye wordpress y wpuser por el nombre de tu base de datos y tu usuario:

mkdir -p ~/backups
mysqldump -u wpuser -p --single-transaction wordpress > ~/backups/wordpress-$(date +%F).sql
sudo tar -czf ~/backups/wordpress-files-$(date +%F).tar.gz -C /var/www wordpress

Comprueba que los archivos existen y no están vacíos:

ls -lh ~/backups/
-rw-rw-r-- 1 your_user your_user  48M Sep 25 10:02 wordpress-2026-09-25.sql
-rw-r--r-- 1 root      root      212M Sep 25 10:03 wordpress-files-2026-09-25.tar.gz

Paso 2: Instalar WP-CLI

WP-CLI es la herramienta de línea de comandos de WordPress. La usarás para convertir la instalación y gestionar la red. Descarga el archivo phar oficial y compruébalo:

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
php wp-cli.phar --info

Si muestra la versión de PHP y de WP-CLI, instálalo en el PATH:

chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp

Ejecutarás WP-CLI como el usuario del servidor web (www-data) para que los archivos que cree tengan el propietario correcto. Comprueba que ve tu instalación:

sudo -u www-data wp --path=/var/www/wordpress core version
6.8.2

Paso 3: Preparar el DNS

Si vas a usar subdirectorios, no necesitas cambios en el DNS y puedes pasar al paso 4.

Si vas a usar subdominios, crea en tu proveedor DNS un registro comodín que apunte a la IP del servidor, además del registro del dominio principal:

example.com     A    your_server_ip
*.example.com   A    your_server_ip

Cuando se haya propagado, cualquier subdominio debe resolver a tu servidor:

dig +short cualquiercosa.example.com
203.0.113.10

Paso 4: Convertir la instalación en una red

WordPress recomienda desactivar los plugins antes de crear la red. Guarda la lista de plugins activos para reactivarlos después:

sudo -u www-data wp --path=/var/www/wordpress plugin list --status=active --field=name | tee ~/plugins-activos.txt
sudo -u www-data wp --path=/var/www/wordpress plugin deactivate --all

Convierte la instalación. Para una red de subdominios añade --subdomains; para subdirectorios omítelo:

sudo -u www-data wp --path=/var/www/wordpress core multisite-convert --title="Mi red" --subdomains
Set up multisite database tables.
Added multisite constants to wp-config.php.
Success: Network installed. Don't forget to set up rewrite rules (and a .htaccess file, if using Apache).

El comando crea las tablas de red (wp_blogs, wp_site, wp_sitemeta y otras) y añade las constantes a wp-config.php. Ábrelo para comprobarlo:

sudo nano /var/www/wordpress/wp-config.php

Encima de la línea /* That's all, stop editing! */ debe haber un bloque como este (con SUBDOMAIN_INSTALL a false si elegiste subdirectorios):

define( 'WP_ALLOW_MULTISITE', true );
define( 'MULTISITE', true );
define( 'SUBDOMAIN_INSTALL', true );
$base = '/';
define( 'DOMAIN_CURRENT_SITE', 'example.com' );
define( 'PATH_CURRENT_SITE', '/' );
define( 'SITE_ID_CURRENT_SITE', 1 );
define( 'BLOG_ID_CURRENT_SITE', 1 );

Si wp-config.php no tenía permisos de escritura para www-data, WP-CLI mostrará el bloque en pantalla en lugar de escribirlo: cópialo tú en ese lugar. DOMAIN_CURRENT_SITE debe coincidir exactamente con el dominio que usa el sitio, con o sin www.

Reactiva los plugins en el sitio principal:

xargs -r sudo -u www-data wp --path=/var/www/wordpress plugin activate < ~/plugins-activos.txt

Paso 5: Configurar Nginx

Nginx no lee archivos .htaccess, así que las reglas de reescritura de la red van en el bloque de servidor. Abre el archivo de tu sitio:

sudo nano /etc/nginx/sites-available/wordpress

Red de subdominios

En una red de subdominios basta con que el bloque acepte cualquier subdominio: WordPress decide qué sitio servir según el host. Reemplaza el contenido por:

server {
    listen 80;
    listen [::]:80;
    server_name example.com *.example.com;

    root /var/www/wordpress;
    index index.php;
    client_max_body_size 64m;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

Red de subdirectorios

En una red de subdirectorios, rutas como /tienda/wp-admin/ o /tienda/wp-includes/... no existen en disco y hay que reescribirlas hacia la instalación única. Reemplaza el contenido por:

server {
    listen 80;
    listen [::]:80;
    server_name example.com;

    root /var/www/wordpress;
    index index.php;
    client_max_body_size 64m;

    if (!-e $request_filename) {
        rewrite /wp-admin$ $scheme://$host$request_uri/ permanent;
        rewrite ^(/[^/]+)?(/wp-.*) $2 last;
        rewrite ^(/[^/]+)?(/.*\.php) $2 last;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

En ambos casos, comprueba la sintaxis y recarga Nginx:

sudo nginx -t
sudo systemctl reload nginx

Accede a http://example.com/wp-admin/network/ con tu usuario administrador. Deberías ver el Escritorio de la red; tu usuario es ahora superadministrador.

Paso 6: Añadir HTTPS

Subdirectorios: certificado normal

Con subdirectorios todos los sitios comparten el mismo dominio, así que basta con un certificado normal obtenido con el plugin de Nginx de Certbot:

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com

Subdominios: certificado comodín

Let's Encrypt solo emite certificados comodín (*.example.com) con validación DNS-01: Certbot crea un registro TXT temporal en tu DNS mediante la API del proveedor. Este ejemplo usa Cloudflare; hay plugins equivalentes para otros proveedores (apt search python3-certbot-dns).

Instala Certbot y el plugin de Cloudflare:

sudo apt install -y certbot python3-certbot-dns-cloudflare

Crea en Cloudflare un token de API con permiso Zone > DNS > Edit sobre tu zona y guárdalo en un archivo que solo pueda leer root:

sudo install -d -m 700 /root/.secrets
sudo nano /root/.secrets/cloudflare.ini
dns_cloudflare_api_token = your_cloudflare_api_token
sudo chmod 600 /root/.secrets/cloudflare.ini

Solicita el certificado para el dominio y el comodín:

sudo certbot certonly --dns-cloudflare \
  --dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
  -d example.com -d '*.example.com'
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem

Como certonly no toca Nginx, edita tú el bloque de servidor. Cambia el bloque de subdominios del paso 5 por estos dos: uno que redirige HTTP a HTTPS y otro que sirve HTTPS:

sudo nano /etc/nginx/sites-available/wordpress
server {
    listen 80;
    listen [::]:80;
    server_name example.com *.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name example.com *.example.com;

    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    root /var/www/wordpress;
    index index.php;
    client_max_body_size 64m;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

Recarga Nginx y comprueba que la renovación automática funciona. El temporizador de Certbot renueva también los certificados DNS-01, pero Nginx necesita recargarse para usar el certificado nuevo, así que añade un deploy hook:

sudo nginx -t && sudo systemctl reload nginx
printf '#!/bin/sh\nsystemctl reload nginx\n' | sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
sudo certbot renew --dry-run

Actualizar las URL de la red a HTTPS

Si la red se creó con http://, actualiza las URL guardadas en la base de datos de todos los sitios. Revisa primero los cambios con --dry-run:

sudo -u www-data wp --path=/var/www/wordpress search-replace 'http://example.com' 'https://example.com' --network --skip-columns=guid --dry-run

Si el recuento es razonable, ejecútalo sin --dry-run. En una red de subdominios repite el comando para cada subdominio existente (http://tienda.example.com), o usa una expresión regular con --regex si tienes muchos.

Paso 7: Crear sitios y usuarios

Crea un sitio nuevo. En una red de subdominios, --slug=tienda crea tienda.example.com; en una de subdirectorios, example.com/tienda/:

sudo -u www-data wp --path=/var/www/wordpress site create --slug=tienda --title="Tienda" [email protected]
Success: Site 2 created: https://tienda.example.com/

Lista los sitios de la red:

sudo -u www-data wp --path=/var/www/wordpress site list --fields=blog_id,url
+---------+-----------------------------+
| blog_id | url                         |
+---------+-----------------------------+
| 1       | https://example.com/        |
| 2       | https://tienda.example.com/ |
+---------+-----------------------------+

Los usuarios son comunes a toda la red, pero los roles son por sitio. Crea un editor solo para la tienda con --url, que indica a WP-CLI sobre qué sitio actuar:

sudo -u www-data wp --path=/var/www/wordpress user create maria [email protected] --role=editor --url=tienda.example.com

Para dar a un usuario existente acceso a otro sitio, o convertirlo en superadministrador de toda la red:

sudo -u www-data wp --path=/var/www/wordpress user set-role maria editor --url=example.com
sudo -u www-data wp --path=/var/www/wordpress super-admin add maria

Asignar un dominio propio a un sitio

WordPress permite que un sitio de la red use un dominio distinto sin plugins adicionales:

  1. Apunta el registro A de otramarca.com a la IP del servidor.
  2. Añade otramarca.com al server_name de Nginx (o crea un bloque aparte) y obtén su certificado con sudo certbot --nginx -d otramarca.com.
  3. En Escritorio de la red > Sitios, edita el sitio y cambia su Dirección del sitio (URL) a https://otramarca.com.

Paso 8: Gestionar plugins y temas en la red

En Multisite solo el superadministrador instala plugins y temas; los administradores de cada sitio solo pueden activar los que la red les permite.

Instala un plugin y actívalo en toda la red (queda activo en todos los sitios y no se puede desactivar desde un sitio individual):

sudo -u www-data wp --path=/var/www/wordpress plugin install two-factor --activate-network

Si prefieres que cada sitio decida, instálalo sin activarlo y actívalo solo donde haga falta:

sudo -u www-data wp --path=/var/www/wordpress plugin install woocommerce
sudo -u www-data wp --path=/var/www/wordpress plugin activate woocommerce --url=tienda.example.com

Los temas se habilitan para la red y luego cada sitio elige el suyo:

sudo -u www-data wp --path=/var/www/wordpress theme enable twentytwentyfive --network
sudo -u www-data wp --path=/var/www/wordpress theme activate twentytwentyfive --url=tienda.example.com

Los límites de subida se guardan como ajustes de red. Por ejemplo, para permitir archivos de hasta 10 MB (el valor va en KB):

sudo -u www-data wp --path=/var/www/wordpress network meta update 1 fileupload_maxk 10240

El límite efectivo también depende de upload_max_filesize y post_max_size de PHP y de client_max_body_size de Nginx.

Paso 9: Ejecutar WP-Cron desde el sistema

WP-Cron se dispara con las visitas y, en una red, cada sitio tiene su propia cola de tareas. Los sitios con poco tráfico pueden acumular tareas atrasadas (publicaciones programadas, correos). Es más fiable desactivarlo y lanzarlo desde cron del sistema para todos los sitios.

Añade esta línea a wp-config.php, encima de /* That's all, stop editing! */:

sudo nano /var/www/wordpress/wp-config.php
define( 'DISABLE_WP_CRON', true );

Crea una tarea de cron que recorra todos los sitios cada cinco minutos:

sudo nano /etc/cron.d/wordpress-multisite
*/5 * * * * www-data /usr/local/bin/wp --path=/var/www/wordpress site list --field=url | xargs -r -I{} /usr/local/bin/wp --path=/var/www/wordpress cron event run --due-now --quiet --url={}

Comprueba que el comando funciona ejecutándolo a mano para un sitio:

sudo -u www-data wp --path=/var/www/wordpress cron event run --due-now --url=tienda.example.com
Success: Executed a total of 3 cron events.

Solución de problemas

  • "Error establishing a database connection" tras la conversión: suele ser un DOMAIN_CURRENT_SITE que no coincide con el dominio de las tablas wp_site y wp_blogs (por ejemplo, www.example.com frente a example.com). Corrige la constante para que coincida.
  • Bucle de redirecciones al entrar en /wp-admin de un subsitio: en redes de subdirectorios falta el bloque if (!-e $request_filename) en Nginx. En redes de subdominios, comprueba que el subdominio resuelve y que server_name incluye *.example.com.
  • Imágenes rotas en los sitios nuevos: los archivos de cada sitio se guardan en wp-content/uploads/sites/<id>/. Comprueba que www-data puede escribir en wp-content/uploads.
  • La opción de subdirectorios aparece desactivada en el asistente web: WordPress la bloquea si el sitio tiene más de un mes, por el conflicto de enlaces descrito arriba. Con WP-CLI la conversión sí es posible, pero revisa después los enlaces permanentes del sitio principal.

Conclusión

Has convertido una instalación de WordPress en una red Multisite, has configurado Nginx para subdominios o subdirectorios, has añadido HTTPS (con certificado comodín si usas subdominios) y sabes crear sitios, asignar usuarios y controlar plugins y temas con WP-CLI. Como siguientes pasos, añade una caché de objetos con Redis compartida por toda la red, programa copias de seguridad de la base de datos y de wp-content/uploads/sites/, y revisa el endurecimiento de seguridad de WordPress, que en una red afecta a todos los sitios a la vez.