Configuring Multi-site Setup in Magento 2 (Website/Store/Store View)
Magento 2 allows managing multiple websites from a single installation. This is not just convenience — with proper architecture, multi-site significantly reduces operational burden: one codebase, one deployment, shared products and customer base with separate catalogs and settings.
Three-level Hierarchy
Magento divides sites into three levels with clear hierarchy:
Website — top level. Determines:
- Independent cart and checkout (purchases don't transfer between Websites)
- Shared customer base (by default) or isolated
- Base currency
- Store groups
Store (Store Group) — middle level:
- Root category of the catalog (different category trees for different Stores)
- Multiple Store Views for one language version
- One Store View must be marked as Default
Store View — bottom level:
- Language and localization
- URL (subdomain or path)
- Content translations
Typical structure:
Website: Main (myshop.com)
├── Store: Retail
│ ├── Store View: English (en_US) [default]
│ └── Store View: German (de_DE)
└── Store: Wholesale
└── Store View: English (en_US) [default]
Website: Partner (b2b.myshop.com)
└── Store: B2B Catalog
└── Store View: English (en_US) [default]
Creation via Admin
Admin > Stores > All Stores
1. Create Website
- Name: B2B Portal
- Code: b2b (unique, only latin/digits/underscore)
- Sort Order: 2
2. Create Store (Store Group)
- Website: B2B Portal
- Name: B2B Catalog
- Root Category: B2B Categories (created separately)
- Default Store View: (selected after Store View creation)
3. Create Store View
- Store: B2B Catalog
- Name: English
- Code: b2b_en
- Status: Enabled
- Sort Order: 1
Nginx Configuration for Multi-site
Option 1 — different subdomains:
# /etc/nginx/sites-available/magento-retail.conf
server {
listen 443 ssl http2;
server_name shop.example.com;
root /var/www/magento/pub;
set $MAGE_RUN_CODE "base";
set $MAGE_RUN_TYPE "website";
include /etc/nginx/snippets/magento.conf;
}
# /etc/nginx/sites-available/magento-b2b.conf
server {
listen 443 ssl http2;
server_name b2b.example.com;
root /var/www/magento/pub;
set $MAGE_RUN_CODE "b2b";
set $MAGE_RUN_TYPE "website";
include /etc/nginx/snippets/magento.conf;
}
Option 2 — URL paths (one domain):
server {
listen 443 ssl http2;
server_name example.com;
root /var/www/magento/pub;
# Store View determination by URL path
location ~ ^/b2b {
set $MAGE_RUN_CODE "b2b_en";
set $MAGE_RUN_TYPE "store";
rewrite ^/b2b/?(.*) /$1 break;
}
location / {
set $MAGE_RUN_CODE "base";
set $MAGE_RUN_TYPE "website";
}
include /etc/nginx/snippets/magento.conf;
}
Option 3 — via PHP entry point (most flexible):
// pub/index.php — custom mapping before Bootstrap::run()
use Magento\Framework\App\Bootstrap;
require __DIR__ . '/../app/bootstrap.php';
$host = $_SERVER['HTTP_HOST'] ?? '';
$params = $_SERVER;
$runCodes = [
'shop.example.com' => ['type' => 'website', 'code' => 'base'],
'b2b.example.com' => ['type' => 'website', 'code' => 'b2b'],
'de.example.com' => ['type' => 'store', 'code' => 'store_de'],
];
if (isset($runCodes[$host])) {
$params['MAGE_RUN_TYPE'] = $runCodes[$host]['type'];
$params['MAGE_RUN_CODE'] = $runCodes[$host]['code'];
}
$bootstrap = Bootstrap::create(BP, $params);
$app = $bootstrap->createApplication(\Magento\Framework\App\Http::class);
$bootstrap->run($app);
URL Configuration for Store View
Admin > Stores > Configuration > Scope: [Store View]
> General > Web > Base URLs
Base URL: https://b2b.example.com/
Base Link URL: https://b2b.example.com/
Base Static View Files URL: https://b2b.example.com/pub/static/
Base Media Files URL: https://b2b.example.com/pub/media/
For HTTPS:
> Base URLs (Secure)
Secure Base URL: https://b2b.example.com/
Use Secure URLs on Storefront: Yes
Use Secure URLs in Admin: Yes
Separate Catalogs
Each Store has its own Root Category. This allows showing different category trees:
Admin > Catalog > Categories
Create root category "B2B Categories":
├── Industrial Equipment
│ ├── Machines
│ └── Measurement Instruments
└── Consumables
Create root category "Retail Categories":
├── Electronics
├── Home Appliances
└── Tools
Products can be shared — one product linked to categories from different trees.
Configuration Scope
Most Magento settings have Scope: Global → Website → Store View. Store View settings override Website settings, which override Global.
Admin > Stores > Configuration
Current scope: selected in top left corner
Example — different shipping methods for different Websites:
Scope: Website B2B
> Sales > Shipping Methods
Table Rates: Enabled
Free Shipping: Disabled (show real cost for B2B)
Scope: Website Retail
> Sales > Shipping Methods
Table Rates: Enabled
Free Shipping: Enabled (from 3000 USD)
Via CLI with scope specification:
# Set base URL for specific Website
bin/magento config:set --scope=websites --scope-code=b2b web/unsecure/base_url https://b2b.example.com/
bin/magento config:set --scope=websites --scope-code=b2b web/secure/base_url https://b2b.example.com/
# For Store View
bin/magento config:set --scope=stores --scope-code=b2b_en general/locale/code en_US
bin/magento config:set --scope=stores --scope-code=b2b_en general/locale/timezone UTC
bin/magento cache:flush
Static Content Deployment for Multiple Themes
In multi-site, different Websites/Stores can use different themes:
# Deploy for all themes and locales
bin/magento setup:static-content:deploy en_US de_DE \
--theme MyCompany/retail \
--theme MyCompany/b2b \
--jobs=4 \
-f
Shared Customer Base vs Isolated
By default, customers are shared across the entire installation — email is unique globally. To isolate customers by Website:
Admin > Stores > Configuration > Scope: Global
> Customers > Customer Configuration > Account Sharing Options
Share Customer Accounts: Per Website
After change — mandatory bin/magento customer:hash:upgrade and reindexing.
Multi-site Performance
Each Store View adds load on indexers and cache. With large number of Store Views:
- Indexer
catalog_product_price— heaviest, needs optimization - Varnish FPC divides cache by Store View via
X-Magento-Tags - Redis cache should have separate databases for different data types
Monitoring slow indexers:
bin/magento indexer:status
bin/magento indexer:reindex catalog_product_price
# Last reindex time
SELECT indexer_id, status, updated FROM indexer_state;
Timeline
Adding second Website/Store with shared catalog and separate settings: 2–3 days. Full multi-site with 3–5 Websites, different themes, isolated catalogs, separate customer base and custom Nginx rules: 1–2 weeks. With B2B module Adobe Commerce with corporate accounts and price lists: additional 2–4 weeks.







