main content

Cómo crear un sitio web multisitio con Drupal para gestionar varias marcas

He visto el mismo patrón demasiadas veces. Un grupo empresarial con cinco marcas, cada una con su WordPress contratado por una agencia distinta, tres versiones de PHP distintas y un CMO que ya no sabe a quién pedirle un cambio de logo. Llega la pregunta: «¿podemos centralizarlo todo y reducir costes?». Y antes de responder, hay que sentarse y decidir qué tipo de multisitio se quiere realmente, porque el término significa cosas muy distintas según con quién hables.

Drupal lleva soportando arquitecturas multimarca desde la versión 5. En Drupal 10 y 11 las opciones están maduras, pero la elección entre ellas --multisite nativo, Domain Access o instalaciones independientes con código compartido-- marca el techo del proyecto. Si nadie en tu equipo ha tocado Domain Access antes, párate aquí y lee con calma: cambiar de arquitectura cuando ya hay tres marcas en producción cuesta tres o cuatro veces más que acertar al principio.

Qué se está pidiendo cuando alguien dice «multisitio»

Empecemos por desmontar la ambigüedad. La palabra «multisitio» se usa para tres escenarios que Drupal resuelve de forma muy distinta, y mezclarlos en una conversación de scoping es la receta para que el cliente espere una cosa y reciba otra.

  1. Multisite nativo de Drupal Core. Una sola base de código PHP sirve varios sitios. Cada uno con su settings.php y su base de datos. El directorio sites/ contiene una carpeta por dominio. Está documentado oficialmente desde Drupal 5.

  2. Domain Access. Una instalación, una base de datos, varios dominios. El módulo contribuido domain (estable en Drupal 10, compatible con Drupal 11 desde la 2.0.x) decide qué contenido, qué bloques y qué configuración ve cada dominio. Todos los nodos viven en la misma tabla.

  3. Instalaciones independientes con código compartido. Cada marca tiene su Drupal completo, pero el equipo mantiene un monorepo o un Composer central con módulos custom y temas base reutilizados. CI/CD se encarga de desplegar las diferencias.

La diferencia no la pagas en horas de desarrollo, la pagas en flujo editorial, en factura de hosting y en madrugones cuando hay que parchear un CVE.

Drupal Core Multisite: qué resuelve y qué te complica

La arquitectura de carpetas

El core resuelve el enrutamiento por dominio en sites/sites.php. Cada dominio apunta a un subdirectorio dentro de sites/, y ese subdirectorio puede contener su propio settings.php, sus archivos subidos y, opcionalmente, módulos y temas específicos.

Estructura típica:

/var/www/drupal/
  ├── core/
  ├── modules/
  ├── themes/
  ├── sites/
  │   ├── default/
  │   ├── marca-a.es/
  │   │   ├── settings.php
  │   │   ├── files/
  │   │   └── modules/   (módulos específicos de esta marca)
  │   ├── marca-b.es/
  │   │   ├── settings.php
  │   │   ├── files/
  │   │   └── modules/
  │   └── sites.php

Lo que ganas

  • Bases de datos separadas. Si la marca A se corrompe (alguien hizo un drush sql-drop por error, ha pasado), la marca B sigue en pie.
  • Una sola actualización del core. Subes Drupal una vez y todas las marcas se mueven a la nueva versión a la siguiente recarga de la base de datos.
  • Menos disco. El PHP se comparte. Hemos medido reducciones del 40% al 60% en proyectos con 5 sitios Drupal 10 y un perfil de módulos estándar, comparado contra cinco instalaciones independientes con su vendor/ cada una.

Lo que te complica la vida

