Configuration of Multi-Site Support in Craft CMS
Craft CMS supports multiple sites from one installation: different domains, languages, regions. Content can be unique to each site or synchronized between them.
Multi-Site Architecture
Craft Installation
├── Site Group: Main
│ ├── Site: mysite.ru (ru-RU) — primary
│ ├── Site: mysite.com (en-US)
│ └── Site: mysite.de (de-DE)
└── Site Group: Microsite
└── Site: promo.mysite.ru (ru-RU)
Configuration via CP or Project Config
# config/project/sites/mysite-ru.yaml
name: 'My Site RU'
handle: mySiteRu
language: ru-RU
primary: true
enabled: true
hasUrls: true
baseUrl: 'https://mysite.ru/'
Nginx configuration for multiple domains on one installation:
# Both domains point to one document root
server {
server_name mysite.ru mysite.com mysite.de;
root /var/www/mysite/web;
# ...standard Craft Nginx config...
}
Content Distribution Management via Sites
propagationMethod in Section defines how content is distributed:
-
all— entry is created for all sites automatically -
none— only for site where it's created -
siteGroup— for sites in the same group -
language— for sites with same language
# config/project/sections/blog.yaml
propagationMethod: all
siteSettings:
mySiteRu:
hasUrls: true
uriFormat: 'blog/{slug}'
template: blog/_entry
mySiteEn:
hasUrls: true
uriFormat: 'en/blog/{slug}'
template: blog/_entry
mySiteDe:
hasUrls: true
uriFormat: 'de/blog/{slug}'
template: blog/_entry
Fields with Different Localization
Field "title": translationMethod = site (own title for each site)
Field "publishDate": translationMethod = none (one date)
Field "heroImage": translationMethod = none (shared image)
Field "body": translationMethod = site (unique text)
Field "slug": translationMethod = site (slug in site language)
Language Switcher in Template
{# List of all versions of current page #}
<nav class="language-switcher">
{% for site in craft.app.sites.getAllSites() %}
{% set localeEntry = entry.getLocalized().site(site).one() %}
{% if localeEntry %}
<a href="{{ localeEntry.url }}"
lang="{{ site.language | slice(0, 2) }}"
{% if site.id == currentSite.id %}aria-current="page"{% endif %}>
{{ site.language | upper | slice(0, 2) }}
</a>
{% endif %}
{% endfor %}
</nav>
Site-Aware Queries
{# Current site content (automatic) #}
{% set posts = craft.entries().section('blog').all() %}
{# Explicit site specification #}
{% set enPosts = craft.entries().section('blog').site('mySiteEn').all() %}
{# Via PHP in module #}
$entries = Entry::find()
->section('blog')
->site(\Craft::$app->sites->getSiteByHandle('mySiteRu'))
->all();
Interface Translations
// translations/ru/site.php
return [
'Read more' => 'Читать далее',
'Published on {date}' => 'Опубликовано {date}',
];
In Twig:
{{ "Read more" | t('site') }}
{{ "Published on {date}" | t('site', { date: entry.postDate | date('d.m.Y') }) }}
Configuration of multi-site with 2–3 languages for existing project takes 2–4 days.







