instant-thinking.de

just enough to get you started and leave you confused

Lokaler WordPress Mirror

| Kommentare

Es gibt einige gute Gründe einen lokalen Mirror des eigenen Blogs zu erstellen. Eine nicht abschliessende Liste umfasst:

  • Man kann nach Herzenslust an Themes, PlugIns und anderen Plumbing Bestandteilen der Website herumschrauben ohne dass die Besucher nur krude Fehlermeldungen zu sehen bekommen.
  • Ein Live-Backup von dem man weiss dass es lauffähig ist kann man mit Geld gar nicht bezahlen
  • Billige Günstige Hoster1 legen ihren Usern manchmal nervige Steine in den Weg wenn es um Performance geht. Die Laufzeit für PHP-Scripte ist begrenzt, CPU-Zeit wird beschränkt, Hauptspeicher ist nicht unendlich vorhanden, etc.

Bei mir war gerade der dritte Punkt das Problem, denn durch diese Beschränkungen konnte ich nach dem Update auf WordPress 2.6 leider meine alten SimpleTagging Tags nicht in native WordPress Tags umwandeln.

3651 tag to post relationships waren einfach too much für mein shared hosting Paket…

Der Plan war also, die Dateien und die Datenbank aus dem letzten Backup2 zu kopieren und lokal auf dem MacBook zu installieren. Dort dann ohne jede CPU- oder RAM-Beschränkung die Konvertierung der Tags durchführen und die fertig konvertierte lokale Datenbank wieder zu dumpen und live auf instant-thinking.de zu stellen.

Danach wäre es ja nicht schlecht die Mirror-Erstellung zu automatisieren, um eine ständig aktuelle lokale Testumgebung zu haben. Vielleicht könnte man diese3 auch als Fallback einsetzen wenn die live Site mal offline gehen sollte…

Aber eins nach dem anderen…

Vorraussetzungen

  • Ein Mac unter OS X 10.54
  • Apache Webserver mit aktiviertem PHP und MySQL Datenbankserver
  • Shell-Kenntnisse sind von Vorteil, aber eigentlich sollte das auch mit der Anpassung einiger Variablen per Copy & Paste gehen

Nach dem Klick gehts los…

PHP aktivieren

Auf dem MacBook brauchen wir zunächst einen laufenden Webserver mit PHP. Den Webserver liefert Apple dankenswerterweise bereits mit, PHP ist allerdings nicht aktiviert.

Um die PHP-Unterstützung für Apache unter Mac OS X 10.5 zu aktivieren, genügt es in der Datei /etc/apache2/httpd.conf die Raute am Anfang der Zeile

1
\#LoadModule php5_module        libexec/apache2/libphp5.so

zu entfernen.

<img src=”http://img.skitch.com/20080801-rh8xm98uwguh8qb2gq1ks3b1iu.jpg” alt=”Sharing”/ class=”right”>Danach (re)startet man den Webserver. Dazu entweder in den Systemeinstellungen unter Sharing den Haken vor Web-Sharing setzen5 oder den Apache direkt aus der Shell mit sudo apachectl start starten. Der Neustart gelingt mit restart anstelle von start.

Um die PHP-Unterstützung zu testen erstellt man eine Datei namens info.php in dem Ordner Websites6 im Home-Verzeichnis und füllt sie mit der einzelnen Zeile:

1
< ? php phpinfo(); ?>

Danach lässt sich eine Seite mit detaillierten Informationen über die PHP Installation unter der Adresse http://localhost/~dennis/info.php7 aufrufen. Die sollte ungefähr so aussehen:

phpinfo()

Mirror Addresse und VirtualHost Konfiguration

Damit der Mirror unter einem bequemen Namen zu erreichen ist konfigurieren wir einen neuen Hostnamen inklusive neuer Top Level Domain und einen passenden VirtualHost für den Apache Webserver.

In der Datei /etc/hosts wird am Ende einfach unser neuer Name für den lokalen Host eingetragen:

