Använda Apache mod_proxy för att flytta en webbsida

När man ska flytta en webbsida smidigt utan att orsaka nertid är det en hel del saker att tänka på. Det svåraste momentet är i själva ”skarven” när webbsidan finns på två ställen och innan DNS-ompekningen slagit igenom fullt ut.

Vissa DNS-leverantörer envisas också med att ha TTL-tider på ett dygn eller mer. Under den här tiden kan användare hamna på antingen den gamla eller nya sidan och ändra information, t.ex. nya inlägg eller annat innehåll. Nya ändringar som sker på den gamla sidan kommer då att gå förlorade.

Det finns i princip tre sätt att lösa problemet:

* Stänga av funktioner för att ändra sidans innehåll under övergångsperioden.
* Ändra TTL för DNS till 0 eller ett lågt värde några dagar i förväg.
* Skicka vidare alla anslutningar som kommer till gamla sidan till nya med t.ex. mod_proxy.

Det första alternativet fungerar om det är en kort period eller om sidans innehåll är okritiskt om det är lite gammalt. Det är ingen bra idé om det t.ex. rör sig om en nyhetssida.

Att ändra TTL fungerar bra, men det är inte alltid man har tillgång eller möjlighet att ändra DNS-inställningar.

Att skicka vidare anslutningar fungerar om man har tillgång till den gamla servern. Om den kör Apache så kommer här ett exempel på hur man kan gå till väga.

Se till att mod_proxy-modulen till Apache är aktiverad och start om Apache:

root@vps-nnnn:~# a2enmod proxy proxy_http
Enabling module proxy.
Considering dependency proxy for proxy_http:
Module proxy already enabled
Enabling module proxy_http.
Run '/etc/init.d/apache2 restart' to activate new configuration!
root@vps-nnnn:~# /etc/init.d/apache2 reload
 * Reloading web server config apache2   [ OK ] 

I din apache-konfiguration, helst i VirtualHost, lägg till din proxy-adress:

<virtualhost *:80>
    ServerName exempel.se
    ServerAlias www.exempel.se
    
    ProxyPreserveHost On
    ProxyPass / http://vps-yyyyy.cloudnet.se/
    ProxyPassReverse / http://vps-yyyyy.cloudnet.se/
    <Proxy http://vps-yyyyy.cloudnet.se/>
        Order Allow,Deny
        Allow from all
    </Proxy>
.....
</VirtualHost>

Starta om Apache.

Om t.ex. domänen www.exempel.se pekar till IP-adressen för vps-nnnnn.cloudnet.se så kommer alla webb-anslutningar till www.exempel.se skickas vidare till vps-yyyyy.cloudnet.se istället. Användaren märker ingenting och allt nytt data som läggs till eller ändras på webbsidan i antingen filsystemet eller någon databas kommer garanterat hamna på den nya webbplasten.

ProxyPass ser till att alla anslutningar skickas vidare. ProxyPassReverse ser till att all information som genereras av den nya webbplatsen har rätt URL. Annars måste man anpassa webbapplikationen. Med dessa två direktiv kommer URL inte ändras något och webbsidan ser ut precis som vanligt.

Direktivet ProxyPreserveHost krävs speciellt om webb-servern har flera vhost. Som standard i Apache är ProxyPreserveHost avstängt och det gör att vps-yyyyy.cloudnet.se (den nya servern) inte vet vilket domännamn som avses.

Med hjälp av tcpdump är det enklare att förklara, om ProxyPreserveHost är avstängt kommer anslutningen till vps-yyyyy.cloudnet.se innehålla något i stil med:

Host: vps-yyyyy.cloudnet.se
Via: 1.1 www.exempel.se
X-Forwarded-For: 192.168.1.1
X-Forwarded-Host: www.exempel.se
X-Forwarded-Server: www.exempel.se

Som du ser så är Host satt till proxy-servern och inte webbplatsen som ska besökas. Istället skickar Apache med en Via– och några X-Forwarded-rader. Det betyder att den applikation som svarar på den nya servern måste kunna tolka dessa rader, och det kan den normalt sett inte.

Om ProxyPreserveHost däremot är påslaget så kommer inte Apache lägga till några Via– eller X-Forwarded-rader. Istället behålls Host som det var ursprungligen:

Host: www.exempel.se

Nu kan man i lugn och ro peka om DNS och vänta tills det slagit igenom överallt. En bonus är att det är enkelt att byta tillbaka om man märker att man gjort något fel på den nya servern.

Råkar det vara HTTPS som ska proxayas så krävs lite extra, lägg till SSLProxyEngine:

<virtualhost *:80>
    ServerName exempel.se
    ServerAlias www.exempel.se
    SSLProxyEngine On
    SSLProxyCheckPeerCN on
    SSLProxyCheckPeerExpire on
    ProxyPreserveHost On
    ProxyPass / http://vps-yyyyy.cloudnet.se/
    ProxyPassReverse / http://vps-yyyyy.cloudnet.se/
    <Proxy http://vps-yyyyy.cloudnet.se/>
        Order Allow,Deny
        Allow from all
    </Proxy>
.....
</VirtualHost>