Wer einen Shopware-Shop ernsthaft entwickelt, kennt das Problem: das Live-System hat 30 GB
Produktbilder im public/media/-Ordner, dazu eine ähnliche Menge an Thumbnails.
Für jedes Staging diesen Berg zu synchronisieren ist langsam, teuer und nach drei Tagen
wieder veraltet. Schneller geht es, wenn die Staging-Instanz Bilder einfach direkt aus
dem Live-Shop nachlädt — und nur dann, wenn lokal kein Bild vorhanden ist.
Das Setup auf einen Blick
Drei Container per docker-compose: ein nginx-Proxy mit Self-Signed-Zertifikat,
ein Dockware-Dev-Image mit Shopware 6.7 und eine MariaDB. Der Trick
steckt in zwei Stellen:
- Ein
RewriteRulein derpublic/.htaccess, das alle Requests auf/media/*und/thumbnail/*per 302 auf den Live-Shop schickt — aber nur, wenn die Datei lokal nicht existiert. - Eine eigene
dev.conffür den nginx-Proxy, die HTTPS, Admin-Port 8888 und Mailhog-Port 9998 sauber durchreicht.
docker-compose.yml
version: "3.8"
services:
proxy:
container_name: proxy
image: dockware/proxy:latest
ports:
- "80:80"
- "443:443"
depends_on:
- shopwareshop
restart: always
volumes:
- "./dev.conf:/etc/nginx/conf.d/shop-1.conf"
shopwareshop:
image: dockware/dev:6.7.0.0
container_name: shopwareshop
environment:
- SHOP_DOMAIN=shopwareshop.de
entrypoint:
- bash
- -c
- |
sed -i 's|DATABASE_URL=.*|DATABASE_URL=mysql://shopuser:secret@db:3306/shopware|' /var/www/html/.env
sed -i '/RewriteEngine On/a\
\
# Proxy fuer Media/Thumbnail zum Live-Shop\
RewriteCond %{REQUEST_FILENAME} !-f\
RewriteCond %{REQUEST_URI} ^/(media|thumbnail)/ [NC]\
RewriteRule ^(media|thumbnail)/(.*)$ https://www.liveshop.de/$1/$2 [L,R=302,NC]' /var/www/html/public/.htaccess
/entrypoint.sh &
sleep 30
cd /var/www/html && bin/console theme:compile && bin/console assets:install && bin/console cache:clear
wait
volumes:
- "./git/button-king-6/custom:/var/www/html/custom"
- "./dev_bk/media:/var/www/html/public/media"
- "./dev_bk/thumbnail:/var/www/html/public/thumbnail"
db:
image: mariadb
container_name: mariadbshop
environment:
- MYSQL_ROOT_PASSWORD=hidden
- MYSQL_USER=dbuser
- MYSQL_PASSWORD=dbpassword
- MYSQL_DATABASE=shopware
volumes:
- "./mysqlconf:/etc/mysql/conf.d"
Warum das Entrypoint-Script so wichtig ist
Im shopwareshop-Service wird der Standard-Entrypoint überschrieben. Bevor Dockware den
eigentlichen Container startet, passieren drei Dinge:
- Die
DATABASE_URLin der.envwird auf den eigenen DB-Container umgebogen. - In die
public/.htaccesswerden direkt nachRewriteEngine Ondie Media-Proxy-Regeln eingefügt. - Nach 30 Sekunden Warmlauf werden Theme-Compile,
assets:installund Cache-Clear ausgeführt.
Wichtig: Das ist kein Apache-Reverse-Proxy, sondern eine simple Redirect-Regel. Der Browser
bekommt die 302 zurück und holt das Bild selbst von www.liveshop.de. Vorteil: kein zusätzlicher
Apache-Modul-Overhead, keine offene Ausgangs-Verbindung pro Request, keine Bandbreite auf der
Staging-Maschine.
Die zwei Bedingungen sind das eigentliche Feature
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} ^/(media|thumbnail)/ [NC]
RewriteRule ^(media|thumbnail)/(.*)$ https://www.liveshop.de/$1/$2 [L,R=302,NC]
!-fheißt: Datei existiert lokal nicht. Wenn man also für eine bestimmte Kategorie schon Bilder ins gemountete Volume legt, gewinnen die — der Proxy springt erst ein, wenn lokal nichts da ist.^/(media|thumbnail)/beschränkt die Regel ausschließlich auf die zwei Shopware-Pfade. Bundles, statische Assets und Plugin-Resources bleiben unberührt.R=302statt 301 ist Absicht: nicht permanent cachen. Sonst zeigt der Browser auch nach lokalem Upload weiter auf den Live-Shop.
dev.conf — der nginx-Proxy
Dockware lauscht intern auf 80, 443, 8888 (Admin-UI) und 9998 (Mailhog). Die dev.conf
legt davor einen einzigen sauberen Eingang mit selbst-signiertem TLS:
server {
listen 80;
server_name shopwareshop.de;
location / {
proxy_pass https://shopwareshop;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
}
}
server {
listen 443 ssl;
server_name shopwareshop.de;
ssl_certificate /etc/nginx/ssl/selfsigned.crt;
ssl_certificate_key /etc/nginx/ssl/selfsigned.key;
location / {
proxy_pass https://shopwareshop;
}
}
server {
listen 8888 ssl;
server_name shopwareshop.de;
ssl_certificate /etc/nginx/ssl/selfsigned.crt;
ssl_certificate_key /etc/nginx/ssl/selfsigned.key;
location /admin { proxy_pass http://shopwareshop:8888; }
location /static { proxy_pass http://shopwareshop:8888; }
location /api { proxy_pass http://shopwareshop; }
location / { proxy_pass http://shopwareshop:8888; }
}
server {
listen 9998;
server_name shopwareshop.de;
location / {
proxy_set_header Host localhost;
proxy_pass http://shopwareshop:9998;
}
}
Damit ist die Storefront unter https://shopwareshop.de erreichbar, das Admin-Panel
unter https://shopwareshop.de:8888/admin und Mailhog unter
http://shopwareshop.de:9998.
Was lokal noch zu tun ist
-
Eintrag in der
/etc/hosts(bzw.C:\Windows\System32\drivers\etc\hosts):127.0.0.1 shopwareshop.de -
Datenbank-Dump vom Live-Shop einspielen (
mysql -u root -p shopware < dump.sql). Die DB-Struktur muss zur installierten Shopware-Version passen. -
Storage-Konfiguration in der
.envbzw. unterconfig/services.yamlauf lokales Filesystem stellen — sonst zeigen URLs auf einen S3-Bucket, der die Redirect-Regel umgeht.
Was zu beachten ist
1. DSGVO: Wenn der Live-Shop kunden-individuelle Uploads (B2B-Datenblätter, signierte Verträge,
Reklamationsbilder) im /media/-Pfad ablegt, lädt jeder Aufruf der Staging-URL diese Dateien
beim Live-System nach. Für reine Produktbilder unkritisch. Sobald personenbezogene Inhalte dabei sind,
gehört der Pfad-Filter feinjustiert (z. B. nur /media/produkt/* redirecten).
2. Bildänderungen werden „verschluckt": Wenn im Live-Shop ein Produktbild ausgetauscht wird,
die Datenbank im Staging aber älter ist, fragt Shopware nach dem alten Dateinamen, der live nicht mehr
existiert. Lösung: Datenbank vor jedem Test frisch ziehen, oder einen 404-Fallback im
RewriteRule akzeptieren.
3. Niemals in Produktion: Die Regel ist für Dev und Staging gedacht. In Produktion gehört der echte Storage-Layer (Filesystem, S3, CDN) konfiguriert — Self-Redirects auf den eigenen Live-Host wären eine Endlosschleife.
4. Self-Signed-Zertifikat: Browser warnen bei shopwareshop.de. Für Tests einmal
akzeptieren, oder das Zertifikat via mkcert als lokal vertrauenswürdig markieren.
5. Theme-Compile dauert: Das sleep 30 im Entrypoint ist ein pragmatischer Hack, kein
sauberes Healthcheck-Pattern. Bei langsameren Maschinen lieber auf 60 Sekunden hochziehen oder einen
echten Wait-On-Loop einbauen.
Wann sich das wirklich lohnt
Bei kleinen Shops mit wenigen hundert MB Mediathek nicht. Da reicht ein rsync. Spannend wird
der Trick ab dem Punkt, wo eine Vollkopie länger als der Kaffee dauert oder die Festplatte des Dev-Rechners
sprengt — also bei Shops ab ein paar tausend Produkten mit Lifestyle-Bildern, Konfigurator-Renderings oder
PDF-Datenblättern. Plus: das Setup eignet sich hervorragend für CI-Container, die einen frisch geklonten
Shop in < 2 Minuten aufstellen müssen.
Brauchen Sie ein verlässliches Staging-Setup?
Egal ob Dockware, eigene Compose-Files oder CI-gestützte Pipelines — ich richte Shopware-Stagings so ein, dass sie wirklich nutzbar bleiben.
Anfrage senden