Gebruik Apache RewriteMaps om een website te migreren

  •  

Verhuis je je website van Joomla naar Wordpress, of migreer je naar een ander CMS? Dan is de kans groot dat URL's zullen veranderen. Je klikt op een link die al door Google was geïndexeerd en je krijgt de foutmelding: "Pagina niet gevonden". Dit kan een grote impact hebben op jouw reputatie in Google. De kans is groot dat je gebruik gaat maken van een CMS dat gebruik maakt van Apache als webserver en dan bieden Rewritemaps een oplossing.

Wanneer het systeem waar je vandaan komt al nette, leesbare en zoekmachine geoptimaliseerde URL's bevat, dan is het advies de URL's één op één over te nemen, op die manier veranderd er niets en blijven alle URL's gewoon functioneren. In de meeste systemen kun je echter niet zelf de URL's instellen, laat staan exact overnemen.

Onderstaand wordt je uitgelegd hoe je een Rewritemap zodanig instelt dat alle oude URL's worden doorgestuurd — door middel van 301 redirect —  naar de nieuwe versie van de URL. Rewritemaps werken zowel in Apache2.2 als in Apache2.4. We gaan uit van de sitemap van je oude site en converteren deze stap voor stap naar een bestand dat Apache begrijpt. Dit bestand kun je vervolgens instellen in je Virtualhost of .htaccess bestand op de nieuwe locatie.

Strict gezien zouden de Rewritemaps al ingesteld moeten zijn voordat je de daadwerkelijke migratie start, maar als jouw website al gemigreerd is dan kun je onderstaande stappen alsnog doorlopen, mits je bijvoorbeeld bij de database kunt, een aparte omgeving hebt waar je website nog op draait of als je een back-up hebt van jouw oude sitemap.

URL's verzamelen

Als eerste dien je een lijst te verzamelen met de URL's die in jouw oude website aanwezig zijn. Als basis kun je het beste gebruik maken van een sitemap.xml bestand, deze is meestal uit het systeem te halen door naar http://www.jouwsite.nl/sitemap.xml te navigeren, maar dit kan per systeem verschillen. Soms kan het opvragen van de robots.txt indien aanwezig meer informatie geven: http://www.jouwsite.nl/robots.txt.

Zodra je de sitemap hebt dien je elke URL op een aparte regel te zetten in een nieuw tekstbestand. Zorg dat elke URL op een eigen regel staat en haal het domein inclusief de eerste slash weg zodat je een resultaat krijgt dat op onderstaande lijkt:

/oude/url/die/niet/meer/bestaat.html
/lelijke?url=kan&echt=niet&meer
/article.php?id=123

Wanneer je geen sitemap hebt kun je natuurlijk ook handmatig een lijst van URL's opstellen, bijvoorbeeld door in Google te zoeken op "inurl:jouwsite.nl", zolang het resultaat er maar uit ziet zoals bovenstaand voorbeeld.

Tekstuele Rewritemap opstellen

Elke rewritemap bestaat uit twee kolommen: de eerste kolom is de match, de bron of de afkomstige URL en de tweede kolom de target of de doel URL. Deze twee kolommen worden gescheiden door een aantal tabs of spaties (wij adviseren één tab te gebruiken). Verzamel voor elke oude URL een matchende nieuwe URL en zorg dat jouw bestand er ongeveer als volgt uit gaat zien:

oude/url/die/niet/meer/bestaat.html     /nieuwe/url/die/wel-bestaat.html
oude/url/naar/homepage                  /
oude/url/naar/pagina-met-hastag.html    /pagina/met/hash#tag

Let er op dat er maximaal één redirect per regel staat en dat de bron gescheiden is van het doel. Sla dit bestand op als tekstbestand in de public_html van jouw website, bijvoorbeeld /var/www/html/migrate.txt.

Rewriterules opstellen

De rewriterules worden in eerste instantie opgesteld in het .htaccess bestand, maar kunnen ook direct in het VirtualHost bestand geplaatst worden. We gebruiken het tekstbestand als basis maar converteren dit later naar een DBM-map waar Apache sneller mee kan werken.