La propia documentación de Drupal.org viene advirtiendo desde 2023 que el multisite nativo no es la opción por defecto recomendada para producción seria. Y tienen razones:

  • Módulos contribuidos compartidos. Subes un módulo a modules/ y se aplica a todas las marcas. Si la marca A necesita la 2.x de webform y la B aún arrastra una customización con la 1.x, ya tienes un problema que solo se resuelve metiendo el módulo dentro del directorio específico del sitio, lo que rompe la idea de «código compartido».
  • Drush sin paraguas. drush updb, drush cim, drush cr exigen un alias por sitio. No hay un comando transaccional que aplique migraciones a las 12 bases de datos a la vez y revierta si una falla. Te toca scriptarlo. Y vigilarlo.
  • Hosting administrado con asteriscos. Acquia Cloud, Platform.sh y Pantheon soportan multisite, pero con condiciones. Pantheon directamente recomienda su sistema de Custom Upstreams antes que el multisite nativo, lo que te ata a su forma de trabajar.
  • Escalar es manual. Añadir un sitio nuevo implica crear la base de datos, configurar el directorio, ajustar el vhost de Apache o Nginx, modificar sites.php, y si hay CDN, dar de alta un origen más. No hay un wizard que lo automatice si no lo construyes tú.

Cuándo merece la pena

Multisite nativo encaja cuando se cumplen las tres a la vez:

  1. Todas las marcas usan exactamente los mismos módulos y las mismas versiones.
  2. Hay alguien en el equipo que mantiene scripts de Drush con aliases y no le tiembla la mano al automatizar despliegues.
  3. Ninguna marca va a divergir funcionalmente de las demás en los próximos dos años.

Si fallas en cualquiera de las tres, vete a Domain Access o a instalaciones independientes. He tenido que migrar un cliente de multisite a Domain Access porque una marca empezó a necesitar Commerce y las otras cuatro no, y la divergencia de módulos se volvió ingobernable.

Domain Access: una sola instalación, varias marcas en una tabla

El ecosistema de módulos

El módulo domain no viene solo. Es una familia, y cada pieza resuelve una preocupación concreta. Esta es la combinación que suelo dejar instalada en un proyecto multimarca serio:

Módulo Para qué sirve
Domain Gestiona los dominios y subdominios como entidades. Cada marca es un Domain con su ID.
Domain Access Asigna nodos a uno o varios dominios. Un post puede aparecer en marca-a.es y marca-b.es.
Domain Alias Alias del tipo www, staging, idiomas localizados, todo apuntando al mismo dominio canónico.
Domain Config Sobrescribe configuración por dominio: nombre del sitio, logo, email de contacto, sin tocar código.
Domain Source Define el dominio canónico de cada nodo. Imprescindible si no quieres que Google te penalice por contenido duplicado.
Domain Theme Asigna un tema visual distinto a cada dominio.

Lo que hace bien

  • Contenido compartido sin duplicar. Una nota de prensa corporativa puede aparecer en tres marcas siendo el mismo nodo. Edición en un sitio, propagación a todos. Esto es oro cuando hay un departamento de comunicación corporativo que dispara contenido transversal.
  • Usuarios y roles únicos. El mismo editor puede tener permisos distintos en cada marca. Un solo login, una sola foto de perfil, una sola sesión.
  • Pipeline simple. Un composer.json, un repositorio, un pipeline CI/CD. El equipo de DevOps lo agradece.
  • Search API transversal. Puedes indexar todo y luego filtrar por dominio, o indexar por dominio según el caso de uso. Es flexible.

Y dónde te muerde

  • Acoplamiento brutal. Un fallo en un módulo custom o una migración mal hecha tumba las 12 marcas a la vez. No hay aislamiento de datos: si algo va mal a las 03:00, te has cargado el grupo entero.
  • Permisos que se vuelven una pesadilla. El sistema de roles de Drupal no se diseñó pensando en segmentación por dominio. Domain Access añade una capa adicional, y cuando llevas 50 roles combinados (admin marca A, editor marca B, revisor marca C...), auditarlo se vuelve un ejercicio de paciencia. He visto matrices de permisos de 40 columnas que nadie en el equipo era capaz de leer entera.
  • Rendimiento que se nota a partir de 20-25 dominios. La tabla de configuración crece, la resolución de dominio añade entre 5 y 15 ms por request según mediciones publicadas por el mantenedor del módulo en la issue queue de Drupal.org en 2024. Con caché agresiva no lo notas. Sin caché, sí.
  • Temas radicalmente distintos cuestan. Si la marca A es un long-form editorial y la marca B es un ecommerce minimalista con un layout completamente distinto, Domain Theme no es suficiente. Acabas con lógica condicional en Twig ({% if domain == 'marca-a' %}) y la mantenibilidad cae por un precipicio.

Tabla comparativa, ahora con honestidad

