Eigenes CDN in WordPress nutzen

Die Zeiten ändern sich.

Dieser Beitrag scheint älter als 13 Jahre zu sein – eine lange Zeit im Internet. Der Inhalt ist vielleicht veraltet.

In einem Artikel von Leo Flyer ist mir ein altes Thema nochmals aufgefallen – CDN mit dem eigenen Webspace. Sämtliche Analysetools wie YSlow oder PageSpeed empfehlen das Nutzen eines oder mehrerer CDN. In Sachen Performance erst mal richtig – im weitesten Sinne muss das CDN aber kein kostenpflichtiges CDN bei anderen Dienstleistern sein, sondern der eigenen Webspace kann dazu dienen.
Google fordert nicht direkt ein CDN, sondern lediglich eine Domain ohne Cookies. Dafür muss man lediglich eine oder mehrere Subdomain mit Webspace anlegen und alles weitere übergebe ich an WordPress.

CDN – Content Delivery Network, ist ein Netz lokal verteilter und über das Internet verbundener Server, mit dem Inhalte (insbesondere große Mediendateien) ausgeliefert werden. In der Regel sind diese Server sehr leistungsfähig und schnell. Sie konzentrieren sich auf die Ausgabe der Dateien und keine anderen Funktionen wie Cookies.


Weitere Informationen zum Thema CDN gibt es beispielsweise bei Wikipedia oder bei Sergej Müller.
Im Webspace meiner Domain habe ich drei Subdomains angelegt, die ich jeweils so eingestellt habe, dass sie auf Bilder, das Theme und Plugins verweisen.

Subdomains

Im ersten Test sollte dies reichen. Insbesondere für Bilder und die Dateien des Theme ist das sicher nützlich, da die so gut wie statische Elemente sind. Für Bilder, die in erster Linie im Content der Artikel zu finden sind, habe ich eine Funktion laufen, die über den Hook the_content von WordPress die URLs im Artikel filtert und mit der Subdomain ersetzt.


// replace content for CDN 
if ( !function_exists('fb_add_static_content_url') ) {
	function fb_add_static_content_url($content) {
			if ( is_admin() ) // eigentlich überflüssig
				return $content;
			
			$wpurl = get_bloginfo('wpurl');
			
			$search = array(
				$wpurl . '/wp-content/images/',
				$wpurl . '/wp-content/download/',
			);
			
			$replace = array(
				'http://cdn1.bueltge.de/',
				'http://cdn2.bueltge.de/',
			);
			
			return str_replace( $search, $replace, $content );
	}
	add_filter( 'the_content', 'fb_add_static_content_url' );
}

Im weiteren kommt eine Funktion ins Spiel, die die Template Tags für die Adressen des Themes anpasst und auf die Subdomain verweist. Dies setzt voraus, dass die Dateien auch mit Hilfe der Template Tags von WordPress inkludiert wurden – zum Beispiel das Stylesheet über <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css" media="screen" />.


// replace for CDN 
if ( !function_exists('fb_add_static_wpurl') ) {
	function fb_add_static_wpurl($info, $show) {
		
		if ( is_admin() )
			return $info;
		
		$keys = array(
			'url',
			'wpurl',
			'stylesheet_url',
			'stylesheet_directory',
			'template_url',
			'template_directory',
			);
		
		if ( in_array( $show, $keys ) ) {
			
			$wpurl = get_bloginfo('wpurl');
			
			$search = array(
				$wpurl . '/wp-content/images/',
				$wpurl . '/wp-content/download/',
				$wpurl . '/wp-content/themes/',
				$wpurl . '/wp-content/plugins/',
			);
			
			$replace = array(
				'http://cdn1.bueltge.de/',
				'http://cdn2.bueltge.de/',
				'http://cdn3.bueltge.de/',
				'http://cdn4.bueltge.de/',
			);
			
			return str_replace( $search, $replace, $info );
		
		} else {
			return $info;
		}
	}
	add_filter( 'bloginfo_url', 'fb_add_static_wpurl', 9999, 2 );
}

Um alle relevanten Möglichkeiten von bloginfo() zu erreichen, muss man weitere Hooks ansprechen – hier habe ich erst nichts gefunden und eine Frage in der wp-hackers-Gemeinde fand Aufschluss. Die folgende Funktion kümmert sich daher um drei Schlüssel der Funktion und sorgt für das Ersetzen mit der Subdomain.


function fb_add_static_stylesheet_uri($uri) {
			
			if ( is_admin() )
				return $uri;

			$wpurl = get_bloginfo('wpurl');

			$search = array(
				$wpurl . '/wp-content/images/',
				$wpurl . '/wp-content/download/',
				$wpurl . '/wp-content/themes/',
				$wpurl . '/wp-content/plugins/',
			);

			$replace = array(
				'http://cdn1.bueltge.de/',
				'http://cdn2.bueltge.de/',
				'http://cdn3.bueltge.de/',
				'http://cdn4.bueltge.de/',
			);
			return str_replace( $search, $replace, $uri );

}
add_filter ( 'template_directory_uri', 'fb_add_static_stylesheet_uri' );
add_filter ( 'stylesheet_uri', 'fb_add_static_stylesheet_uri' );
add_filter ( 'stylesheet_directory_uri', 'fb_add_static_stylesheet_uri' );

Mit diesen drei kleinen Funktionen muss man in den Artikeln oder den Theme von WordPress nichts tun, man kann einfach die Funktionen in ein Plugin oder die functions.php des Themes legen. Natürlich müssen die Subdomains angelegt und richtig konfiguriert sein.
Nun gilt es noch, dafür zu sorgen, dass die Cookies auf die Subdomains nicht vererbt werden. Dies kann man innerhalb der wp-config.php der WordPress Installation hinterlegen, da WP dafür eine Konstante hat.


define( 'COOKIE_DOMAIN', 'bueltge.de' );

Eventuell aufpassen, je nach dem wie man die URL konfiguriert hat – entweder mit oder ohne www.

Zusätzlich empfiehlt sich ein Eintrag in der .htaccess der Installation um doppelten Content zu verhindern.


##
# Explicitly send a 404 header if a file on cdn[0-9].example.org is not
# found. This will prevent the start page (empty URL) from being loaded.
##
RewriteCond %{HTTP_HOST} ^cdn[0-9]\.example\.org [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* - [R=404,L]


##
# Do not dispatch dynamic resources via cdn[0-9].example.org.
##
RewriteCond %{HTTP_HOST} ^cdn[0-9]\.example\.org [NC]
RewriteCond %{REQUEST_FILENAME} \.(php|html)$
RewriteRule .* - [R=404,L]

Zusätzliche Information zu dem Eintrag entnehmt bitte dem Artikel von Leo zu Contao Optimierung.

Viel Spaß beim ausprobieren, beim Testen und auswerten. Neue Ideen, Erweiterungen und Verbesserungen können wie immer von euch in den Kommentaren hinterlassen werden – ich freue mich darauf.

Von Frank Bültge

bueltge.de [by:ltge.de] wird von Frank Bültge geführt, administriert und gestaltet. Alle Inhalte sind persönlich von mir ausgewählt und erstellt, nach bestem Gewissen und Können, was die Möglichkeit von Fehlern nicht ausschließt.