We geven twee voorbeelden waarop de redirects ingesteld kunnen worden:

  1. 301 redirects van source naar destination:
    De bron-links zoals deze in de eerste kolom van de rewritemap staan worden één op één gebruikt om te bepalen naar welke url er geredirect moet worden. Wanneer de gebruiker naar een oude link op de site surft wordt hij automatisch doorverwezen naar de nieuwe variant.
  2. 301 redirects op basis van een numerieke source:
    De bron-links zoals in de eerste kolom zijn geen urls maar numerieke waarden. Dit is vaak handig bij verouderde blog- of nieuwssite systemen, waarbij het artikel steeds met een ID wordt gedefinieerd, maar waarbij de rest van de URL steeds gelijk blijft.  

301 redirects van source naar destination

Hiervoor plaatsen we de volgende inhoud in het .htaccess bestand:

# Create a new rewritemap with "migration" as identifier. Change path accordingly
Rewritemap migration txt:/var/www/html/rewritemap.txt

# Enable rewrite-engine
RewriteEngine On
# Check if current request exists in rewritemap
RewriteCond ${migration:$1} !^$ [NC]
# If request exists, apply 301 redirect to whats set in right column
RewriteRule ^(.+)$ ${migration:$1} [NE,L,R=301]

Bovenstaand wordt allereerst de rewritemap met als naam migration gedefineerd (zorg dat het pad klopt). Vervolgens wordt de RewriteEngine ingeschakeld en wordt er alleen geforward als de URL is gevonden. Plaats deze regels boven RewriteRule's die eventueel al aanwezig zijn in het systeem, zodat als een item niet bestaat in het txt-bestand, de normale actie uitgevoerd kan worden (het betreffende CMS zal dan waarschijnlijk een 404 pagina tonen).

301 redirects op basis van een numerieke source

Gebruik deze methode als URL's in jouw oude CMS er bijvoorbeeld als volgt zien:

article.php?action=showarticle&id=1234

Hierbij is elke URL steeds hetzelfde op één unieke ID na. Zorg allereerst dat jouw txt-bestand in de eerste kolom niet de gehele URL heeft maar slechts dit unieke id:

1     /nieuwe/url/voor/artikel-een.html
2     /nieuwe/url/voor/artikel-twee.html
3     /etc.html

Vervolgens kunnen we nagenoeg dezelfde rewrite-regels gebruiken als bovenstaand voorveeld, uitgezonderd de rewrite-condition en rule zelf:

# Create a new rewritemap with "migration" as identifier. Change path accordingly
Rewritemap migration txt:/var/www/html/rewritemap.txt

# Enable rewrite-engine
RewriteEngine On
# Check if query-string end with something like "id=123"
RewriteCond %{QUERY_STRING} id=[0-9]+
# When matches, grep id out of query string and redirect to it
RewriteRule id=([0-9]+)$ ${migration:$1} [NE,L,R=301]

Bovenstaande regels gelden in dit geval alleen voor URL's die eindigen op id=XXX. Voor andere URL's dient de RewriteCond en RewriteRule regel aangepast te worden. Hierbij geldt ook dat de redirect alleen plaatsvindt als de ID aangetroffen is in de Rewritemap.

De flags [NE,L,R=301] gebruiken we voor "Non Escaping" om te zorgen dat urls met hashtags en questionmarks niet worden veranderd, "Last" zorg dat er geen andere RewriteRules meer geprobeerd worden, mits deze regel matcht en "Redirect" met een HTTP 301 header (301 staat voor "Moved Permanently" vert. "Permanent Verplaatst")

Default value: wat als het item niet in de Rewritemap bestaat

In de meeste gevallen zijn er al RewriteRules aanwezig voor het betreffende CMS. Waneer een item dan niet is gevonden in de rewritemap, zal de URL zoals deze is exact opgepakt moeten worden door het CMS, welke waarschijnlijk een "pagina niet gevonden" zal genereren. Als dit echter niet het geval is, kan er gebruik gemaakt worden van een default value, deze kan worden toegevoegd aan het onderdeel waar je de RewriteMap specificeerd:

