PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Expires-Header und Komprimierung aktivieren im Apache2

with 19 comments

Wie wir alle wissen kann man die größten Performanceverbesserungen auf der Browserseite erreichen. Ich habe bereits das Zusammenfassen von CSS- und Javascript-Dateien vorgestellt, ebenso wie das Zusammenfassen von Bildern in CSS-Sprites. Damit wird die Anzahl der Request schonmal reduziert. Aber es gibt natürlich noch mehr zu tun, beispielsweise die Requests noch weiter reduzieren durch gute Cache-Einstellungen, die wir an den Brower senden. Das werde ich hier vorstellen ebenso wie die Komprimierung mittels gzip/deflate der Dateien, die dann noch heruntergeladen werden müssen.

Cache-Einstellungen werden via HTTP-Header an den Browser mitgesendet. Zum Beispiel der Expires-Header, der angibt wie lange der Browser eine Datei cachen soll bevor er nach einer neuen Version fragt. Diese Cachedauer setzt man je nach Dateityp relativ hoch auf mehrere Tage.

Damit die unten stehenden Anweisungen vom Apache interpretiert werden können muss man das „Expires-Modul“ aktivieren, häufig kann man das wie folgt erledigen:

a2enmod expires

Hier die entsprechenden Apache-Einstellungen, die man entweder global im Apache einstellen kann, oder im entsprechenden vhost der Domain oder aber in der .htaccess-Datei speziell für Ordner:

<IfModule mod_expires.c>
    # turn on the module for this directory
    ExpiresActive on
    # set default
    ExpiresDefault "access plus 24 hours"

    # cache common graphics
    ExpiresByType image/jpg "access plus 1 months"
    ExpiresByType image/gif "access plus 1 months"
    ExpiresByType image/jpeg "access plus 1 months"
    ExpiresByType image/png "access plus 1 months"

    # cache CSS
    ExpiresByType text/css "access plus 1 months"

    # cache other filetypes
    ExpiresByType text/javascript "access plus 1 months"
    ExpiresByType application/javascript "access plus 1 months"
    ExpiresByType application/x-shockwave-flash "access plus 1 months"
</IfModule>

Mit dem Firefox-Addon Firebug kann man sich das Ergebnis anschauen:

Wie man im obigen Bild sehen kann wurde diese Datei auch gzip-komprimiert an den Browser gesendet. Dies macht vor allem Sinn bei textbasierten Dateien wie HTML, CSS, Javascript usw. Komprimierung bei bereits komprimierten Bildern wie jpg, png oder gif macht keinen Sinn, diese werden wir nicht komprimieren.

Dazu benötigen wir im Apache2 das „Modul Deflate„, und wir werden für bestimmte Dateitypen die Komprimierung aktivieren. Genau wie oben kann man die unten stehenden Anweisungen nach der Aktivierung des Moduls an die 3 bekannten Stellen setzen:

a2enmod deflate
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE text/javascript
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    AddOutputFilterByType DEFLATE application/x-shockwave-flash

    DeflateFilterNote Input input_info
    DeflateFilterNote Output output_info
    DeflateFilterNote Ratio ratio_info
    LogFormat '"%r" %s %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
    CustomLog /var/log/apache2/deflate_log deflate
</IfModule>

Die oberen Zeilen sollten verständlich sein, die unteren 5 Zeilen sind dazu da ein spezielles Log mit Komprimierungsinformationen anzulegen. Dieses sieht dann wie folgt aus:

"GET /wp-includes/images/smilies/icon_wink.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-content/themes/journalist/images/top.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-content/plugins/syntaxhighlighter/syntaxhighlighter/styles/shCore.css?ver=2.1.364b HTTP/1.1" 200 1917/7297 (26%)
"GET /wp-content/plugins/syntaxhighlighter/syntaxhighlighter/styles/shThemeDefault.css?ver=2.1.364b HTTP/1.1" 200 1095/3636 (30%)
"GET /wp-content/plugins/wp-cumulus/tagcloud.swf?r=5611069 HTTP/1.1" 200 34520/34610 (99%)
"GET /wp-content/plugins/wp-cumulus/tagcloud.swf?r=8457739 HTTP/1.1" 200 34520/34610 (99%)
"GET /wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/themes/advanced/link.htm?ver=327-1235-syntaxhighlighter2.3.8 HTTP/1.1" 200 974/2655 (36%)
"GET /wp-includes/js/tinymce/tiny_mce_popup.js?ver=327-1235 HTTP/1.1" 200 1921/5223 (36%)
"GET /wp-includes/js/tinymce/utils/mctabs.js?ver=327-1235 HTTP/1.1" 200 751/1786 (42%)
"GET /wp-includes/js/tinymce/utils/form_utils.js?ver=327-1235 HTTP/1.1" 200 1895/5303 (35%)
"GET /wp-includes/js/tinymce/utils/validate.js?ver=327-1235 HTTP/1.1" 200 1578/4764 (33%)
"GET /wp-includes/js/tinymce/themes/advanced/js/link.js?ver=327-1235 HTTP/1.1" 200 1467/4803 (30%)
"GET /wp-includes/js/tinymce/themes/advanced/skins/wp_theme/dialog.css?ver=327-1235-syntaxhighlighter2.3.8 HTTP/1.1" 200 1722/5510 (31%)
"GET /wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/fade-butt.png HTTP/1.1" 200 -/- (-%)
"GET /wp-includes/js/tinymce/themes/advanced/skins/wp_theme/img/tabs.gif HTTP/1.1" 200 -/- (-%)

