WordPress auf Azure

WordPress AppService response time

Ich habe viel probiert um WordPress auf Azure schnell zu bekommen. Hier gehe auch auf die Tuningmaßnahmen ein, die ich getroffen habe.

Architektur

Als Erstes gibt es ja verschiedenen Ansätze um WordPress auf Azure zu betreiben. Auf diese möchte ich im folgenden eingehen.

App Service

PaaS – das bietet sich doch an. Ich muss mich um keine Betriebssystemupdates kümmern und bekommen direkt eine WordPress Site. Perfekt, doch leider nur performant wenn man auch auf der Datenbank (PaaS) gut skaliert. Dabei kann ich sagen, dass Linux etwas günstiger und damit schneller ist als Windows, denn ich erhalte für etwa das gleiche Geld beim App Service einen PremiumV2 Plan anstatt einen Standard S2 bei Windows und damit SSD.

Docker

Docker habe ich auch versucht zu verwenden, anders als den klassischen Linux App Service erhalten ich hier auch einen für WordPress entsprechenden LAMP bzw. LEMP Stack. d.h. mit Apache oder NGINX, MySQL und PHP. Da Docker nur ein virtuelles Image ist, was auf Linux ausgeführt wird, muss dieses nicht gepflegt werden. Dennoch muss ich entweder ein bestehendes Docker Image verwenden und ein eigenes pflegen. Das Endresultat in Verbindung mit MySQL als PaaS war etwas besser als AppService auf Windows, dennoch nicht befriedigend. Mit einem leeren WordPress sicherlich noch super schnell, aber sobald ein paar Plugins und ein paar Inhalte drauf sind… Und dann wäre das noch mit den Updates, dass man über ein eigenes GitHub Repository die WordPress und Plugin-Updates pflegen muss. Zusätzlich werden diese nur beim neuen Deploy verteilt. Problem sind die anderen Daten, wie Bilder, Beiträge und co.

FrontDoor

Sicherlich eine coole Funktion um Seiten abzusichern. Allerdings hämmern die ca. 70 Backend Hosts mit dem HealthCheck auf die WordPress Seite ein, das max. alle 4-5 Minuten. Das ist weniger von der Last das Problem, eher von den Kosten. Unabhängig was FrontDoor kostet und an Sicherheit bietet mit WAF und zusätzlich integriertem SSL Zertifikat. Es erzeugt nicht zu vernachlässigenden Netzwerktraffic am App Service, wodurch Kosten anfallen. Hier müsste idealerweise eine eigene Seite ohne Bilder etc. eingerichtet werden, die nur im Byte Bereich liegt. Ansonsten fallen schnell 2-3 stellige Kosten an.

Virtuelle Maschine

Vermutlich die einzige Variante, die tatsächlich einen kostenbewussten Umgang und performanten Zugriff für WordPress auf Azure erlaubt. Denn hier kann ich eine kleine Standard SSD verwenden, und eine kleine VM. Die kostet dann ca. 70-80 €/Monat und es können Datenbank und FrontEnd gleichzeitig darauf betrieben werden. Allerdings für mich keine Option, da ich mich auf Linux zu wenig auskenne um das sicher betreiben zu können und der Patchaufwand in keinem Verhältnis steht – das wollte ich ja gerade vermeiden.

App Service Tuning

user.ini

Hier muss insbesondere output_buffering auf „Off“ gestellt werden. Im Azure PHP ist das standardmäßig „On“ und ist wohl eher schlecht. Alles andere ist nur Dateigröße und lange Ausführungszeit zwecks Timeout.

output_buffering = Off
upload_max_filesize = 100M
post_max_size = 100M
max_execution_time = 300

Web.config

