Websites, Store Views und Domains realistisch nachbauen
Wer Multi-Store-Bugs erst im Staging findet, verliert Zeit und Vertrauen. Eine lokale Multi-Store-Entwicklungsumgebung mit eigenen Domains, echten Store Views und store-spezifischen Konfigurationswerten deckt Fehler auf, die eine Single-Store-Instanz nie zeigen würde.
Inhaltsverzeichnis
- 1. Warum eine lokale Multi-Store-Umgebung nötig ist
- 2. Docker-Compose-Setup für mehrere Websites
- 3. Domains und Hosts-Datei für Store Views
- 4. Nginx-Vhosts und MAGE_RUN_CODE
- 5. app/etc/config.php und store-spezifische Werte
- 6. Website, Store Group und Store View anlegen
- 7. Sprachen, Währungen und Locale je Store View
- 8. Testdaten und Fixtures pro Store
- 9. Single-Store vs. Multi-Store im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum eine lokale Multi-Store-Umgebung nötig ist
Viele Magento-Teams entwickeln monatelang gegen eine einzige Store-View und wundern sich dann, warum im Staging plötzlich Preise falsch angezeigt werden oder ein Layout-Update nur auf einer von drei Domains greift. Der Grund ist fast immer derselbe: Die lokale Instanz kannte gar keine Multi-Store-Entwicklungsumgebung, sondern lief mit einem einzigen Default-Store, während Produktion längst mehrere Websites mit eigenen Domains, Sprachen und Preisbüchern betreibt. Fehler, die nur im Zusammenspiel mehrerer Store-Codes auftreten, werden so systematisch übersehen.
Eine korrekt aufgesetzte Multi-Store-Entwicklungsumgebung bildet die komplette Website-Store-Group-Store-View-Hierarchie lokal nach, inklusive eigener Domains pro Store View. Das kostet beim initialen Setup etwas Zeit, zahlt sich aber bei jedem Feature aus, das store-spezifisches Verhalten berührt: Preisregeln, Versandmethoden, Payment-Konfiguration, CMS-Blöcke und Layout-Updates. Wer diese Fälle nur in Produktion testet, testet zu spät.
Dieser Artikel zeigt den kompletten Aufbau einer Multi-Store-Entwicklungsumgebung: vom Docker-Compose-Setup mit mehreren Domains über Nginx-Vhosts bis zu store-spezifischen Fixtures. Das Ziel ist eine lokale Instanz, die sich exakt wie Produktion verhält, nur eben auf dem eigenen Rechner.
2. Docker-Compose-Setup für mehrere Websites
Der erste Baustein einer Multi-Store-Entwicklungsumgebung ist die Docker-Konfiguration selbst. Mit dem Mark-Shust-Setup läuft ohnehin nur ein einziger Magento-Container, unabhängig davon, wie viele Websites im Backend definiert sind, denn Magento löst Websites über Domains und den MAGE_RUN_CODE, nicht über getrennte Prozesse auf. Die eigentliche Arbeit passiert also nicht in zusätzlichen Containern, sondern in der Nginx-Konfiguration und in zusätzlichen Host-Einträgen, die alle auf denselben PHP-FPM-Upstream zeigen.
Trotzdem lohnt sich ein eigener Docker-Service für einen zweiten Nginx-Vhost, wenn die Domains unterschiedliche SSL-Zertifikate oder Ports brauchen. In den meisten Fällen reicht aber ein einziger Nginx-Container mit mehreren server-Blöcken, jeweils einer pro Store-Domain. Wichtig ist, dass alle Domains in derselben Docker-Netzwerkbrücke landen und über denselben fastcgi_pass an PHP-FPM weitergereicht werden, damit Sessions, Cache und Datenbank konsistent bleiben.
#!/usr/bin/env bash
# Extend the existing Mark Shust docker-compose with additional domains
# for a Magento 2 multi-store development environment
# 1. Add all store domains to /etc/hosts (or use dnsmasq for wildcard domains)
echo "127.0.0.1 shop-de.test shop-at.test shop-en.test" | sudo tee -a /etc/hosts
# 2. Generate a self-signed cert covering all local store domains
bin/generate-cert shop-de.test shop-at.test shop-en.test
# 3. Restart nginx so it picks up the additional server blocks
bin/restart nginx
# 4. Verify all three domains resolve to the same Magento container
for domain in shop-de.test shop-at.test shop-en.test; do
curl -sk -o /dev/null -w "%{http_code} $domain\n" "https://$domain/"
done
3. Domains und Hosts-Datei für Store Views
Jede Store View in einer sauberen Multi-Store-Entwicklungsumgebung braucht eine eigene, auflösbare Domain, denn Magentos URL-Erkennung basiert primär auf dem angefragten Host. Lokal übernimmt die /etc/hosts-Datei diese Aufgabe: Jede Store-Domain wird dort auf 127.0.0.1 gemappt, sodass der Browser die Anfrage an den lokalen Docker-Container schickt, Magento aber anhand des Hostnamens erkennt, welche Store View gemeint ist.
Ein häufiger Stolperstein: Entwickler nutzen für alle Stores dieselbe lokale Domain mit unterschiedlichen Pfaden wie localhost/de und localhost/at. Das mag für einfache Sprachumschaltung funktionieren, deckt aber keine Bugs ab, die auf der tatsächlichen Domain-Erkennung basieren, etwa Cookie-Scoping, CORS-Header bei GraphQL-Anfragen oder Store-spezifische Redirects. Für eine belastbare Multi-Store-Entwicklungsumgebung sind separate Top-Level-Domains wie shop-de.test und shop-at.test die einzige Variante, die Produktionsverhalten wirklich abbildet.
Die Endung .test ist dabei kein Zufall: Sie ist laut RFC 2606 für lokale Testzwecke reserviert und kollidiert nie mit echten öffentlichen Domains. Zertifikate für diese Domains lassen sich mit mkcert oder dem Docker-eigenen generate-cert-Kommando erzeugen, sodass auch HTTPS-abhängige Features wie Service Worker oder Payment-SDKs lokal korrekt getestet werden können.
4. Nginx-Vhosts und MAGE_RUN_CODE
Der eigentliche Kern der Domain-Auflösung liegt im Zusammenspiel von Nginx-Vhost und dem Umgebungsparameter MAGE_RUN_CODE. Jeder server-Block in der Nginx-Konfiguration entspricht einer Store-Domain und setzt fastcgi_param MAGE_RUN_CODE sowie MAGE_RUN_TYPE auf den jeweiligen Store- oder Website-Code. Magento liest diese beiden Parameter beim Bootstrap aus und lädt exakt die zugehörige Store-Konfiguration, unabhängig davon, was in der URL selbst steht.
In einer Multi-Store-Entwicklungsumgebung muss diese Konfiguration konsistent mit den Store-Codes im Backend sein. Ein Tippfehler im MAGE_RUN_CODE führt nicht zu einem Fehler, sondern zum stillen Fallback auf den Default-Store, was besonders tückisch ist, weil alles funktioniert, nur eben mit den falschen Daten. Deshalb sollte der Store-Code aus der Nginx-Konfiguration regelmäßig mit bin/magento store:list abgeglichen werden.
# nginx vhost snippet for one store domain in a multi-store setup
server {
listen 443 ssl;
server_name shop-at.test;
ssl_certificate /etc/nginx/certs/shop-at.test.pem;
ssl_certificate_key /etc/nginx/certs/shop-at.test.key;
set $MAGE_ROOT /var/www/html;
set $MAGE_MODE developer;
include /etc/nginx/magento.conf;
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_param MAGE_RUN_CODE "store_at";
fastcgi_param MAGE_RUN_TYPE "store";
include fastcgi_params;
include fastcgi.conf;
}
}
5. app/etc/config.php und store-spezifische Werte
Deklaratives Konfigurationsmanagement über app/etc/config.php ist ein zentraler Baustein jeder Multi-Store-Entwicklungsumgebung, weil damit alle store-spezifischen Systemkonfigurationswerte versioniert werden können, statt nur in der Datenbank zu existieren. Nach bin/magento app:config:dump landen Werte wie Payment-Methoden, Versandkonfiguration und Basis-URLs pro Scope in dieser Datei, und jeder Entwickler bekommt beim Checkout identische Store-Konfigurationen, ohne Datenbank-Dumps austauschen zu müssen.
Der Scope-Mechanismus in config.php folgt der Hierarchie Default, Website, Store, wobei speziellere Scopes generellere überschreiben. Für eine Multi-Store-Entwicklungsumgebung bedeutet das: Basis-URLs werden pro Store gesetzt, während gemeinsame Einstellungen wie der Produktkatalog-Cache im Default-Scope bleiben. Diese Trennung macht sofort sichtbar, welche Konfiguration wirklich store-spezifisch ist und welche versehentlich dupliziert wurde.
<?php
// Excerpt from app/etc/config.php after app:config:dump
// Shows how store-specific base URLs are stored per scope
return [
'system' => [
'default' => [
'web' => [
'secure' => [
'base_url' => 'https://shop-de.test/',
],
],
],
'websites' => [
'website_at' => [
'web' => [
'secure' => [
'base_url' => 'https://shop-at.test/',
],
],
'general' => [
'locale' => [
'code' => 'de_AT',
],
],
],
],
'stores' => [
'store_en' => [
'general' => [
'locale' => [
'code' => 'en_GB',
],
],
],
],
],
];
Ein häufiger Fehler bei der Arbeit mit config.php in einer Multi-Store-Entwicklungsumgebung: Entwickler bearbeiten Werte direkt in der Datenbank über den Adminbereich, ohne anschließend einen neuen Dump zu erzeugen. Die Datei driftet dann von der tatsächlichen Konfiguration ab, und beim nächsten Deployment werden die manuellen Änderungen überschrieben. Der korrekte Workflow ist immer: Änderung im Admin, danach app:config:dump, danach Commit der Datei.
6. Website, Store Group und Store View anlegen
Magentos Store-Hierarchie besteht aus drei Ebenen: Website, Store Group und Store View. Die Website definiert die technische Trennung, etwa unterschiedliche Domains oder Zahlungsanbieter. Die Store Group bündelt Store Views, die sich einen Produktkatalog teilen. Die Store View selbst ist die kleinste Einheit und steuert Sprache, Theme und Sichtbarkeit. Für eine belastbare Multi-Store-Entwicklungsumgebung müssen alle drei Ebenen lokal existieren, nicht nur eine einzelne Store View mit umgeschalteter Sprache.
Die Erstellung erfolgt über Stores > All Stores im Adminbereich oder per CLI-Skript, das über die WebsiteRepositoryInterface, GroupRepositoryInterface und StoreRepositoryInterface läuft. Für lokale Setups empfiehlt sich ein reproduzierbares PHP-Skript oder ein Data-Patch, der beim Setup der Multi-Store-Entwicklungsumgebung automatisch die komplette Hierarchie anlegt, statt sie manuell im Backend nachzubauen. Das macht das Setup für neue Teammitglieder in Minuten statt Stunden reproduzierbar.
Wichtig ist die korrekte Root-Category-Zuweisung pro Store View, denn eine falsch zugeordnete Root-Category führt zu leeren Kategoriebäumen im Frontend, obwohl die Produkte in der Datenbank vorhanden sind. Dieser Fehler tritt in Multi-Store-Entwicklungsumgebungen besonders häufig auf, wenn Store Views per Copy-Paste im Backend angelegt werden und die Root-Category dabei versehentlich vom Default-Store übernommen wird.
7. Sprachen, Währungen und Locale je Store View
Sobald die Hierarchie steht, folgt die eigentliche Store-View-Konfiguration: Locale-Code, Basiswährung, zulässige Währungen und Zeitzone. Diese Werte werden unter General > Locale Options und General > Currency Setup pro Scope gesetzt und sind einer der häufigsten Gründe, warum Teams überhaupt eine Multi-Store-Entwicklungsumgebung brauchen: Ohne unterschiedliche Locales lassen sich Formatierungsfehler bei Preisen, Datumsangaben und Zahlenwerten nie lokal reproduzieren.
Ein konkretes Beispiel: Der deutsche Store nutzt de_DE mit Komma als Dezimaltrennzeichen, während der österreichische Store zwar dieselbe Sprache, aber eine eigene Preisanzeige mit anderer Mehrwertsteuer-Klasse braucht. Ohne getrennte Store Views mit eigenen Locale- und Steuerkonfigurationen wird dieser Unterschied erst in Produktion sichtbar, meist durch eine Kundenbeschwerde über einen falschen Endpreis.
Für Sprachübersetzungen selbst sollte die Multi-Store-Entwicklungsumgebung zusätzlich die passenden i18n-Pakete installiert haben (bin/composer require magento/language-de_at zum Beispiel), damit auch Backend-Übersetzungen und Systemmeldungen store-korrekt getestet werden können, nicht nur Frontend-Texte aus CMS-Blöcken.
8. Testdaten und Fixtures pro Store
Realistische Testdaten sind der letzte fehlende Baustein. Eine Multi-Store-Entwicklungsumgebung ohne store-spezifische Produktpreise, Kategoriesichtbarkeiten und Lagerbestände testet zwar die Konfiguration, aber nicht das eigentliche Geschäftsverhalten. Magentos Testing Framework bietet dafür Fixtures, die gezielt auf einen Store-Scope angewendet werden können, etwa #storeView store_at als Annotation in einem MFTF-Test oder direkt als Parameter beim Import über CSV.
Für den täglichen Entwicklungsalltag lohnt sich ein Data-Patch, der pro Store unterschiedliche Preise, Sonderangebote und Sichtbarkeiten für dieselben Test-SKUs setzt. So lässt sich mit wenigen Klicks zwischen den Store Views wechseln und sofort sehen, ob eine neue Preisregel oder ein neues Layout-Update store-übergreifend konsistent funktioniert.
<?php
declare(strict_types=1);
namespace Mironsoft\DevFixtures\Setup\Patch\Data;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Store\Api\StoreRepositoryInterface;
/**
* Sets store-specific prices for the shared demo SKU across all
* store views in the local multi-store development environment.
*/
class SetStoreSpecificPrices implements DataPatchInterface
{
/**
* @param ModuleDataSetupInterface $moduleDataSetup Module setup helper
* @param ProductRepositoryInterface $productRepository Product repository
* @param StoreRepositoryInterface $storeRepository Store repository
*/
public function __construct(
private readonly ModuleDataSetupInterface $moduleDataSetup,
private readonly ProductRepositoryInterface $productRepository,
private readonly StoreRepositoryInterface $storeRepository,
) {
}
/**
* Applies the data patch.
*
* @return void
*/
public function apply(): void
{
$prices = ['store_de' => 49.90, 'store_at' => 54.90, 'store_en' => 44.90];
foreach ($prices as $storeCode => $price) {
$store = $this->storeRepository->get($storeCode);
$product = $this->productRepository->get('demo-sku', true, $store->getId());
$product->setPrice($price);
$this->productRepository->save($product);
}
}
/**
* @return array
*/
public static function getDependencies(): array
{
return [];
}
/**
* @return array
*/
public function getAliases(): array
{
return [];
}
}
9. Single-Store vs. Multi-Store im Vergleich
Der Unterschied zwischen einer Single-Store- und einer echten Multi-Store-Entwicklungsumgebung zeigt sich am deutlichsten bei den Fehlerklassen, die jeweils gefunden werden. Die folgende Tabelle stellt beide Ansätze gegenüber.
| Aspekt | Single-Store Setup | Multi-Store-Entwicklungsumgebung |
|---|---|---|
| Domain-Erkennung | Wird nie getestet | Vollständig abgedeckt |
| Store-spezifische Preise | Nicht reproduzierbar | Über Fixtures abgebildet |
| Locale- und Steuerbugs | Erst in Staging sichtbar | Lokal reproduzierbar |
| Setup-Aufwand | Gering | Einmalig höher, danach amortisiert |
| Cache- und Session-Scoping | Nicht getestet | Realistisch abgebildet |
Der einmalige Mehraufwand beim Aufbau der Multi-Store-Entwicklungsumgebung amortisiert sich bereits nach wenigen Sprints, sobald das erste store-spezifische Bugticket lokal statt in Produktion reproduziert werden kann. Teams, die regelmäßig mehrere Websites betreuen, sollten dieses Setup fest im Onboarding-Prozess neuer Entwickler verankern.
Mironsoft
Magento-2-Entwicklung, Multi-Store-Architektur und Hyvä-Themes
Multi-Store-Setup, das Bugs findet, bevor Kunden sie melden?
Wir bauen lokale Multi-Store-Entwicklungsumgebungen auf, die eure Produktions-Websites, Domains und Store Views exakt nachbilden, inklusive Docker, Nginx-Vhosts und store-spezifischer Testdaten.
Umgebungs-Audit
Bestehende Dev-Umgebung auf Multi-Store-Tauglichkeit prüfen
Setup-Automatisierung
Data-Patches und Skripte für reproduzierbare Store-Hierarchien
Onboarding
Neue Entwickler in Stunden statt Tagen produktiv machen
10. Zusammenfassung
Eine lokale Multi-Store-Entwicklungsumgebung ist kein Luxus für große Enterprise-Projekte, sondern die einzige Möglichkeit, store-spezifisches Verhalten zuverlässig zu testen, bevor es in Produktion Kunden betrifft. Der Aufbau folgt einem klaren Muster: eigene Domains pro Store View, Nginx-Vhosts mit korrektem MAGE_RUN_CODE, versionierte Konfiguration über app/etc/config.php und store-spezifische Fixtures für realistische Testdaten.
Der größte Denkfehler ist, Multi-Store nur als Sprachumschaltung zu betrachten. Echte Websites unterscheiden sich in Domains, Preisbüchern, Steuerklassen, Zahlungsanbietern und Cache-Scoping, und nur eine vollständige Multi-Store-Entwicklungsumgebung deckt diese Unterschiede lokal ab. Der einmalige Setup-Aufwand zahlt sich bereits beim ersten store-übergreifenden Bugfix aus.
Multi-Store-Entwicklungsumgebung für Magento 2 — Das Wichtigste auf einen Blick
Domains
Eigene .test-Domain pro Store View in /etc/hosts, keine Pfad-basierte Sprachumschaltung.
Nginx und MAGE_RUN_CODE
Ein Vhost pro Domain mit korrektem MAGE_RUN_CODE, sonst stiller Fallback auf den Default-Store.
Konfiguration
app/etc/config.php nach jedem Admin-Change neu dumpen und committen, sonst driftet die Konfiguration.
Fixtures
Data-Patches mit store-spezifischen Preisen und Sichtbarkeiten für reproduzierbare Tests.