Shopware-Staging mit Docker: Live-Bilder ohne Gigabyte-Sync nutzen

Wie ein Dockware-Setup mit nginx-Proxy lokal läuft und Media-Dateien per 302-Weiterleitung direkt aus dem Live-Shop zieht — keine Gigabyte-Downloads, immer aktuelles Bildmaterial.

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 RewriteRule in der public/.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.conf fü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:

  1. Die DATABASE_URL in der .env wird auf den eigenen DB-Container umgebogen.
  2. In die public/.htaccess werden direkt nach RewriteEngine On die Media-Proxy-Regeln eingefügt.
  3. Nach 30 Sekunden Warmlauf werden Theme-Compile, assets:install und 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]
  • !-f heiß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=302 statt 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

  1. Eintrag in der /etc/hosts (bzw. C:\Windows\System32\drivers\etc\hosts):
    127.0.0.1 shopwareshop.de
  2. Datenbank-Dump vom Live-Shop einspielen (mysql -u root -p shopware < dump.sql). Die DB-Struktur muss zur installierten Shopware-Version passen.
  3. Storage-Konfiguration in der .env bzw. unter config/services.yaml auf 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