Criterio Multisite nativo Domain Access Instalaciones independientes
Aislamiento de datos Total (BD separadas) Ninguno (BD compartida) Total
Contenido compartido entre marcas Requiere desarrollo custom Nativo Requiere API o syndication
Complejidad de despliegue Media-alta Baja Alta (más infraestructura)
Escalabilidad (>10 marcas) Media Media-baja Alta
Coste de hosting (5 marcas) ~30-40% menos que independientes ~50-60% menos Referencia base
Tiempo de onboarding nueva marca 4-8 horas 1-2 horas 8-16 horas
Riesgo ante fallo crítico Afecta solo a la marca impactada Afecta a todas las marcas Afecta solo a la marca impactada
Actualizaciones de seguridad Una vez, efecto en todos Una vez, efecto en todos Una vez por instalación
Independencia de roadmap por marca Alta Baja Total

Composer en un proyecto multimarca: la pieza que nadie mira hasta que falla

Independientemente de la arquitectura, Composer es donde se libran las batallas reales del día a día. Estas son las estrategias que han sobrevivido a varios proyectos.

Monorepo con Composer Patches

Un solo repositorio Git con el composer.json raíz, módulos custom en web/modules/custom/ y temas en web/themes/custom/. Las diferencias entre marcas se manejan así:

  • Parches por sitio con cweagans/composer-patches. Aplicas parches a módulos contribuidos solo cuando despliegas una marca concreta, controlado con variables de entorno en el pipeline.
  • Configuración exportada con config_split o config_ignore. Cada marca tiene su set de YAML que sobrescribe la base. Esto te evita el infierno de mantener configuraciones a mano.

Estructura de repositorio que escala

proyecto-multimarca/
  ├── composer.json
  ├── composer.lock
  ├── config/
  │   ├── base/          (configuración común)
  │   ├── marca-a/       (overrides de marca A)
  │   ├── marca-b/       (overrides de marca B)
  │   └── marca-c/
  ├── web/
  │   ├── modules/custom/
  │   │   ├── tangram_core/     (funcionalidad compartida)
  │   │   ├── marca_a_features/ (solo marca A)
  │   │   └── marca_b_features/
  │   └── themes/custom/
  │       ├── tangram_base/     (tema base con Design System)
  │       ├── marca_a_theme/    (subtema marca A)
  │       └── marca_b_theme/
  └── scripts/
      ├── deploy-marca-a.sh
      └── deploy-marca-b.sh

Con esta forma de organizar, cada marca tiene su subtema heredando del tema base, sus features específicas y su configuración propia, compartiendo entre el 70% y el 80% del código. Cuando alguien me pregunta qué porcentaje «sale gratis» en un multimarca, esa es la respuesta honesta: alrededor de tres cuartas partes. El cuarto restante se paga.

Flujo editorial: el verdadero campo de batalla

El multisitio se rompe más por temas organizativos que técnicos. Cada marca quiere autonomía editorial, ninguna quiere depender de un equipo central para publicar un comunicado, y a la vez nadie quiere que la marca A publique algo que descuadre la imagen del grupo. La plataforma tiene que reflejar esa tensión.

Modelo de roles que ha sobrevivido a auditorías

Rol Alcance Permisos típicos
Superadmin Todas las marcas Configuración global, despliegues, gestión de módulos
Admin de marca Una marca Gestión de menús, taxonomías, bloques y usuarios de su marca
Editor de marca Una marca Crear, editar y publicar contenido de su marca
Revisor corporativo Todas las marcas (solo lectura + aprobación) Revisar contenido antes de publicación en cualquier marca

En Domain Access estos roles se materializan combinando los permisos estándar con las restricciones por dominio del módulo. En multisite nativo, cada sitio tiene su tabla de usuarios y roles, lo que simplifica la segmentación pero impide la revisión transversal sin tooling adicional (típicamente: un servicio externo que consulte las bases de datos vía API).

Content Moderation: el módulo que pocos configuran bien

