Zero-Downtime Server Migration: HTTP Redirects with Host Header Preservation During IP Change


5 views

html

When moving web servers to new infrastructure, the traditional DNS update approach creates a synchronization gap where some users hit the old server while others reach the new one. This becomes problematic when maintaining stateful applications or database consistency. The HTTP 301/302 redirect solution solves this by creating a unified traffic funnel.

For Apache servers, modify the virtual host configuration on your OLD server:

<VirtualHost *:80>
    ServerName yourdomain.com
    Redirect permanent / http://new-server-ip/
    ProxyPreserveHost On
    RequestHeader set Host "yourdomain.com"
</VirtualHost>

For Nginx configurations on the old server:

server {
    listen 80;
    server_name yourdomain.com;
    return 301 http://$server_name$request_uri;
    proxy_set_header Host $host;
    proxy_pass http://new-server-ip;
}

The critical component is maintaining the original Host header through the redirect chain. This example shows a Node.js middleware approach for seamless transition:

const express = require('express');
const app = express();

app.use((req, res, next) => {
    req.headers['x-forwarded-host'] = req.headers.host;
    next();
});

app.get('*', (req, res) => {
    res.redirect(301, http://${newServerIP}${req.url});
});

After implementing redirects, update your DNS TTL values 48 hours pre-migration:

; Reduce TTL for smoother transition
$TTL 300
@ IN A new-server-ip

Verify the redirect chain maintains host headers using curl:

curl -vIL -H "Host: yourdomain.com" http://old-server-ip/path

Check for these critical response elements:

HTTP/1.1 301 Moved Permanently
Location: http://yourdomain.com/new-path
Host: yourdomain.com

For MySQL/MariaDB environments, implement master-master replication during migration:

CHANGE MASTER TO
  MASTER_HOST='old-server-ip',
  MASTER_USER='replica_user',
  MASTER_PASSWORD='password',
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=123456;

When migrating servers with different IP addresses, DNS propagation delays create a synchronization nightmare. Users hitting old DNS records will reach your original server, while others see the new one - causing database consistency issues.

A naive 301 redirect from old-server to new-IP creates these problems:

# Bad example - loses host header
RewriteEngine On
RewriteRule ^(.*)$ http://203.0.113.45/$1 [R=301,L]

This makes browsers display the raw IP address, breaking SSL certificates and confusing users.

Instead of redirects, configure your old server as a reverse proxy:

# Apache config
<VirtualHost *:80>
    ServerName example.com
    ProxyPreserveHost On
    ProxyPass / http://203.0.113.45/
    ProxyPassReverse / http://203.0.113.45/
</VirtualHost>

# Nginx config
server {
    listen 80;
    server_name example.com;
    location / {
        proxy_pass http://203.0.113.45;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

During migration window:

  1. Configure master-slave replication from old to new server
  2. Set read-only mode on old server during final cutover
  3. Use this MySQL command to verify sync status:
    SHOW SLAVE STATUS\G

When proxies are active:

# Reduce TTL 24h before migration
$ dig +short example.com IN SOA
# Expected output shows TTL value

Update DNS records only after confirming proxy works perfectly.

For HTTPS traffic:

# Apache SSL proxy config
SSLProxyEngine On
SSLProxyCheckPeerCN off
SSLProxyCheckPeerName off

Ensure your new server has valid certificates for all domains.