Shopware 6 Caching richtig konfigurieren: HTTP-Cache, Reverse Proxy, Redis
Der HTTP-Cache ist laut Shopware ein Muss für jedes Produktivsystem. Wie er arbeitet, wo er seine Daten ablegt und was Redis und Varnish dazu beitragen, ist aber über viele Seiten der Entwicklerdoku verteilt. Dieser Artikel ordnet die drei Ebenen ein, zeigt die Konfiguration für Shopware 6.7 und erklärt, warum ein Cache-Redis volllaufen kann, obwohl alles richtig eingestellt ist.
Kurz gesagt
HTTP-Cache mit SHOPWARE_HTTP_CACHE_ENABLED=1 einschalten. Auf einem Server reicht das Dateisystem, bei mehr Last oder mehreren Servern gehört der Cache in Redis. Sessions und Warenkörbe kommen in eigene Redis-Instanzen, die ihre Daten sichern. Seit 6.7 leert cache:clear den HTTP-Cache nicht mehr, und Änderungen erscheinen mit bis zu fünf Minuten Verzögerung.
1. Drei Ebenen, die oft verwechselt werden
HTTP-Cache
Ganze Seiten der Storefront, etwa Produkt- und Kategorieseiten. Ein Treffer spart den kompletten Aufbau der Seite.
Im App-Cache von Shopware, standardmäßig im Dateisystem unter var/cache, oder in einem Reverse Proxy wie Varnish oder Fastly.
Objekt-Cache
Daten, die Shopware beim Aufbau einer Seite immer wieder braucht, zum Beispiel Konfiguration, Textbausteine oder Theme-Einstellungen.
Ebenfalls im App-Cache, also im Dateisystem oder in Redis.
Sitzungs- und Shopdaten
Sessions, Warenkörbe, Nummernkreise und Sperren. Das ist kein Cache, sondern Daten, die nicht verloren gehen dürfen.
Standardmäßig in der Datenbank oder im PHP-Session-Speicher, bei mehr Last in Redis.
Die Unterscheidung ist wichtig, weil die drei Ebenen unterschiedlich behandelt werden müssen. Ein Cache darf jederzeit verloren gehen, Shopware baut ihn neu auf. Ein Warenkorb oder eine Session darf das nicht. Wer alles in eine einzige Redis-Instanz ohne Sicherung legt, riskiert bei einem Neustart leere Warenkörbe.
2. Der HTTP-Cache
Eingeschaltet wird er mit SHOPWARE_HTTP_CACHE_ENABLED=1 in der .env.local. Laut Shopware-Doku speichert er nur GET-Anfragen auf Seiten, die Shopware als cachebar markiert, etwa Produkt- und Kategorieseiten. Warenkorb, Checkout und Kundenkonto landen nicht im Cache.
Ein Cache für alle, solange nichts besonders ist
Damit ein eingeloggter Kunde mit Nettopreisen nicht die Seite eines Gasts sieht, setzt Shopware das Cookie sw-cache-hash. Es enthält einen Hash aus allem, was die Seite verändert: Login, Steuerstatus, Währung, passende Regeln. Solange ein Besucher nicht eingeloggt ist, die Standardwährung nutzt und einen leeren Warenkorb hat, gibt es das Cookie nicht, und alle teilen sich dieselben Cache-Einträge. Je mehr unterschiedliche Zustände in den Hash einfließen, desto mehr Varianten einer Seite entstehen und desto seltener trifft der Cache.
Was seit 6.7 anders ist
- Header und Footer per ESI: Sie werden über eigene Routen geladen und lassen sich dadurch getrennt vom Rest der Seite cachen. Themes und Plugins, die Header oder Footer erweitern, müssen dafür von den neuen Templates erben.
- Kein Store-API-Cache mehr: Die eigene Cache-Schicht für Store-API-Routen ist entfallen.
- Verzögerte Invalidierung: Shopware leert betroffene Einträge nicht sofort, sondern gesammelt, standardmäßig alle fünf Minuten über die geplante Aufgabe
shopware.invalidate_cache. Das bringt mehr Treffer und weniger doppelte Arbeit, eine geänderte Produktbeschreibung ist aber erst nach ein paar Minuten sichtbar.
Listing-Seiten wie Kategorien und Suchergebnisse leert Shopware ohnehin nicht bei jeder Produktänderung gezielt, sie laufen über ihre Laufzeit im Cache ab. Laut Doku nimmt Shopware hier bewusst ein wenig Verzögerung in Kauf, weil ein Produkt in unzähligen Filter- und Sortierkombinationen auftauchen kann.
Cache leeren
bin/console cache:clearLeert und wärmt den Anwendungscache. Den HTTP-Cache leert der Befehl seit 6.7 nicht mehr.
bin/console cache:clear:httpLeert nur den HTTP-Cache, bei aktivem Reverse Proxy dort, sonst im App-Cache. Seit 6.6.10.
bin/console cache:clear:allLeert alles, inklusive HTTP-Cache und Cache-Pools. Seit 6.6.8.
bin/console cache:pool:clear --allLeert nur den Objekt-Cache.
Wer nach einem Update aus Gewohnheit nur cache:clear ausführt, wundert sich unter 6.7 über alte Seiten. In Deployment-Skripten gehört deshalb geprüft, welcher Befehl dort steht.
3. Dateisystem oder Redis
Ohne weitere Konfiguration liegt der HTTP-Cache im Dateisystem unter var/cache. Laut Doku funktioniert das auf einem einzelnen Server ohne Zusatzaufwand, ist aber nicht die beste Wahl, sobald ein Load Balancer oder mehrere Server im Spiel sind. Dann braucht es einen gemeinsamen Cache, und das ist in der Regel Redis.
In meinen Projekten nutze ich bei kleineren Shops auf einem Server den HTTP-Cache im Dateisystem und bei größeren Redis für den Cache. Die Umstellung passiert in der config/packages/cache.yaml, die PHP-Erweiterung für Redis muss installiert sein:
framework:
cache:
app: cache.adapter.redis_tag_aware
system: cache.adapter.redis_tag_aware
default_redis_provider: 'redis://redis-cache:6379/0'Der Adapter redis_tag_aware ist wichtig, weil Shopware Cache-Einträge über Tags gemeinsam leert, etwa alle Seiten, auf denen ein bestimmtes Produkt vorkommt.
4. Redis für Sessions und Warenkorb
Die Redis-Doku von Shopware empfiehlt, Daten nach ihrer Art auf getrennte Redis-Instanzen zu verteilen. Der Grund: In einer Instanz lässt sich nur eine Eviction-Policy einstellen, also die Regel, welche Schlüssel Redis bei vollem Speicher zuerst löscht.
Cache
HTTP-Cache und Objekt-Cache
Keine Speicherung auf der Festplatte nötig, Eviction-Policy volatile-lru
Sessions
Sitzungen der Besucher
Auf der Festplatte sichern (RDB und AOF), Eviction-Policy allkeys-lru
Shopdaten
Warenkörbe, Nummernkreise, Sperren, Zähler
Auf der Festplatte sichern, Eviction-Policy volatile-lru
Sessions und Warenkorb lege ich in Projekten in Redis, getrennt vom Cache. Seit Shopware 6.6.8.0 definierst du die Verbindungen einmal in der config/packages/shopware.yaml und verweist dann darauf:
shopware:
redis:
connections:
persistent:
dsn: 'redis://redis-data:6379/0?persistent=1'
cart:
storage:
type: 'redis'
config:
connection: 'persistent'Der Zusatz ?persistent=1 betrifft die Verbindung, nicht die Speicherung der Daten. Ob Redis die Daten auf die Festplatte schreibt, stellst du in Redis selbst ein. Bestehende Warenkörbe aus der Datenbank übernimmt bin/console cart:migrate sql, ohne dass Kunden ihren Warenkorb verlieren. Die Sessions laufen über Symfony in der config/packages/framework.yaml:
framework:
session:
handler_id: 'redis://redis-session:6379/0'5. Wenn der Cache-Redis volläuft
Ein Cache-Redis, der sein Speicherlimit erreicht, ist laut Doku normal. Mit volatile-lru löscht er die am längsten nicht genutzten Einträge, die eine Ablaufzeit haben. Das Problem entsteht bei Einträgen ohne Ablaufzeit, die Redis nie löschen darf.
Genau solche Einträge erzeugt der Tag-Index. Für jeden Cache-Tag speichert Symfony eine Liste der Einträge, die dazugehören, und diese Listen laufen nie ab. Läuft ein Cache-Eintrag ab, bleibt sein Verweis in der Liste stehen. Bei viel Verkehr wachsen diese verwaisten Verweise, bis Redis nichts mehr hat, was es löschen darf, und mit „OOM command not allowed“ abbricht. Das habe ich selbst erlebt.
Ob das die Ursache ist, zeigt redis-cli INFO keyspace: Ist die Zahl der Schlüssel (keys) deutlich größer als die Zahl mit Ablaufzeit (expires), liegt der Verdacht nahe. Mehr Speicher verschiebt das Problem nur. Die Lösung laut Doku ist ein regelmäßiges Aufräumen, etwa jede Nacht per Cronjob, mit dem Befehl frosh:redis-tag:cleanup aus dem Plugin FroshTools oder mit dem eigenständigen Werkzeug shopware-redis-cli-helper.
6. Reverse Proxy: Varnish und Fastly
Ein Reverse Proxy sitzt vor Shopware und beantwortet Treffer, bevor die Anfrage die Anwendung erreicht. Der HTTP-Cache liegt dann nicht mehr im App-Cache, sondern im Proxy. Shopware unterstützt laut Doku Varnish und Fastly. Beide teilen sich dieselben Cache-Tags wie der Objekt-Cache, eine Produktänderung leert also auch den Proxy.
Seit 6.7 braucht Varnish das Modul XKey. Die frühere Variante, die Tags für Varnish in Redis zu speichern, ist entfallen. Die Grundkonfiguration in Shopware sieht so aus:
shopware:
http_cache:
reverse_proxy:
enabled: true
use_varnish_xkey: true
hosts:
- 'http://varnish'Dazu kommt SYMFONY_TRUSTED_PROXIES in der .env, damit Shopware die echte IP-Adresse und das Protokoll der Besucher erkennt. Für den Einstieg bietet Shopware ein vorkonfiguriertes Varnish-Docker-Image mit der passenden VCL an. Antwortet Varnish immer mit Age: 0, cacht er nichts. Meist fehlt dann der Header Cache-Control: public in der Antwort von Shopware, weil der Reverse-Proxy-Modus nicht aktiv ist.
7. Kurz geprüft: arbeitet der Cache?
- Eine Kategorieseite zweimal im privaten Browserfenster laden. Die zweite Antwort muss deutlich schneller kommen, sichtbar an der Time to First Byte in den Entwicklertools.
- Im Warenkorb einen Artikel ablegen und prüfen, ob das Cookie
sw-cache-hashgesetzt wird. - Ein Produkt im Admin ändern und nach spätestens fünf Minuten prüfen, ob die Produktseite die Änderung zeigt. Wenn nicht, läuft vermutlich die geplante Aufgabe nicht, etwa weil kein Worker für geplante Aufgaben aktiv ist.
- Bei Redis:
INFO keyspaceregelmäßig ansehen und die Zahl der Schlüssel ohne Ablaufzeit im Blick behalten.
Caching ist der wichtigste Hebel auf dem Server, aber nicht der einzige. Die übrigen Einstellungen für PHP, Logging und das Frontend stehen in der Checkliste Shopware 6 Performance optimieren. Wer ein Headless-Frontend mit Next.js betreibt, findet das Gegenstück im Artikel zu Next.js ISR für Shopware.
8. Häufige Fragen zum Caching in Shopware
Wie aktiviere ich den HTTP-Cache in Shopware 6?
Mit SHOPWARE_HTTP_CACHE_ENABLED=1 in der .env.local. Ohne weitere Konfiguration speichert Shopware die Seiten im Dateisystem unter var/cache. Für einen Shop auf einem Server reicht das, bei mehreren Servern gehört der Cache in Redis oder in einen Reverse Proxy.
Warum sehe ich meine Änderung nicht sofort im Shop?
Seit Shopware 6.7 werden Cache-Einträge verzögert invalidiert, standardmäßig alle fünf Minuten über die geplante Aufgabe shopware.invalidate_cache. Listing-Seiten wie Kategorien und Suchergebnisse verlassen sich außerdem auf ihre Laufzeit im Cache und werden nicht bei jeder Produktänderung gezielt geleert.
Brauche ich Varnish für Shopware?
Nein. Der eingebaute HTTP-Cache funktioniert ohne Zusatzdienst. Ein Reverse Proxy wie Varnish oder Fastly nimmt den Cache aus der Anwendung heraus und beantwortet Treffer, bevor die Anfrage Shopware erreicht. Seit 6.7 braucht Varnish dafür das XKey-Modul.
Welcher Befehl leert den Cache in Shopware 6.7?
bin/console cache:clear leert seit 6.7 nur noch den Anwendungscache. Für den HTTP-Cache gibt es bin/console cache:clear:http, für alles zusammen bin/console cache:clear:all.
Stand: Shopware 6.7.15. Grundlage sind die Entwicklerdoku zu HTTP-Cache, Caches, Redis und Reverse Proxy sowie das Upgrade-Dokument zu 6.7. Die Hostnamen in den Beispielen sind Platzhalter.
Dein Shop ist trotz Cache langsam?
In einem kurzen Call schauen wir uns Cache, Redis und Server-Setup deines Shops an, mit konkreten nächsten Schritten.
Schriftlich oder im Gespräch — 15 Minuten, unverbindlich.
Newsletter
Mehr davon? Jeden Montag ein Shopware-Thema
Jeden Montag: mein neuer Blog-Artikel plus ein, zwei kurze News aus der Shopware-Welt.
Zum Start als Dankeschön: der Shopware-Update-Check – 30 Prüfpunkte, mit denen du dein nächstes Shopware-Update sauber planst.