Wie man sieht sind die Bilder nicht komprimiert worden, die CSS- und Javascript-Dateien sind teilweise auf 26% komprimiert worden. Wie man auch gut sehen kann bringt die Komprimierung der swf-Datei garnichts, man kann es also wieder deaktivieren.

Bei Änderungen an der apache2.conf bzw. den vhost-Dateien sollte man natürlich daran denken den Apache neuzustarten, damit die Änderungen aktiv werden.

In diesem Zusammenhang möchte ich auch nochmal auf die beiden sehr nützlichen Firefox-Addons Google Pagespeed und YSlow aufmerksam machen. Beide geben einen sehr guten Überblick wo Probleme liegen und was man noch verbessern kann.

Written by Michael Kliewe

März 8th, 2010 at 8:51 am

19 Responses to 'Expires-Header und Komprimierung aktivieren im Apache2'

Subscribe to comments with RSS or TrackBack to 'Expires-Header und Komprimierung aktivieren im Apache2'.

  1. Sehr schön zusammengefasst, diese Optimierung bringt auch sehr schnell, sehr viel, da das Einbinden / die Aktivierung dieser Module sehr trivial ist (solange man den Apache entsprechend konfigurieren kann).

    Zwei kurze Anmerkungen
    1) Den Apache muss man nicht zwingend neu starten, da das der Apache im Generelln gar nicht mag. Die Option „graceful“ sei hier als sinnvolle Alternative genannt (und sollte auch ausreichen für die beiden Module).
    2) Wenn der Expire-Header für CSS und JS-Dateien so lange in die Zukunft gesetzt wird, sollte man sich überlegen wie man verhindern kann, dass der Browser bei neuen Versionen der Dateien auf dem Server die gecachten Files verwendet, da dies zu hässlichen Fehlern führen kann. Die sauberste Variante ist sicherlich die Version als get-Parameter dranzuhängen also style.css?version=1 usw., aber da ist natürlich immer die Frage: Kann man das schnell & effizient mit seinem derzeitigen System erreichen?

    Ulf

    8 Mrz 10 at 09:50

  2. Das mit der Revision kann man auch automatisiert lösen. In meinem Fall werden mehrere JS Files mittels PHP zusammengefasst. Zusätzlich noch gecached, um die nicht jedesmal neu generieren zu müssen. Beim einbinden wird einfach ?nocache=…. angehängt, den Wert liefert dieses Funktion:

    public function getLastmTime(){
    $filemtime = 0;
    foreach($this->includes as $file){
    $t = filemtime($file);
    $filemtime = ($t > $filemtime) ? $t : $filemtime;
    }
    return $filemtime;
    }

    Michael

    8 Mrz 10 at 10:48

  3. Hallo,

    klingt ja ganz interessant, leider funzt es bei mir nicht so richtig…

    Ich hab nun die beiden Module:
    LoadModule expires_module modules/mod_expires.so
    LoadModule deflate_module modules/mod_deflate.so

    aktiviert.

    Danach hab ich in der vhosts-Datei deine Zeilen hinzugefügt….

    ServerName http://www.xxxxx.ch
    ServerAlias xxxxx.ch

    ServerAdmin administrator@xxxxx.ch
    DocumentRoot „C:/Webserver/htdocs/www.xxxxx.ch“
    CustomLog C:/Webserver/logs/xxxxx.ch/access.log combined

    ExpiresActive on
    ExpiresDefault „access plus 24 hours“

    AddOutputFilterByType DEFLATE text/plain

    Leider kann ich bei den GIF-Grafiken keinen „Expires“-Tag im Firebug-Plugin erkennen. Zudem wird nichts in die Datei deflate_log geschrieben…

    Hast du eine Ahnung wieso?

    Gruss

    rniederer

    8 Mrz 10 at 10:57

  4. Hi,

    entschuldigt die Frage aber sind deflate und gzip nicht verschiedene Algorythmen? Ich hab bisher angenommen, dass mod_deflate der deflate Algoyrthmus und mod_gzip der gzip Algorythmus sei?!

    Keks

    8 Mrz 10 at 11:54

  5. @Ulf: Sehr gute Tipps!
    Den graceful-Parameter nutze ich kaum noch da ich mich schon so oft geärgert habe warum einige Änderungen nicht funktionieren (SSL war glaube ich so ein Beispiel), und es lag schlicht daran dass graceful solche Änderungen nicht neu einliest, dafür muss wirklich ein richtiger Neustart des Dienstes her. Und da ich mir nie sicher bin wann graceful reicht und wann nicht nutze ich es nicht mehr.

    Der zweite Tipp ist auch wichtig, das gilt generell für alle Dateien mit einem Expire-Header. Wenn man sicher gehen möchte dass alle Browser einmal die gecachte Datei austauschen gegen die neue Version muss man den Dateinamen oder die Parameter austauschen. Michaels Lösung ist eine häufig benutzte.

    @rniederer: Kann ich dir grad aus dem Stand nicht helfen. Gab es beim Start Probleme, gibt es Einträge im error.log?

    @Keks: mod_gzip ist in Apache 2 (oder 2.2?) durch mod_deflate ersetzt worden. Es gibt da Unterschiede, welche genau kann ich grad nicht sagen, evtl. mal die Suchmaschine deiner Wahl nutzen.

    Michael Kliewe

    8 Mrz 10 at 12:04

  6. Hi Michael,

    danke für den Tipp. Hab mich schon gewundert.

    Vielleicht solltest du noch auf eine Browser-Weiche eingehen, für jene die es nicht unterstützen.

    Keks

    8 Mrz 10 at 12:08

  7. @Keks: Der Browser sendet mit jedem Request bereits die unterstützten Kompressionsalgorithmen mit, und der Server entscheidet anhand dessen ob er komprimieren darf oder nicht. Eine Browserweiche braucht man dafür nicht.

    Michael Kliewe

    8 Mrz 10 at 12:21

  8. Hi,

    mhm, hab ich bisher immer anders gelesen. Aber okay

    Keks

    8 Mrz 10 at 13:09

  9. Hi,

    „Older browsers still may have trouble with compressed content (they say they can accept it, but really they can’t)“

    soweit ich das sehe, bezieht sich das aber nur auf Netscape 4. Also für die meisten zu vernachlässigen. Wen es dennoch interessiert der kann ja mal im Manual unter der Rubrik einen Blick auf „Sample Configurations“ werfen.

    Keks

    8 Mrz 10 at 13:17

  10. Neee, gibt keine Fehler in der error.log.

    Ich hab mir mal die phpinfo-Seite angeschaut… da steht unter „loaded modules“ -> „mod_deflate“… sowie unter:
    – HTTP_ACCEPT_ENCODING
    – Accept-Encoding
    – Stream Filter support
    – _SERVER[„HTTP_ACCEPT_ENCODING“]

    Also läuft es?! Ausser, dass das Log-File geschrieben wird…?!

    rniederer

    8 Mrz 10 at 13:21

  11. Interessanter Artikel, hab grad mal das Modul hier aktiviert. Vielen Dank. 🙂

    Das Google Pageview Plugin meckert aber bei immernoch, dass das *.ico-File (also das Favicon) nicht gechached wird.

    Hab dazu in meiner /etc/apache2/conf.d/deflate folgendes geaddet:

    ExpiresByType image/vnd.microsoft.icon „access plus 1 months“

    Allerdings scheint das nicht so ganz zu funktionieren.

    Hat hier jemand mal nen Tipp für mich? Welchen mimmetype muss ich einstellen?

    Simon

    8 Mrz 10 at 14:00

  12. Guter Artikel!
    @Simon probiers mal mit: image/x-icon

    Jacky

    8 Mrz 10 at 15:36

  13. @Jacky: Danke, hat bestens funktioniert. 😉

    Simon

    8 Mrz 10 at 17:38

  14. Heyho,
    sehr schöner Artikel. Hab mich bisher noch nicht so sehr mit „Expires-Header“ befasst.
    Beide angesprochenen Themen sind aber vor allem bei größeren Seiten durchaus angebracht.

    Sepp

    9 Mrz 10 at 22:18

  15. Hallo,

    Hezlichen dank für den interesanten beitrag. Werde es nun mal ausprobieren, solte ich nicht Klar kommen, poste ich hier in der Hofnung von euch Hilfe zu bekommen. Danke.

    Handy Akku Nokia

    10 Nov 10 at 16:19

  16. Mit GZIP Komprimierung die Server-Ladegeschwindikeit optimieren…

    Die Ladegeschwindigkeit des Servers ist inzwischen nicht nur für die User-Experience sehr wichtig, sondern sogar oder eben deswegen ein Ranking Kriterium für Google. Als ein wichtigster und einfachster Schritt zur Optimierung der Ladezeiten sollte das …

  17. […] […]

    Anonymous

    23 Jan 16 at 00:50

  18. […] habe hier (klick) eine noch bessere Anleitung für das Einrichten des Caching gefunden und folgende Einstellungen in […]

  19. […] HTTP expire headers für statische Objekte festlegen, damit die gecachten Objekte beim erneuten Aufruf der Seite vom Browser-Cache und nicht vom Webserver abgerufen werden. Tutorial Tipp: Mit Expires-Header die Performance von Websites verbessern (Teil 2, Teil 3) […]

Leave a Reply

You can add images to your comment by clicking here.