Wagtail Multisite Configuration
Wagtail supports multiple sites within one installation. One Django project, one database, one admin panel, but different domains with independent page trees. Architecture suits holding companies, agencies managing client sites.
How Multisite Works
Wagtail stores site config in wagtailcore_site table. Each record contains:
-
hostname— domain -
port— port (80/443) -
root_page— root of site tree -
is_default_site— default site flag
When request arrives, Wagtail checks Host header and selects the site.
Basic Setup via Admin Panel
- Create root page for each site (usually
HomePage) - Add Sites record with domain and root page
- Repeat for each domain
For local development with multiple domains, add to /etc/hosts:
127.0.0.1 brand-a.local
127.0.0.1 brand-b.local
Programmatic Setup via Data Migration
For reproducible setup:
# migrations/0002_multisite_setup.py
from django.db import migrations
def create_sites(apps, schema_editor):
Site = apps.get_model('wagtailcore', 'Site')
Page = apps.get_model('wagtailcore', 'Page')
brand_a_root = Page.objects.get(slug='brand-a')
brand_b_root = Page.objects.get(slug='brand-b')
Site.objects.filter(is_default_site=True).update(
hostname='brand-a.example.com',
root_page=brand_a_root,
)
Site.objects.create(
hostname='brand-b.example.com',
port=443,
root_page=brand_b_root,
site_name='Brand B',
is_default_site=False,
)
class Migration(migrations.Migration):
dependencies = [('website', '0001_initial')]
operations = [migrations.RunPython(create_sites, migrations.RunPython.noop)]
Multisite Settings
BaseSiteSetting binds settings to specific site:
from wagtail.contrib.settings.models import BaseSiteSetting, register_setting
@register_setting
class BrandSettings(BaseSiteSetting):
logo = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL)
primary_color = models.CharField(max_length=7, default='#000000')
footer_text = models.TextField(blank=True)
panels = [
FieldPanel('logo'),
FieldPanel('primary_color'),
FieldPanel('footer_text'),
]
class Meta:
verbose_name = 'Brand Settings'
In templates:
{% load wagtailsettings_tags %}
{% get_settings %}
<style>:root { --primary: {{ settings.website.BrandSettings.primary_color }}; }</style>
Nginx Routing
upstream wagtail {
server 127.0.0.1:8000;
}
server {
listen 443 ssl;
server_name brand-a.example.com;
location / {
proxy_pass http://wagtail;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
}
}
Editor Access Control
from django.contrib.auth.models import Group
from wagtail.models import GroupPagePermission
def setup_brand_editors(brand_root_page, group_name):
group, _ = Group.objects.get_or_create(name=group_name)
GroupPagePermission.objects.get_or_create(
group=group,
page=brand_root_page,
permission_type='change',
)
return group
Timeline
Basic multisite setup for 2–3 domains: 1–2 days. With custom brand settings, media management: 3–4 days.