${migration:$1|/page-not-found.html}

Rewritemaps debuggen

Voor het debuggen van Rewritemaps kun je o.a. gebruik maken van de volgende methoden:

  1. De debugging mogelijkheden in Apache
  2. De headers opvragen via cURL

Verder dien je onderstaande te controleren:

  1. Zorg dat het pad van de Rewritemap juist in het .htaccess of VirtualHosts bestand is geplaatst en dat het bestand leesbaar is voor de www-data gebruiker;
  2. Na elke aanpassing in de Rewritemap dien je service apache2 reload uit te voeren zodat de rewritemap opnieuw wordt ingeladen. Gebruik eerst apachectl configtest om zeker te zijn dat jouw configuratie foutloos is;
  3. De redirects kunnen in de browsercache opgeslagen zijn, waardoor jouw laatste aanpassingen niet te zien zijn, leeg je browsercache na elke aanpassing of maak gebruik van onderstaande cURL commando;
  4. Controleer eventueel /var/log/apache2/other_vhosts_access.log voor aanvullende info.

Rewritemaps debuggen d.m.v. Apache logs

Standaard wordt er geen informatie gelogd over de Rewritemaps. Hiervoor dien je het LogLevel in Apache te verhogen zodat mod Rewrite meer details laat zien. Dit verschilt enigszins per versie van Apache:

Logging in Apache2.2

RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 3

Open vervolgens het logbestand voor de output:

tail -f /var/log/apache2/rewrite.log

Logging in Apache 2.4

LogLevel alert rewrite:trace6

Open vervolgens het logbestand voor de output:

tail -f /var/log/apache2/error.log

301 Redirects debuggen dmv cURL

Omdat 301-redirects vast blijven zitten in de cache van je browser, is het het handigst om gebruik te maken van bijvoorbeeld cURL, zodat je de headers van het response kunt onderzoeken. Je kunt dan precies zien naar welke pagina er geredirect wordt en of dit dan ook de juiste pagina is:

curl -I -L https://www.perfacilis.com/home.html

Wanneer je in het resultaat "HTTP/1.1 301 Moved Permanently" en vervolgens "HTTP/1.1 200 OK" krijgt, weet je in ieder geval dat er eerst een redirect en een uiteindelijke pagina wordt weergegeven. De regel beginnend met "location" geeft aan waar er precies naartoe wordt geredirect.

Een DBM map genereren met httxt2dbm

Wanneer alles naar behoren functioneert kun je het txt-bestand omzetten naar een DBM bestand, waardoor Apache sneller de juiste redirect zal vinden:

httxt2dbm -i rewritemap.txt -o rewritemap.dbm

Vervolgens kun je in je .htaccess of VirtualHosts bestand het nieuwe DBM bestand instellen:

Rewritemap migration dbm:/var/www/html/rewritemap.dbm

Herstart of herlaad Apache zodat de rewritemap juist wordt ingeladen.

Rewritemaps resultaat

Het uiteindelijke resultaat zou het allerbeste niet in een .htacces bestand geplaatst moeten worden, gezien dit bestand bij elk verzoek ingelezen moet worden. Het is beter om hier gebruik te maken van een VirtualHosts bestand, wat er ongeveer als volgt uit kan zien:


ServerName www.vettenieuwesite.nl
DocumentRoot /var/www/html

# Disable debugging for production environments
#LogLevel alert rwrite:trace6
RewriteMap migration dbm:/var/www/html/rewritemap.dbm


RewriteEngine On
RewriteCond ${migration:$1} .+
RewriteRule ^(.+)$ ${migration:$1} [NE,L,R=301]

# Fallback rewrite rules, these may vary based on your system
# Place Wordpress' default RewriteRules insteds of these two lines
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L]

Conclusie

De exacte configuratie zal per installatie verschillen, maar de basis blijft wat het Rewritemap-proces betreft steeds min of meer gelijk. Wanneer je van deze methode gebruik maakt weet je in ieder geval zeker dat het aantal 404-errors dat na een migratie meestal optreedt tot het minimale beperkt kan worden.