Drupal Core incluye Content Moderation desde la 8.5. Define estados (borrador, en revisión, publicado, archivado) y transiciones. Para un entorno multimarca, el flujo que recomiendo es:

  1. El editor de la marca crea el contenido en «Borrador».
  2. Pasa a «En revisión» y se notifica al admin de marca o al revisor corporativo según el tipo de contenido (típicamente, las notas de prensa se revisan a nivel corporativo, los posts de blog no).
  3. Tras la aprobación, pasa a «Publicado» y se asigna al dominio correspondiente en Domain Access o se inyecta en la base de datos correcta en multisite nativo.

El paso 2 es donde caen los proyectos. Sin una matriz clara de qué requiere revisión corporativa y qué no, los editores se atascan en el flujo y acaban publicando en producción saltándose el workflow. La regla de oro: cuanto menos tipos de contenido requieran revisión corporativa, más sano será el flujo.

Rendimiento y caché: lo que cambia según la arquitectura

Varnish y CDN

En multisite nativo, cada sitio puede tener su VCL. Las reglas de purga y los TTL se definen por dominio. Si usas Cloudflare o Fastly, cada dominio es un sitio independiente en la consola del CDN.

En Domain Access, la caché tiene que discriminar por dominio o explotará en tu cara. El módulo emite las cabeceras Vary: Host, pero Varnish necesita reglas explícitas para no servir a un visitante de marca-a.es una página de marca-b.es. Lo mínimo:

sub vcl_hash {
    hash_data(req.http.Host);
    hash_data(req.url);
}

He visto una vez a un equipo olvidar el hash_data(req.http.Host) y servir, durante 40 minutos en producción, el home de la marca B a los visitantes de la marca A. Una marca era B2B industrial, la otra B2C alimentación. Imagínate la cara del director de marketing.

Datos reales de un proyecto de 4 marcas

Métricas comparativas medidas en un cliente con 4 marcas, cada una entre 500 y 2000 nodos:

Métrica Domain Access (1 BD) Multisite nativo (4 BD)
Tiempo medio de respuesta (sin caché) 320 ms 280 ms
Tiempo medio de respuesta (con Varnish) 12 ms 11 ms
Consumo de RAM MySQL (idle) 380 MB 520 MB (130 MB x 4)
Tamaño total de BD 1.2 GB 1.8 GB (overhead de esquema x 4)

Multisite nativo va un 14% más rápido sin caché porque las consultas SQL trabajan con tablas más pequeñas. Con Varnish activado, la diferencia es estadística, no operativa. Si vas a tener caché agresiva (y deberías), no decidas por rendimiento bruto.

Actualizaciones de seguridad: la métrica que de verdad importa

Drupal publica parches de seguridad los miércoles. En un entorno multimarca, el tiempo que tardas en aplicar un parche crítico es un KPI de riesgo real. La diferencia entre arquitecturas aquí es brutal.

  • Domain Access: composer update drupal/core --with-dependencies, drush updb, drush cr. Una operación, todas las marcas actualizadas. Tiempo medio con pruebas: 15-30 minutos.
  • Multisite nativo: actualización de código única, pero drush updb debe correr por cada sitio. Con 5 sitios y scripts decentes: 30-60 minutos.
  • Instalaciones independientes: composer update y despliegue por cada una. Con 5 instalaciones y sin una automatización muy seria: 2-3 horas reales, contando pruebas.

Esa diferencia de tiempo es la que separa estar parcheado a las 11:00 del miércoles o a las 14:00 del jueves. Y los exploits no esperan.

Módulos que mantengo siempre instalados

Módulo Versión Drupal Para qué lo uso
Config Split 10, 11 Separar configuración base de configuración por marca
Config Ignore 10, 11 Ignorar ciertos valores durante importaciones (claves de API, secretos)
Environment Indicator 10, 11 Barra visual que te recuerda en qué entorno y marca trabajas. Evita despliegues a producción accidentales.
Monitoring (Monolog) 10, 11 Logs centralizados de todas las marcas en un mismo backend
Automated Cron Core Cron independiente por sitio en multisite nativo
Ultimate Cron 10, 11 Control granular de tareas cron por marca cuando hay procesos pesados

Gobernanza: la parte que no aparece en los presupuestos

Un multimarca en Drupal sin gobernanza acaba siendo una factura mensual creciente y un equipo de marketing frustrado. La parte técnica es resoluble; la parte organizativa, no siempre. Tres pilares que han funcionado en grupos empresariales españoles, desde cadenas hoteleras con marcas por segmento hasta holdings industriales con divisiones B2B y B2C.