1
2
3
4
5
6
7
8
9
10
11
\##
\# Host Database
\#
\# localhost is used to configure the loopback interface
\# when the system is booting.  Do not change this entry.
\##
127.0.0.1	localhost
255.255.255.255	broadcasthost
::1             localhost 
fe80::1%lo0	localhost
127.0.0.1	instant-thinking.mirror

Ich habe den Mirror aus offensichtlichen Gründen instant-thinking.mirror genannt. Hier kann man aber prinzipiell alles nehmen was einem einfällt, man sollte nur keine existierende Top Level Domain nehmen, auch .local ist keine gute Idee denn darüber wickelt Apple sein Bonjour ab…

Der gewünscht Name sollte jetzt im Terminal pingbar sein:

1
2
3
4
5
~ > ping instant-thinking.mirror
PING instant-thinking.mirror (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.139 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.438 ms
...

Ausserdem wird ein neues DocumentRoot Verzeichnis angelegt:

mkdir /Users/dennis/Sites/instant-thinking.mirror

In diesem landen später alle WordPress-Dateien aus der Original-Installation.

Als nächstes wird die Mirror-Adresse als virtueller Host in Apache konfiguriert. Anstelle der Hauptkonfigurationsdatei httpd.conf kann man unter OS X auch seine Userdatei anpassen. Das macht die Anpassungen schön übersichtlich. Bei mir ist das die Datei /etc/apache2/users/dennis.conf. Dieser sollte man folgendes hinzufügen:

1
2
3
4
5
6
7
8
9
NameVirtualHost *:80
<VirtualHost *>
    DocumentRoot /Users/dennis/Sites/instant-thinking.mirror
    ServerName instant-thinking.mirror
    <Directory "/Users/dennis/Sites/instant-thinking.mirror">
        Options FollowSymLinks
        AllowOverride All
    </Directory>
</VirtualHost>

Die Pfade und Namen muss man natürlich wieder an die eigenen Gegebenheiten anpassen. Nach einem erneuten Apache Restart sind die Konfigurationsänderungen übernommen.

Jetzt kann man im Prinzip schon alle WordPress Dateien von der Live Website in den DocumentRoot Ordner des Mirrors kopieren. Wie man das am liebsten macht ist eigentlich egal, ich nutze dafür rsync. Das hat bei der späteren Automatisierung den Vorteil, dass nicht immer alles kopiert werden muss, sonder nur neue und geänderte Daten. FTP, scp oder sonstige Methoden funktionieren aber auch.

rsync -avz --delete instant-thinking.de:./www/instant-thinking/ ~/Sites/instant-thinking.mirror/

Sobald die Dateien alle kopiert sind, kann man statische Seiten auf dem Mirror testen. So sollte die WordPress Readme bereits unter http://instant-thinking.mirror/readme.html erreichbar sein. Für die Inhalte aus der Datenbank benötigen wir noch MySQL.

MySQL installieren und konfigurieren

Als erstes lädt man sich den aktuellen MySQL-Community Server von der Download-Seite. Ich habe hier für mein MacBook die Version 5.0.67 für Mac OS X 10.5 (x86) verwendet8. Von dem DiskImage installiert man den Server, das Startup Item und die PrefPane. In letzterer kann man dann auch den automatischen Start des MySQL-Servers einschalten. Bei mir klappt das ganz hervorragend, die unten erwähnten Quellen sprechen von Problemen und bieten Lösungen an, YMMV.

Wenn das erledigt ist kann man die verschiedenen MySQL-Binaries zu seinem $PATH hinzufügen um später bequemen Zugriff darauf zu haben. Die Binaries leben in /usr/local/mysql/bin. In meiner ~/.bash_profile schaut die entsprechende Zeile so aus:

export PATH=/opt/local/bin:/opt/local/sbin:/usr/local/mysql/bin:$PATH

Ein frisch installiertes MySQL ist nicht sonderlich sicher konfiguriert. Um diesem Umstand abzuhelfen tippt man nun mysql_secure_installation in ein Terminal. Dort kann man dann das Passwort für den MySQL-root setzen, remote root Zugriffe abschalten und die Test-Datenbanken entfernen.

Nachdem das erledigt ist loggt man sich mit dem neuen root-Passwort in der MySQL-Shell ein und erstellt eine Datenbank nebst User für den Wordpress-Mirror:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
~ > mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 5.0.67 MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> CREATE database wp_mirror;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE user wp_mirror_user@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql> SET PASSWORD FOR 'wp_mirror_user'@'localhost' = PASSWORD('passwort');
Query OK, 0 rows affected (0.00 sec)

mysql> GRANT ALL ON wp_mirror.* TO wp_mirror_user@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql>

In der letzten Zeile werden dem User wp_mirror_user alle Rechte an allen Tabellen (.*) in der Datenbank wp_mirror gewährt.

Die Namen für die Datenbank und den User kann man natürlich frei wählen und das Passwort sollte auch nicht unbedingt “passwort” sein…

Jetzt müssen wir die Mirror-Datenbank noch mit den Daten der Live-Site füllen. Ich nutze dazu den Befehl mysqldump. Bei anderen Providern hat man eventuell keinen direkten MySQL- oder ssh-Zugriff, aber irgendwie9 kommt man sicher an eine .sql Datei mit dem Datenbankinhalt.

Bei mir schaut das so aus:

~ > mysqldump --default-character-set=latin1 -hmysqlhost.1blu.de -ubenutzer -ppasswort -f -v instant-thinking-db --lock-tables=false > instant-thinking_backup.sql

Wenn man die sql-Datei heruntergeladen hat füttert man die Mirror-Datenbak mit deren Inhalt:

~ > mysql -uwp_mirror_user -p wp_mirror < instant-thinking_backup.sql

Hier erhielt ich den folgenden Fehler:

1
ERROR 1153 (08S01) at line 349: Got a packet bigger than 'max_allowed_packet' bytes

Nach diesen beiden Änderungen in der MySQL-Shell trat der Fehler dann nicht mehr auf.

1
2
mysql> set global max_allowed_packet=1000000000; 
mysql> set global net_buffer_length=1000000;

Als letztes muss jetzt noch ein kleines Missverständniss zwischen PHP und MySQL beigelegt werden. Die beiden sind sich nicht einig wo die Datei für die MySQL-Socket-Verbindung liegen soll. Um Fehlern bei der Datenbankanbindung vorzubeugen, erstellen wir einen Symlink:

1
2
~ > sudo mkdir /var/mysql
~ > sudo ln -s /tmp/mysql.sock /var/mysql/mysql.sock

So ist es egal welcher von beiden Sockets angesprochen wird.

Wordpress konfigurieren

Da die lokale Datenbankkonfiguration bei mir von der Live Site abweicht, wird die wp-config.php bearbeitet um die lokalen Verhältnisse wiederzugeben. Wenn man auch auf dem Server im Netz localhost benutzt und User, Passwort und Datenbankname ebenfalls identisch sind kann man diesen Schritt auch überspringen.

1
2
3
4
5
// ** MySQL settings ** //
define('DB_NAME', 'wp_mirror');    
define('DB_USER', 'wp_mirror_user');   
define('DB_PASSWORD', 'passwort'); 
define('DB_HOST', 'localhost');

Als letztes müssen zwei Optionen in der MySQL Datenbank auf die Mirror-URL abgeändert werden. Das erledigt man entweder per CocoaMySQL10 oder einfach direkt auf der MySQL Shell.

Hier sind beide Möglichkeiten aufgeführt. Letztlich ist es wichtig das in der Tabelle wp_options die Werte für home und site_url auf die Mirror-Adresse geändert werden.

cocoaMySQL change url

1
2
3
mysql> USE wp_mirror
Database changed
mysql> UPDATE wp_options SET option_value = "http://instant-thinking.mirror" WHERE option_name = "siteurl" OR option_name = "home";

Fertig

Das wars, unter der Mirror-URL ist jetzt eine aktuelle Kopie der eigenen WordPress Installation erreichbar.

Automatisierung

Um das ganze zu automatisieren gibt es einige Möglichkeiten. Ich habe ein Shell-Script geschrieben das sich recht gut an verschiedene Gegebenheiten anpassen lassen sollte:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
\#!/bin/sh

\# Remote Variables
SITE_TO_MIRROR=instant-thinking.de:./www/instant-thinking/

MYSQL_HOST=mysql.host.de
MYSQL_USER=username
MYSQL_PW=passwort
MYSQL_DB=datenbank
MYSQL_DUMP=wordpress_dump.sql

\# Local Variables
TEMP_DIR=/tmp

LOCAL_MIRROR=~/Sites/instant-thinking.mirror/
LOCAL_MIRROR_URL=http://instant-thinking.mirror

LOCAL_MYSQL_DB=wp_mirror
LOCAL_MYSQL_USER=wp_mirror_user
LOCAL_MYSQL_PW=passwort

\# rsync the filesystem to the local directory

rsync -avz --delete $SITE_TO_MIRROR $LOCAL_MIRROR

\# Dump the Database to a temporary folder

mysqldump --default-character-set=latin1 -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PW -f -v $MYSQL_DB --lock-tables=false > $TEMP_DIR/$MYSQL_DUMP

\# Import the dump into the local database

mysql -u$LOCAL_MYSQL_USER -p$LOCAL_MYSQL_PW $LOCAL_MYSQL_DB < $TEMP_DIR/$MYSQL_DUMP

\# Cleanup, remove the tmp-Database

rm $TEMP_DIR/$MYSQL_DUMP

\# Replace the Original Values in wp-config.php with the local ones

sed -i '' -e s@$MYSQL_DB@$LOCAL_MYSQL_DB@ -e s@$MYSQL_USER@$LOCAL_MYSQL_USER@ -e s@$MYSQL_PW@$LOCAL_MYSQL_PW@ -e s@$MYSQL_HOST@localhost@ $LOCAL_MIRROR/wp-config.php

\# Put the Mirror-Address in the Database

echo 'UPDATE wp_options SET option_value = "http://instant-thinking.mirror" WHERE option_name = "siteurl" OR option_name = "home";' | mysql -u$LOCAL_MYSQL_USER -p$LOCAL_MYSQL_PW $LOCAL_MYSQL_DB

Alle benötigten Daten werden oben in die Variablen eingetragen, nur in der letzten MySQL Anweisung ist die URL des Mirrors fest verdrahtet. Ich weiss leider nicht wie ich in dem escapten echo Befehl an die Variable dran komme11

Mit diesem Script kann ich nun nach Belieben eine lokale Kopie meines Blogs erstellen und an Themes, Tags und allem anderen arbeiten ohne dass die werten Leser unter meiner Experimentierwut leiden müssen…

Quellen

Diese Anleitung basiert zum Großteil auf den beiden Artikeln Mac OS X Local Mirror im Codex und Installing Drupal on Mac OS X 10.5 Leopard. Thank you very much, guys!

  1. meiner zum Beispiel

  2. Das Backup läuft jede Nacht, einmal war es bisher dringend nötig…

  3. dann aber nicht auf dem MacBook und eine entsprechende DNS-Konfiguration vorausgesetzt

  4. aber mit einigen kleinen Anpassungen sollte das hier auch auf anderen unixoiden Betriebssystemen laufen

  5. bzw. entfernen und neu setzen um neu zu starten

  6. Nur Sites in der Shell

  7. “dennis” ist natürlich mit dem eigenen Usernamen zu ersetzen

  8. Ausserdem hatte ich das Vorgehen auch auf dem Cube getestet. Da es keinen Installer für 10.5 und PowerPC gibt habe ich das 10.4er PowerPC-Paket verwendet, klappte auch gut.

  9. Oft ist das Mittel der Wahl phpMyAdmin

  10. Für MySQL Version 4.1 oder neuer braucht man eine Beta-Version von CocoaMySQL

  11. Wenn jemand eine gute Idee hat, nur her damit, dann baue ich da auch noch die Variable ein

Comments