Optimierte .htaccess für TYPO3

Über passende Regeln in der .htaccess-Datei wird die Website noch schöner, schneller und besser. Vor fast 5 Jahren hatten wir bereits im Beitrag Optimierte .htaccess fuer TYPO3 auf Apache2 von Stephan eine alternative .htaccess-Datei veröffentlicht. Die damals von TYPO3 mitgelieferte Version behandelte nur wenige Grundeinstellungen und war für den Produktivbetrieb eher suboptimal. Über die Jahre hat sich vieles getan und holte die Default-htaccess von TYPO3 auf. Ein Punkt von damals gilt aber auch noch heute

  • eine .htaccess wird mit jedem File-Hit geparst, besser wäre es natürlich die Einstellung direkt in der Apache Konfiguration der VirtualHosts vorzunehmen. Das scheitert aber vermutlich meist an entsprechenden Rechten.
  • Dadurch dass es geparst werden muss, sollte man die Datei klein halten, d.h. alle Kommentare entfernen.

Weiterlesen»

lighttp, redirects und rewrites

Wenns mal wieder performant sein muss, ist oft der Griff zu lighty (http://www.lighttpd.net/) ein probates Mittel.

Seine Performance-Vorteile gegenüber dem Apache2 aus der Dose (http://httpd.apache.org/) erreicht der lighttpd unter anderem dadurch, dass er sich das aufwendige Parsen von .htaccess-Files spart. Der Pferdefuß dabei ist allerdings, dass serverseitige rewrites und redirects nichtmehr einfach in ein File im betroffenen Verzeichnis gekippt werden können sondern direkt in die Config von lighttpd geschrieben werden.

Gerade in Verbindung mit einer TYPO3-Umgebung kann der Einsatz von lighttpd als Webserver allerdings schnell zur Herausforderung werden. Seiten werden umbenannt, realurl generiert die Pfade neu und – hoppla, plötzlich gehen natürlich Links, die noch auf den alten Titel verweisen, auf eine 404-Seite oder im schlimmsten Fall komplett ins Leere. Natürlich muss eine Lösung her: die Redirects um dem Browser (und natürlich auch der Suchmaschine) gleich noch mitzuteilen, dass sich die URL geändert hat. Nehmen wir daher ein Beispiel:

Die bisherige Seite „diese-seite-ist-toll.html“ heißt nun „diese-seite-ist-spitze.html“. Links auf http://www.beispielseite.de/diese-seite-ist-toll.html“ führen also ab sofort ins Leere, genau so wie Links, die auf Unterseiten verweisen (z.B. „http://www.beispielseite.de/diese-seite-ist-toll/eine-unterseite.html“). Das Ziel ist also, alle URLs, die „diese-seite-ist-toll“ beinhalten, sollen umgeleitet werden auf „diese-seite-ist-spitze“ und gleichzeitig soll der HTTP-Status „301 – Moved permanently“ gesendet werden, um Browser und Suchmaschine zu sagen, dass die bisherige URL nichtmehr gültig ist. Dazu muss die lighttpd-Konfiguration angepasst werden:

Die Datei lighttpd.conf sieht für TYPO3-Umgebungen mit installierter realurl-Extension i.d.R. bereits einen rewrite-Block vor, der in etwa folgendermaßen aussieht:

url.rewrite-once = (
    "^/(typo3|phpmyadmin/|info/|typo3temp/|typo3conf/|uploads/|fileadmin/|t3lib/|robots\.txt|clear\.gif|favicon\.ico).*$" => "$0",
    "^/$" => "index.php",
    "^typo3$" => "typo3/index_re.php",
    ".html\?([^*]+)" => "index.php?$1",
    ".html$" => "index.php",
    "^([^*]+)\.([^*])+\.html\?([^*]+)$" => "index.php?id=$1&type=$2&$3",
    "^/.*\?([^*]+)" => "index.php?$1",
    "^/.*$" => "index.php"
)

Dazu fügen wir nun den Redirect-Block ein, der folgendermaßen aussieht:

url.redirect-code = 301
url.redirect = (
        "^/diese-seite-ist-toll(/.*|\.html.*)" => "http://www.beispielseite.de/diese-seite-ist-spitze$1",
)

Testet man nun die Funktion, wird man feststellen: es funktioniert nicht. Eine unangenehme Eigenschaft des lighty ist, dass die Reihenfolge, in der Redirects und Rewrites abgearbeitet werden, fest vorgegeben ist, d.h. es ist irrelevant, an welcher Stelle in der Config eine Rewrite- oder Redirect-Direktive eingefügt wird, es werden stets und immer zuerst die Rewrites und dann die Redirects abgearbeitet. Mit diesem Wissen ist es logisch, dass nichts passiert denn der lighty kommt garnicht dazu, die URL zu redirecten.

Abhilfe hierfür schafft man dadurch, dass man die URLs, die umgeleitet werden sollen, von sämtlichen Rewrite-Regeln ausnimmt. In userem Beispiel wäre das die Erweiterung der Direktive „url.rewrite-once durch das Statement

"^/diese-seite-ist-toll(/.*|\.html.*)" => "$0",

Danach lighttpd neu starten und siehe da, der Lighty leitet die fragliche URL um und sendet wie gewünscht vorher den 301-Header.

Elegante http zu https Umleitung ohne Domainangabe

Den Domainnamen in die .htaccess zu schreiben finde ich etwas ungluecklich, vor allem da es nicht notwendig ist:

<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteCond %{HTTPS} off
 RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L]
</IfModule>

Optimierte .htaccess fuer TYPO3 auf Apache2

Dieser Artikel ist sehr alt. TYPO3 wurde weiterentwickelt, wodurch die Inhalte des Artikels möglicherweise nicht mehr zur aktuellen TYPO3-Version passen. Der Beitrag Optimierte .htaccess für TYPO3 ist neuer und befassts ich mit dem gleichen Thema.

Die .htaccess Datei welche standardmäßig in einer TYPO3 Installation (meist als _htaccess) mitgeliefert wird ist fuer Dokumentationszwecke besser geeignet als zum produktiven Einsatz.

  1. .htaccess
    • eine .htaccess wird mit jedem File-Hit geparst, besser wäre es natürlich die Einstellung direkt in der Apache Konfiguration der VirtualHosts vorzunehmen. Das scheitert aber vermutlich meist an entsprechenden Rechten.
    • Dadurch dass es geparst werden muss, sollte man die Datei klein halten. D.h. alle Kommentare entfernen.
  2. Die Direktiven sind „einfach so“ vorhanden. Besser ist es natürlich nur Direktiven zu verwenden, die der Apache auch durch die entsprechenden Modules eingebunden hat. D.h. <IfModule …></IfModule> sind zwingend verwenden um hässliche 500 Serverfehler zu vermeiden.
  3. Etag, Expiration und Compression Direktiven sind in der TYPO3 Vorlage nicht enthalten, bieten sich aber natürlich an. Der geneigte Websitebetreiber sollte dann natürlich die Module aktivieren (a2enmod headers; a2enmod deflate; a2enmod expires)

.htaccess

Hier die optimierte .htaccess (hier für RealURL-Verwendung, die _htaccess Dokumentation verliert natürlich nicht ihre Gueltigkeit bezüglich RewriteBase…)

<FilesMatch "\.(js|css)$">
        <IfModule mod_expires.c>
                ExpiresActive on
                ExpiresDefault "access plus 7 days"
        </IfModule>
        FileETag MTime Size
</FilesMatch>
<IfModule mod_rewrite.c>
RewriteEngine On
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.+)\.(\d+)\.(php|js|css|png|jpg|gif|gzip)$ $1.$3 [L]
        RewriteCond %{REQUEST_URI} ^.+(/(uploads|fileadmin|(typo3(conf|temp)?))/.*)
        RewriteRule ^.*$ %1 [L,R=301]
        RewriteRule ^fileadmin/(.*/)?_recycler_/ - [F]
        RewriteRule ^fileadmin/(templates|ts)/.*(\.txt|\.ts)$ - [F]
        RewriteRule ^typo3conf/ext/[^/]+/Resources/Private/ - [F]
        RewriteRule ^typo3_src\-(.*)$ /
        RewriteRule ^(typo3/|t3lib/|fileadmin/|typo3conf/|typo3temp/|uploads/|favicon\.ico) - [L]
        RewriteRule ^typo3$ typo3/index_re.php [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{REQUEST_FILENAME} !-l
        RewriteRule .* index.php [L]
</IfModule>
<IfModule mod_headers.c>
 FileETag Size
</IfModule>
<IfModule mod_expires.c>
        ExpiresActive on
        ExpiresDefault "access plus 24 hours"
        ExpiresByType image/x-icon "access plus 1 months"
        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"
        ExpiresByType text/css "access plus 1 months"
        ExpiresByType text/javascript "access plus 1 months"
        ExpiresByType application/javascript "access plus 1 months"
        ExpiresByType application/x-shockwave-flash "access plus 1 months"
</IfModule>
<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
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4\.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
        SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
        <IfModule mod_headers.c>
                Header append Vary User-Agent env=!dont-vary
        </IfModule>
</IfModule>

Update 11.07.2013:

Es gab hier einen Fallstrick, der in dem Fall, dass mod_headers nicht installiert ist, im Block bzgl. mod_deflate einen Error 500 verursacht. Dies wurde mithilfe des verschachtelten „IfModule“-Blocks innerhalb des mod_deflate.c gefixed, sodass auch nur bei Vorhandensein des notwendigen Moduls die Header gesendet werden.