I recently renamed this site from magnushansson.xyz to magnusopus.xyz.
The plan sounded trivial:
magnushansson.xyz -> magnusopus.xyz
Keep the old domain around, permanently redirect it to the new one, and forget about it. Namecheap, where the domain is registered, even has a feature called “URL Redirect Record”. So I added a permanent redirect:
magnushansson.xyz -> https://magnusopus.xyz/
Then I tested it.
http://magnushansson.xyz
worked.
But:
https://magnushansson.xyz
didn’t.
A simple redirect turned into a useful example of how DNS, TLS, HTTP, registrars, and reverse proxies fit together.
A redirect is not something DNS does.
It is an HTTP response:
HTTP/1.1 301 Moved Permanently
Location: https://magnusopus.xyz/
The browser connects to magnushansson.xyz, makes an HTTP request, receives this response,
and then makes another request to magnusopus.xyz. DNS has a different job. It answers a question closer to:
magnushansson.xyz -> some IP address
That distinction matters because with HTTPS there is another protocol step before the browser can receive the redirect.
Suppose the browser opens:
https://magnushansson.xyz
Before it can receive an HTTP response, it first needs to establish a TLS connection. Roughly:
Browser
|
| Where is magnushansson.xyz?
v
DNS
|
| IP address
v
Server
|
| TLS handshake
| "Prove you are magnushansson.xyz"
v
Browser
|
| GET /
v
Server
|
| 301 Moved Permanently
| Location: https://magnusopus.xyz/
v
Browser
The important ordering is:
DNS -> TLS -> HTTP -> Redirect
The server has to successfully complete TLS for magnushansson.xyz before it can return
the HTTP 301.
That is why a basic HTTP redirect is not enough for an old HTTPS domain. The redirect
comes too late to solve the certificate problem.
Domain registrars often bundle several services into one control panel, which can make the underlying roles look more unified than they are.
In reality, these are separate functions:
These roles can all be handled by different companies.
My final setup became:
magnushansson.xyz
|
| registered at
v
Namecheap
|
| nameservers
v
Cloudflare
|
| HTTPS + 301 redirect
v
magnusopus.xyz
|
| DNS
v
GitHub Pages
GitHub Pages hosts the actual blog. Namecheap still manages the registration of both domains. Cloudflare handles DNS, TLS, and the redirect for the old domain.
To move DNS authority for magnushansson.xyz to Cloudflare, I replaced Namecheap’s
nameservers:
dns1.registrar-servers.com
dns2.registrar-servers.com
with the nameservers Cloudflare assigned to the domain. This does not transfer the domain registration. Namecheap remains the registrar. Renewals still happen there. What changes is the answer to:
Which DNS servers are authoritative for
magnushansson.xyz?
Before:
Ask Namecheap.
After:
Ask Cloudflare.
The global DNS hierarchy now delegates responsibility for the domain’s DNS records to Cloudflare. That distinction between domain registration and DNS authority is useful because they are often provided by the same company, but they do not have to be.
Cloudflare sits in front of the old domain as a reverse proxy.
When a browser opens:
https://magnushansson.xyz
it connects to a Cloudflare edge server.
Cloudflare can present a valid TLS certificate for magnushansson.xyz, complete the TLS
handshake, receive the HTTP request, and return the redirect:
Browser
|
| HTTPS
v
Cloudflare
|
| valid certificate for magnushansson.xyz
|
| 301
| Location: https://magnusopus.xyz/
v
Browser
|
| HTTPS
v
GitHub Pages
There is no actual website behind magnushansson.xyz anymore.
The request is handled at Cloudflare’s edge, so Cloudflare does not need to contact an
origin server for requests that match the redirect rule.
This is also why the setup can be free for a small personal site. The redirect is a tiny
rule running on infrastructure Cloudflare already operates at enormous scale.
Redirecting the root domain is not enough.
If an old link points to:
https://magnushansson.xyz/posts/some-post
the useful behavior is:
https://magnusopus.xyz/posts/some-post
not:
https://magnusopus.xyz/
The Cloudflare rule is essentially:
concat("https://magnusopus.xyz", http.request.uri.path)
with query-string preservation enabled.
So:
https://magnushansson.xyz/posts/foo?x=1
becomes:
https://magnusopus.xyz/posts/foo?x=1
The redirect uses HTTP status code 301, meaning the move is permanent.
That is useful for old links, bookmarks, and search engines.
Another possible setup would be:
magnushansson.xyz \
-> GitHub Pages
magnusopus.xyz /
But that would make both domains valid addresses for the same site. That is not what I wanted. The old domain should permanently resolve to the new canonical domain:
magnushansson.xyz -> 301 -> magnusopus.xyz
rather than:
magnushansson.xyz -> same content
magnusopus.xyz -> same content
Having one canonical domain keeps URLs, indexing, analytics, and links cleaner. GitHub Pages also expects a primary custom domain for a site, so handling the old domain as a redirect at the edge keeps the architecture simple.
The resulting architecture is small:
GitHub Pages
^
|
magnusopus.xyz
Namecheap DNS
^
|
canonical site
magnushansson.xyz
Namecheap registrar
|
| NS delegation
v
Cloudflare DNS + TLS
|
| 301
+------------------> magnusopus.xyz
There is no VPS. No nginx configuration. No web server for the old domain. No paid hosting. Just DNS delegation, TLS termination, and one redirect rule.
The interesting part of the exercise was not the Cloudflare configuration itself. It was that a redirect, which looks like one simple browser operation, depends on several independent layers of the web stack.
When a browser opens:
https://example.com
DNS has to resolve the domain. A network connection has to be established. TLS has to authenticate the server and establish encryption. Only then does HTTP enter the picture. Only then can the server return:
301 Moved Permanently
A redirect is simple at the HTTP layer. Getting to the HTTP layer is where the rest of the machinery lives. Sometimes a small infrastructure task is a better explanation of the web than a diagram in a networking textbook.