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. Diesen Berg für jedes Staging zu synchronisieren ist langsam, teuer und nach drei Tagen wieder veraltet. Schneller geht es, wenn die Staging-Instanz Bilder direkt aus dem Live-Shop nachlädt, und zwar 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 an zwei Stellen:

  • Eine RewriteRule in der public/.htaccess, die 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 einfache Redirect-Regel. Der Browser bekommt die 302 zurück und holt das Bild selbst von www.liveshop.de. Das spart zusätzlichen Apache-Modul-Overhead, vermeidet eine offene Ausgangsverbindung pro Request und belastet die Bandbreite der Staging-Maschine nicht.

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: Die Datei existiert lokal nicht. Liegen für eine bestimmte Kategorie schon Bilder im gemounteten Volume, gewinnen die. Der Proxy springt erst ein, wenn lokal nichts vorhanden ist.
  • ^/(media|thumbnail)/ beschränkt die Regel auf die zwei Shopware-Pfade. Bundles, statische Assets und Plugin-Resources bleiben unberührt.
  • R=302 statt 301 ist Absicht, damit der Browser den Redirect nicht permanent cacht. Sonst zeigt er auch nach einem lokalen 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: Legt der Live-Shop kundenindividuelle Uploads (B2B-Datenblätter, signierte Verträge, Reklamationsbilder) im /media/-Pfad ab, lädt jeder Aufruf der Staging-URL diese Dateien beim Live-System nach. Für reine Produktbilder ist das unkritisch. Sobald personenbezogene Inhalte dabei sind, gehört der Pfad-Filter feinjustiert (etwa nur /media/produkt/* redirecten).

2. Bildänderungen werden „verschluckt": Wird im Live-Shop ein Produktbild ausgetauscht, die Datenbank im Staging ist aber älter, fragt Shopware nach dem alten Dateinamen, den es live nicht mehr gibt. Lösung: die Datenbank vor jedem Test frisch ziehen oder einen 404-Fallback in der RewriteRule akzeptieren.

3. Niemals in Produktion: Die Regel ist für Dev und Staging gedacht. In Produktion gehört der echte Storage-Layer konfiguriert (Filesystem, S3, CDN); 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. Auf langsameren Maschinen besser auf 60 Sekunden erhöhen 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. Interessant wird der Ansatz, sobald eine Vollkopie spürbar Zeit frisst oder die Festplatte des Dev-Rechners sprengt, also bei Shops ab einigen tausend Produkten mit Lifestyle-Bildern, Konfigurator-Renderings oder PDF-Datenblättern. Dazu kommt: Das Setup eignet sich gut für CI-Container, die einen frisch geklonten Shop in unter zwei Minuten aufstellen müssen.

Brauchen Sie ein verlässliches Staging-Setup?

Ob Dockware, eigene Compose-Files oder CI-gestützte Pipelines: Ich richte Shopware-Stagings so ein, dass sie wirklich nutzbar bleiben.

Anfrage senden