1. Propiedad clara del contenido por marca. Cada marca necesita un responsable editorial con autoridad real para publicar. Si todo pasa por un equipo central de comunicación corporativa, el cuello de botella aparece en cuestión de semanas y los editores empiezan a quejarse al CEO.

2. Estándares compartidos, ejecución distribuida. El equipo técnico central define las reglas: qué módulos están en el catálogo aprobado, qué tipos de contenido se pueden crear, qué estándares de accesibilidad se exigen. Recuerda que WCAG 2.1 AA es obligatorio en España para ciertos sectores según el Real Decreto 1112/2018, así que esto no es un nice-to-have. Cada marca ejecuta dentro de esos límites, sin pedir permiso para cada cambio de contenido pero sin saltarse las reglas estructurales.

3. Presupuesto de mantenimiento asignado desde el día uno. El error clásico: se presupuesta la construcción y se olvida el mantenimiento. El mantenimiento anual de un entorno Drupal multimarca (actualizaciones de seguridad, monitorización, soporte editorial, evolución de funcionalidades) está entre el 15% y el 25% del coste inicial, según datos de la Drupal Association y nuestra experiencia operando estos sistemas. Si no se asigna esa partida, el sistema se degrada y a los dos años el cliente quiere migrar a otra cosa.

Si necesitas plantear este modelo dentro de tu organización o quieres una segunda opinión sobre una arquitectura ya en marcha, puedes contactar con nuestro equipo.

Checklist antes de poner en producción

Lo que repaso siempre con el responsable técnico antes de meter un multimarca en producción:

  • Cada dominio tiene certificado SSL individual o wildcard configurado.
  • Los ficheros robots.txt y sitemap.xml son independientes por marca.
  • Google Search Console tiene una propiedad verificada por dominio.
  • Las redirecciones 301 entre marcas están documentadas y probadas.
  • El plan de disaster recovery contempla restauración individual por marca.
  • Existe documentación actualizada del mapeo de roles y permisos.
  • Los tests automatizados (Behat, Cypress o Playwright) cubren al menos el happy path de cada marca.

Si fallas en cualquiera de estos puntos, no estás listo para producción. Y si te saltas la auditoría porque «hay prisa», la prisa la pagarás multiplicada cuando algo se rompa.

Cuál elegir según tu situación

No hay respuesta universal. Hay variables concretas que cada organización tiene que mirarse al espejo.

Elige Domain Access si:

  • Tienes entre 2 y 10 marcas con contenido parcialmente compartido.
  • Tu equipo técnico es pequeño (1-3 personas) y no puedes permitirte una sobrecarga operativa enorme.
  • Las marcas comparten la mayoría de funcionalidades y solo difieren en diseño y contenido.
  • Necesitas informes cruzados o búsqueda unificada entre marcas.

Elige Multisite nativo si:

  • Cada marca necesita módulos o versiones diferentes.
  • El aislamiento de datos es un requisito regulatorio (por ejemplo, marcas que operan en sectores con normativas de protección de datos distintas, o una marca financiera junto a una de retail).
  • Tienes capacidad técnica para mantener scripts de automatización y Drush aliases sin que se convierta en un coste oculto.

Elige instalaciones independientes si:

  • Cada marca tiene su propio roadmap tecnológico y su propio equipo de desarrollo.
  • Prevés que alguna marca pueda migrar a otra plataforma, ser vendida o escindida.
  • El volumen de tráfico de alguna marca justifica infraestructura dedicada (orientativamente, más de 500.000 visitas mensuales por marca).

Construir un entorno multimarca en Drupal es una decisión que se toma una vez. Migrar entre arquitecturas con tres marcas ya en producción multiplica el coste por tres o por cuatro y consume meses de equipo. Evaluar el escenario real --cuántas marcas, qué grado de autonomía editorial, qué capacidad técnica tienes, cuánto puedes destinar al mantenimiento-- antes de escribir la primera línea de código es lo que separa un proyecto que escala con la organización de uno que acaba siendo el problema favorito de las reuniones de comité técnico.

Lo digo desde la cicatriz de haber tomado, alguna vez, la decisión equivocada.