Base URLs, SSL and getting server configuration right
Magento 2 domain mapping per store means assigning every store view its own distinct domain instead of a shared store code in the path, and that touches far more than just the base URL configuration in the backend. Vhost rules, SSL certificates, cookie domains and the Varnish cache strategy all need to align consistently with the same domain model, otherwise hard-to-find bugs appear between store views.
Table of Contents
- 1. Why domain mapping is more than a backend setting
- 2. Configuring the base URL per store view correctly
- 3. Vhost configuration for multiple domains
- 4. Store resolution: how Magento maps a domain to a store view
- 5. Managing SSL certificates per domain
- 6. Cookie domain and session boundaries between stores
- 7. Varnish and full page cache per domain
- 8. Avoiding duplicate content between domains
- 9. Domain strategies compared
- 10. Summary
- 11. FAQ
1. Why domain mapping is more than a backend setting
For many internationally operating shops, a dedicated domain per market, for example shop.de and shop.fr, makes more business sense than a shared store code in the URL path. Magento 2 domain mapping per store can be set up in the backend with a handful of configuration values, but its actual functionality depends on a whole chain of infrastructure decisions that go far beyond the base URL setting.
Anyone who configures domain mapping per store only in the backend, without thinking through the associated web server configuration, SSL management and cache strategy, produces a system that works in test environments but breaks at unexpected points in production, for example when a certificate for a newly added domain is missing, or the full page cache swaps content between domains. The following sections address each layer of this infrastructure individually.
2. Configuring the base URL per store view correctly
The configuration values web/unsecure/base_url and web/secure/base_url define under which domain a store view is reachable, and must be set individually at store view level if domain mapping per store is to be implemented. A common beginner mistake is setting these values only at website level, which does not work with multiple store views having different domains within the same website, since all store views would then inherit the same base URL.
In addition to the base URL, web/secure/use_in_frontend and web/secure/use_in_adminhtml must be set correctly so Magento consistently generates HTTPS URLs. A subtle mistake occurs when one of the domains does not have a valid SSL certificate, but the secure base URL still points to https: the customer then sees browser certificate warnings even though the Magento configuration itself looks correct.
#!/usr/bin/env bash
set -euo pipefail
# Configure base URLs per store view for domain-based multi-store setup
bin/magento config:set --scope=stores --scope-code=de \
web/unsecure/base_url "http://shop.de/"
bin/magento config:set --scope=stores --scope-code=de \
web/secure/base_url "https://shop.de/"
bin/magento config:set --scope=stores --scope-code=fr \
web/unsecure/base_url "http://shop.fr/"
bin/magento config:set --scope=stores --scope-code=fr \
web/secure/base_url "https://shop.fr/"
bin/magento config:set --scope=stores --scope-code=at \
web/unsecure/base_url "http://shop.at/"
bin/magento config:set --scope=stores --scope-code=at \
web/secure/base_url "https://shop.at/"
# Force HTTPS everywhere in frontend and admin
bin/magento config:set web/secure/use_in_frontend 1
bin/magento config:set web/secure/use_in_adminhtml 1
# Optional: a shared cookie domain only makes sense for subdomains of one TLD
# bin/magento config:set --scope=stores --scope-code=de web/cookie/cookie_domain ".shop.com"
bin/magento cache:flush config full_page
# Verify store resolution locally before the DNS cutover, using the Host header
curl -sI -H "Host: shop.fr" http://127.0.0.1/ | grep -i location
curl -sI -H "Host: shop.de" http://127.0.0.1/ | grep -i location
# Add temporary local entries while DNS still points elsewhere
echo "127.0.0.1 shop.de shop.fr shop.at" | sudo tee -a /etc/hosts
This local test against the Host header, done before the actual DNS cutover, catches a large share of domain mapping per store mistakes ahead of time. If the calculated redirect target URL for a test domain does not match the expected store view, the cause is almost always a misconfigured or missing base URL setting, and can be fixed before a single customer ever sees a faulty redirect.
3. Vhost configuration for multiple domains
At the web server level, every domain used for domain mapping per store needs its own virtual host, either as a separate Nginx server block or as an Apache VirtualHost. All domains point to the same document root, since store assignment does not happen at the file system level but inside Magento based on the requested domain. The web server merely needs to pass the correct host header through to PHP-FPM so Magento's store resolver can evaluate it.
An important detail with Nginx configurations is that all domains can share the same server_name entry, or multiple space-separated entries in the same server block, as long as no domain-specific path rules are needed. If different rewrite rules are needed per domain, for example redirects from an old domain, a separate server block per domain with a shared include for the actual Magento configuration is recommended.
# /etc/nginx/sites-available/magento-multi-domain.conf
# Single server block handling multiple store domains, same document root
server {
listen 443 ssl http2;
server_name shop.de shop.fr shop.at;
root /var/www/magento/pub;
ssl_certificate /etc/ssl/multi-domain/fullchain.pem;
ssl_certificate_key /etc/ssl/multi-domain/privkey.pem;
include /etc/nginx/snippets/magento-fastcgi.conf;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
}
server {
listen 80;
server_name shop.de shop.fr shop.at;
return 301 https://$host$request_uri;
}
# /etc/nginx/snippets/magento-fastcgi.conf
# Shared FastCGI settings included by every store domain's server block
location ~ ^/(index|get|static|errors/report|errors/404|errors/503|health_check)\.php$ {
fastcgi_pass unix:/run/php/php8.4-fpm-magento.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTP_HOST $host;
include fastcgi_params;
}
# Alternative: dedicated server block per domain when redirects from a
# legacy domain (old.shop.de -> shop.de) require domain-specific rewrite rules
server {
listen 443 ssl http2;
server_name old.shop.de;
ssl_certificate /etc/ssl/old-shop-de/fullchain.pem;
ssl_certificate_key /etc/ssl/old-shop-de/privkey.pem;
return 301 https://shop.de$request_uri;
}
4. Store resolution: how Magento maps a domain to a store view
As soon as a request arrives at Magento, Magento\Store\App\Request\PathInfoProcessor in combination with the store resolver takes over mapping the host header to the matching store view. Magento compares the host header against the configured base URLs of all store views and selects the first matching store view. For domain mapping per store it is important that these base URLs match the actual host exactly, including or excluding the www prefix, since even a small difference causes the store not to be recognized.
For more complex requirements, for example when a single domain should point to different store views depending on the URL path segment, native base URL mapping is not sufficient. Here a custom plugin on the store resolver or a custom module is needed that evaluates the host header combined with the path, for example to route shop.com/de/ and shop.com/fr/ to different store views while shop.us simultaneously serves as its own domain for another store view.
For troubleshooting in production, a simple test with curl and a manually set Host header directly against the server IP, bypassing DNS entirely, helps. If the result deviates from expectations, this quickly distinguishes whether the fault lies in the web server, the store resolver, or DNS resolution itself, considerably shortening diagnosis time for domain mapping per store issues.
<?php
declare(strict_types=1);
namespace Mironsoft\DomainMapping\Plugin;
use Magento\Store\Model\StoreResolver;
use Magento\Framework\App\RequestInterface;
/**
* Combines host header and first path segment to resolve a store view,
* enabling shop.com/de/ and shop.com/fr/ to resolve differently while
* shop.us stays a fully independent domain for another store view.
*/
final class HostAndPathStoreResolver
{
/**
* @param RequestInterface $request Current HTTP request
*/
public function __construct(
private readonly RequestInterface $request
) {
}
/**
* @param StoreResolver $subject Native store resolver
* @param string $result Native resolved store code
* @return string Adjusted store code based on host + path segment
*/
public function afterGetRequestValue(StoreResolver $subject, string $result): string
{
$host = (string) $this->request->getServer('HTTP_HOST');
if ($host !== 'shop.com') {
return $result;
}
$firstSegment = trim((string) $this->request->getPathInfo(), '/');
$langCode = explode('/', $firstSegment)[0] ?? '';
return match ($langCode) {
'fr' => 'fr_store',
'de' => 'de_store',
default => $result,
};
}
}
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Store\Model\StoreResolver">
<plugin name="mironsoft_hostAndPathStoreResolver"
type="Mironsoft\DomainMapping\Plugin\HostAndPathStoreResolver"
sortOrder="10" />
</type>
</config>
5. Managing SSL certificates per domain
For domain mapping per store with multiple genuine domains, as opposed to subdomains of the same main domain, every domain needs a valid SSL certificate. A multi-domain certificate, also called a SAN certificate, covering all store domains in a single certificate with multiple Subject Alternative Names, is the lowest-maintenance approach, especially combined with automatic renewal via Let's Encrypt and its DNS or HTTP-01 challenge mechanisms.
A common pitfall is that a newly added store view with a new domain is configured in the backend while the associated SSL certificate has not yet been extended. The store view is then fully configured in Magento but unreachable for customers, because the web server cannot offer a valid certificate for that domain. A deployment checklist item requiring SSL certificate extension before store view activation reliably prevents this recurring problem.
For domains sharing the same main domain, for example de.shop.com and fr.shop.com, a wildcard certificate with a DNS-01 challenge is often the more practical choice, since new subdomains are automatically covered by the existing certificate without a renewed issuance process. For fully independent domains such as shop.de and shop.fr, a SAN certificate with an HTTP-01 challenge per domain is instead the usual approach, since no shared wildcard base exists here.
#!/usr/bin/env bash
set -euo pipefail
# Issue a single SAN certificate covering all store domains
certbot certonly --nginx \
-d shop.de -d shop.fr -d shop.at \
--cert-name multi-domain \
--non-interactive --agree-tos -m ops@mironsoft.de
# Renewal is handled by certbot's own systemd timer, verify with:
certbot renew --dry-run
# Alternative for subdomains of one TLD: a single wildcard certificate
# covers every future subdomain automatically via DNS-01 challenge
certbot certonly --manual --preferred-challenges dns \
-d "*.shop.com" -d "shop.com"
6. Cookie domain and session boundaries between stores
The configuration value web/cookie/cookie_domain determines for which domain Magento cookies, such as the session id or the cart state, are valid. With genuine domain mapping per store using different top-level domains, for example shop.de and shop.fr, the stores do not share a common cookie domain, and every store view necessarily runs an isolated session. This is in most cases also desired, since carts cannot meaningfully be shared between different countries and currencies anyway.
The situation differs with subdomain-based domain mapping, for example de.shop.com and fr.shop.com. Here a shared cookie domain like .shop.com can be configured, allowing a logged-in customer to stay logged in when switching between subdomains, provided customer data is also shared between the stores. This decision should be made deliberately, since a shared cookie domain without a shared customer database leads to contradictory behavior.
7. Varnish and full page cache per domain
When using Varnish as the full page cache, the VCL configuration must include the host header as part of the cache key, otherwise cache entries can be swapped between domains in domain mapping per store, with serious consequences: a customer on shop.fr could suddenly see content cached for shop.de, in the wrong language. Magento's default VCL template already handles the host correctly, but custom VCL modifications should not accidentally override this mechanism.
For cache invalidation it must additionally be considered that a product update affecting multiple store views also needs to trigger multiple purge requests to Varnish, each with the correct host header for the affected domain. Magento's native cache invalidation already accounts for this, but custom extensions of the cache invalidation mechanism, for example for external systems pushing price changes via API, need to explicitly rebuild this domain awareness.
8. Avoiding duplicate content between domains
A risk with domain mapping per store that is easily overlooked is duplicate content, when identical product content is accidentally reachable through multiple domains, for example because a domain incorrectly still points to the global product catalog instead of the store-specific catalog. Search engines interpret this as duplication and may downrank the visibility of both versions in search results, regardless of the fact that these are technically different store views.
The solution lies in a consistent canonical URL and hreflang strategy based on the same domain mapping as the store resolution itself. Every page should set a canonical tag pointing to its own domain, while hreflang tags point to the respective matching language versions on the other domains. Together these two mechanisms clearly signal to search engines that this is deliberately separated, market-specific content rather than accidental duplication.
In addition, every domain should maintain its own robots.txt and, where used, its own x-default hreflang entry for language-neutral landing pages. If a single global robots.txt is accidentally served across all domains, for example because it comes from a shared static asset directory, crawling rules can arise that make sense for one domain but accidentally block entire sections for another.
9. Domain strategies compared
The following table compares the three most common approaches for domain mapping per store.
| Strategy | SSL effort | Cookie isolation | SEO clarity |
|---|---|---|---|
| Store code in path | One certificate suffices | Shared session across all stores | Good, but less brand impact |
| Subdomains (de.shop.com) | One wildcard certificate | Configurable, usually shared | Very good |
| Own TLDs (shop.de, shop.fr) | SAN certificate or several individual certificates needed | Fully isolated | Optimal, clearest market signals |
For brands with a strong local market presence, dedicated country-specific TLDs are usually the most convincing choice, despite higher SSL and infrastructure overhead, since they build trust with the local audience and give search engines the clearest signals about market targeting.
Mironsoft
Magento 2 multi store and internationalization
Need domain mapping that keeps server, SSL and cache consistent?
We configure base URLs, vhosts, SSL certificates and Varnish VCL for Magento 2 shops with multiple store domains, so every market stays reliably reachable without cache swapping.
Infrastructure audit
Review vhost, SSL and base URL configuration for consistency
Varnish hardening
Verify VCL for correct host-based cache keys and purges
SEO safeguarding
Canonical and hreflang strategy against duplicate content
10. Summary
Successful Magento 2 domain mapping per store starts with the base URL configuration at store view level, but does not end there: vhost configuration, SSL certificates, cookie domain decisions and a domain-aware Varnish strategy all need to work together consistently. A SAN certificate with automatic renewal significantly reduces maintenance effort for multiple genuine domains, while the choice between subdomains and dedicated TLDs remains a strategic decision between SEO clarity and infrastructure complexity.
Anyone who additionally aligns canonical tags and hreflang references consistently with the same domain structure as the technical store resolution avoids the risk of duplicate content penalties. The biggest source of error in production remains a new store view whose domain is configured in the backend but whose SSL certificate has not yet been extended, which is why this step firmly belongs in every deployment checklist.
Magento 2 Domain Mapping Per Store — Key Takeaways
Base URL per store view
web/unsecure/base_url and web/secure/base_url must be set store-view-specific, not at website level.
SSL before store activation
New domains need a valid certificate before the associated store view goes live.
Varnish with host-based cache key
VCL must account for the host header, otherwise cache content gets swapped between domains.
Consistent canonical and hreflang
Both mechanisms must use the same domain mapping as the technical store resolution to avoid duplicate content.