When a client of yours is moving a web site between two servers, of course the best option is to plan some time during which modification is prohibited and everything is moved as fast as possible. This ensures that you do only one operation and that everything follows.
However, in some cases, the client can desire to move more slowly in order to rearrange the new site or to filter out content prior to making it available on the new server, or there might be some transition issues that she doesn't want to revisit. In such cases, the web site will need to be available from two locations at once for some time.
In that case, you can help out by reverse proxying to the new server.
disclaimer: yeah, I know this stuff is kinda ugly, but it lets your client have the control over what is happening, and in some cases1 this'll make them really happy.
Add a subdomain
First, add a subdomain, either to the client's domain or to your own. For the purpose of examples, let's say the domain that needs to transition slowly is example.com. We'll add rproxy.example.com and point it to the new server's IP.
Do the reverse proxy dance
This is no magic trick. And since we're talking about Nginx here, it's very easy to setup.
Add a server
block to your Nginx config (in debian, it could be in the file under /etc/nginx/sites-available
in which you configured the server
block for the regular site -- e.g. example.com). Your new server
block should look somewhat like the following:
server {
server_name rproxy.example.com;
root /var/www/example.com; ## whatever..
location / {
proxy_pass http://127.0.0.1/;
proxy_redirect off;
proxy_set_header Host example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Notice that you're actually forcing the value of the Host
header to a different value than what you're accessing (the usual technique with reverse proxying is to set that header to $host
, by which you're hopefully accessing the site. So in more practical terms, the domain name by which you're accessing the reverse proxy is actually the one that should be the web site's "official" domain name. Here, that's not what we want to do, we want to setup a temporary alternate domain name.)
This'll get your server to hand you the content. But something's off: every link inside the content will point back to the original domain name, on the server that is in production. So, if your client wants to change anything other than the html, they won't see the results. Also, the client won't be able to directly navigate the site since all URLs will point back to the old server.
Search and replace (filter)
Enter the HttpSubModule Nginx module. Hopefully your Nginx instance will have been compiled with support for it. In debian the packaged binary does come with it.
To ensure that every link (anchors, css, js, images, other media files) is points to the new server, we'll have to make Nginx replace all occurrences of the old domain name into the temporary subdomain. Add those lines into the server
block:
sub_filter example.com rproxy.example.com;
sub_filter_once off;
Now you can see the result that really comes from the new server, plus you should be able to navigate the new site without being thrown off on the old server.
It's not all advantages, though
There is a drawback with this method, though: you can only have one sub_filter
directive per location
block inside a server
block. So if the site involves multiple domains or subdomains at once, you'll only be able to modify one of them (most likely the one on which the site currently lives). This is the reason for the disclaimer above, it is very ugly and shouldn't be used as a permanent solution.
Let's recapitulate
Here's the full server
block, for a better overview of the result:
server {
server_name rproxy.example.com;
root /var/www/example.com; ## whatever..
location / {
proxy_pass http://127.0.0.1/;
proxy_redirect off;
proxy_set_header Host example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
sub_filter example.com rproxy.example.com;
sub_filter_once off;
}
}