Folgende Anpassungen enthalten Caching und Redirect non www auf www und auf https. :

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.webServer>
   <staticContent>
    <clientCache cacheControlCustom="public" cacheControlMode="UseMaxAge" cacheControlMaxAge="30.00:00:00"/>
    <mimeMap fileExtension=".woff" mimeType="font/x-woff"/>
	<mimeMap fileExtension=".woff2" mimeType="font/x-woff"/>
  </staticContent>
   <urlCompression doStaticCompression="true" doDynamicCompression="true" dynamicCompressionBeforeCache="true"/>
   <httpCompression>
      <dynamicTypes>
        <clear />
        <add enabled="true" mimeType="text/*"/>
        <add enabled="true" mimeType="message/*"/>
        <add enabled="true" mimeType="application/x-javascript"/>
        <add enabled="true" mimeType="application/javascript"/>
        <add enabled="true" mimeType="application/json"/>
        <add enabled="false" mimeType="*/*"/>
        <add enabled="true" mimeType="application/atom+xml"/>
        <add enabled="true" mimeType="application/atom+xml;charset=utf-8"/>
      </dynamicTypes>
      <staticTypes>
        <clear />
        <add enabled="true" mimeType="text/*"/>
        <add enabled="true" mimeType="message/*"/>
        <add enabled="true" mimeType="application/javascript"/>
        <add enabled="true" mimeType="application/atom+xml"/>
        <add enabled="true" mimeType="application/xaml+xml"/>
        <add enabled="true" mimeType="application/json"/>
        <add enabled="false" mimeType="*/*"/>
      </staticTypes>
    </httpCompression>
	<caching enabled="true" enableKernelCache="true">
	 <profiles>
		<add extension=".php" policy="CacheForTimePeriod" duration="08:00:00" />
	 </profiles>
	</caching>		
    <rewrite>
      <rules>
			<rule name="WordPress: http://dns4everv3.azurewebsites.net" patternSyntax="Wildcard">
				<match url="*"/>
					<conditions>
						<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
						<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
					</conditions>
				<action type="Rewrite" url="index.php"/>
			</rule>	  
			<!-- Disabled due problem with SEO sitemap -->
			<rule name="Redirect requests from Azure" stopProcessing="true">
				<match url="(.*)" />  
				<conditions logicalGrouping="MatchAny">
					<add input="{HTTP_HOST}" pattern="^dns4everv3\.azurewebsites\.net$" />
				</conditions>
				<action type="Redirect" url="https://www.hobmaier.net/{R:0}" appendQueryString="false" redirectType="Permanent"/>  
			</rule>
			<rule name="Redirect to www" stopProcessing="true">
				<match url="(.*)"/>  
				<conditions logicalGrouping="MatchAny">
					<add input="{HTTP_HOST}" pattern="^hobmaier\.net$"/>
				</conditions>
				<action type="Redirect" url="https://www.hobmaier.net/{R:0}" appendQueryString="false" redirectType="Permanent"/>  
			</rule>
			<rule name="Redirect to HTTPS" stopProcessing="true">
				<match url="(.*)"/>
				<conditions>
					<add input="{HTTPS}" pattern="^OFF$"/>
				</conditions>
				<action type="Redirect" url="https://{HTTP_HOST}{URL}" appendQueryString="true" redirectType="Permanent"/>
			</rule>			
				
		</rules>
	   <outboundRules>
			<rule name="Add Strict-Transport-Security when HTTPS" enabled="true">
				<match serverVariable="RESPONSE_Strict_Transport_Security"
					pattern=".*" />
				<conditions>
					<add input="{HTTPS}" pattern="on" ignoreCase="true" />
				</conditions>
				<action type="Rewrite" value="max-age=31536000" />
			</rule>
		</outboundRules>		
    </rewrite>
    <modules>
      <remove name="TelemetryCorrelationHttpModule"/>
    </modules>
    <validation validateIntegratedModeConfiguration="false"/>
  </system.webServer>
  <system.web>
    <httpModules>
    </httpModules>
  </system.web>
</configuration>

wp-config.php

Die folgenden Zeilen wurden angepasst um Memory Limit zu erhöhen und um den Host Namen zu erkennen und anzupassen. Dies funktioniert sowohl mit Staging Umgebungen aber insbesondere war das für Docker notwendig:

// DH 22.04.2018 Performance Settings
define( 'WP_MEMORY_LIMIT', '256M' );
// For WP-Admin area
define( 'WP_MAX_MEMORY_LIMIT', '256M' );

if ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
    $_SERVER['HTTPS'] = '1';

if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
    $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
}


if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER["HTTP_X_FORWARDED_FOR"];
}

// CUSTOM WP_Home and WP_SiteURL changed http to https
//Relative URLs for swapping across app service deployment slots 
define('WP_HOME', 'https://'. filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_STRING));
define('WP_SITEURL', 'https://'. filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_STRING));
define('WP_CONTENT_URL', '/wp-content');
define('DOMAIN_CURRENT_SITE', filter_input(INPUT_SERVER, 'HTTP_HOST', FILTER_SANITIZE_STRING));

Caching Plugin

Das Caching Plugin war absolut notwendig, ich habe hier W3 Total Cache verwendet und hatte so ziemlich alles aktiviert inkl. Datenbank-Cache (!).

CDN

Mithilfe des o.g. Cache Plugins habe ich auch ein CDN (Premium Verizon) verwendet, das die Ladezeiten von Bildern und Skripten um den Faktor 10x reduziert hat. Kosten lagen dabei immer <1 €. Absolut empfehlenswert.

Zusätzliche Konfiguration war notwendig für die Komprimierung:

text/plain,text/html,text/css,application/x-javascript,text/javascript,text/xml,application/vnd.msfontobject,application/javascript,application/json,application/x-font-opentype,application/x-font-truetype,application/x-font-ttf,application/xml,font/eot,font/opentype,font/otf,image/svg+xml

Außerdem war die Anpassung für CORS notwendig, d.h. dass die Skripte über das CDN auch ausgeführt werden dürfen. Dazu muss eine Regel erstellt werden, die anschließend noch so aussieht:

<rules schema-version="2" rulesetversion="1" rulesetid="904615" xmlns="http://www.whitecdn.com/schemas/rules/2.0/rulesSchema.xsd">
  <rule id="1692672" platform="http-large" status="active" version="0" custid="A0B80">
    <!--Changed by userId: 952 on 12/12/2018 08:40:56 PM GMT-->
    <!--Changed by b39b63ad-5ed5-40bf-aae9-120c44f7955a@cdn.windowsazure.com on 12/12/2018 08:28:57 PM GMT from IP: 188.22.191.152-->
    <description>CORS</description>
    <!--If-->
    <match.always>
      <feature.set-response-header action="append" key="Access-Control-Allow-Origin" value="https://www.hobmaier.net" />
    </match.always>
  </rule>
</rules>

App Service Plan

Je nachdem wie oben beschrieben gehostet wird (Windows/Linux/Docker) benötigt man auch einen entsprechenden App Service Plan. Hier laufen dann eigentlich auch die Kosten auf. Bei Linux ist der PremiumV2 erschwinglich, bei Windows hingegen hatte ich den Stadard S2 (70-80 €) verwendet. PremiumV2 bringt halt SSD und bessere CPU. Grundsätzlich läuft die Seite auf Linux etwas schneller. Welch wunder, ist es ja für Linux gemacht. Allerdings gibt es andere Hürden, siehe SSL Zertifikat.

MySQL Datenbank

Das ist der Dreh-und Angelpunkt. Die Performance geht meiner Erfahrung direkt mit der Datenbank. Dabei spielt es keine Rolle ob MariaDB oder MySQL, ich hab beides probiert. Am Anfang als das noch in der Preview war, konnte man Datenbanken mit 2.000 IOPS erstellen, damit habe ich auch TTFB auf Windows mit 100-150 ms geschafft (und S2 App Service Plan). Die Kosten hierfür würden aktuell aber rund 210 € / Monat betragen. die Performance von DEV/Test ist nicht garantiert und entsprechend schlecht, kostet auch nur 20-25 €. DEV verwendet Standard Disks und Std/Memory eben Premium Storage = SSD.
Folgende Werte habe ich noch angepasst:

Max_allowed_packet von 536870912 -> 1073741824
net_read_timeout 120 --> 500
net_write_timeout 240 --> 500
wait_timeout 120 --> 500
innodb_lock_wait_timeout 50 --> 500

SSL Zertifikat

State-of-the art ist ja mittlerweile ein SSL-Zertifikat. Das geht eigentlich auch immer kostenlos und zwar mit der Let’s Encrypt CA kann automatisch ein Zertifikat für 3 Monate erstellt werden.

Windows: Per Site Extension kann man das Zertifikat installieren und gleichzeitig erneuern lassen.

Linux: Nicht ausprobiert aber es gibt wohl ne Azure Function.

App Service Einstellungen

Folgende Einstellungen habe ich noch am App Service vorgenommen:

  • AlwaysOn = yes
  • PHP = 7.2 (oder 7.4)
  • Platform = 64 Bit
  • ARR affinity = off
  • HTTP version = 2.0
  • FTP state = FTPS only (mehr Security)

Umzug zu SiteGround

Ich bin mit meiner Seite zu SiteGround umgezogen, dies ist nun um ein vielfaches schneller. Wer noch mehr Performance benötigt, dem kann ich noch Raidboxes empfehlen, hier erhält man eine dedizierte vCPU anstatt ein Quota auf die CPU Leistung. Aber in meinem Fall reicht auch die „Mini“-Variante.

Der Umzug war easy, ich habe lediglich den Link zum mein Backup ZIP bereit gestellt. Ansonsten geht es auch per FTP und phpAdmin.

GTMetrix Report zeigt TTFB von > 3s vorher auf Azure zu 0,2 s anschließend auf SiteGround.

Als Goodie ist der Staging Bereich noch top, auf Knopfdruck Testseite eingerichtet inkl. Datenbankkopie. Natürlich auch rückwärts wieder in die Produktion gespielt. Die verstehen WordPress.

Fazit

WordPress auf Azure geht mit Sicherheit, wenn man entsprechend hoch skaliert und vor allem bei der Datenbank investiert. Für kleine Websites kommen andere Hoster meist preiswerter und schneller zum Ziel.

Teilen

Autor: Dennis Hobmaier

Dennis Hobmaier ist Consultant - Digital Workspace bei Insight Technology Solutions GmbH. Er hat über 15 Jahre Erfahrung in IT-Enterprise Umgebung aller Größenordnungen und bedient Kunden aus den unterschiedlichsten Branchen. Als MCSE SharePoint hat er tiefgreifende Kenntnisse in den Bereichen Microsoft Active Directory, Windows, Azure, SharePoint und Office 365. Gerne teilt er seine Projekterfahrung mit Ihnen.

Leave a Reply

avatar

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahren Sie mehr darüber, wie Ihre Kommentardaten verarbeitet werden .

  Subscribe  
Notify of