Moving a WordPress site from one domain to another

1. Caddy version (caddy version):

root@caddy:~ # caddy version
v2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=

2. How I run Caddy:

a. System environment:

root@caddy:~ # uname -a
FreeBSD caddy 12.2-RELEASE-p10 FreeBSD 12.2-RELEASE-p10 b26f74b5984(HEAD) TRUENAS  amd64

b. Command:

service caddy start

c. Service/unit/compose file:


d. My complete Caddyfile or JSON config:

Frontend Caddy reverse proxy (relevant extract)

(proxy-host) {
  @{args.0} host {args.0}
  reverse_proxy @{args.0} {args.1}
    import proxy-host   blog  

Backend Caddy web server serving WordPress PHP files.

#    debug
    log {
        format json {
            time_format iso8601

:80 {
    log {
        format json {
            time_format iso8601
        output file /var/log/caddy/access.log {
            roll_keep 7

    root * /usr/local/www/wordpress
    encode gzip zstd
    php_fastcgi {
        env SERVER_PORT 80

    # External access denied to these files.
    @forbidden {
        not path /wp-includes/ms-files.php
        path /wp-admin/includes/*.php
        path /wp-includes/*.php
        path /wp-config.php

        path /wp-content/uploads/*.php
        path /.user.ini
        path /wp-content/debug.log
    respond @forbidden 403

    # Mitigate spam attack logins and comments
    @protected path_regexp (wp-comments-posts|wp-login)\.php$
    handle @protected {
        @no-referer {
            not header Referer https://{host}*
            method POST
        abort @no-referer

3. The problem I’m having:

A couple of years ago, I moved my blog site off a somewhat restrictive subdomain of ( and decided to self-host at I managed to export the site off and successfully imported the site to a local instance of WordPress. Text and media came across successfully.

It’s recently come to my attention though that hyperlinks to other blog posts were not updated. Clicking on these on the relocated site would send me back to a post on the old site.

For example, clicking on the link below in the blog post Digitising VHS Tapes: Part 1(3) – Digitising Process Considerations

In Part 2 of this series, I attempt a repair on my failed Samsung VCR.

…sent me off to the old site article instead of the equivalent new site article

4. Error messages and/or full log output:


5. What I already tried:

I can probably use a WordPress plugin such as Go Live Update Urls to search and replace instances of the old URL with the new one, but this seems a bit like a sledgehammer approach. I’m sure I can do better.

There are at least three Caddy directives that I feel might do the job for me (see the next section), but:

  1. I’m not sure which is the right tool for the job; and
  2. I lack the confidence and know-how to apply the tool.

For instance, I note that the only difference in the hyperlink example I provided above is the domain name so I tried the following in the hope that it would work. but it didn’t.

uri replace / /

Is there a way to use Caddy to address this issue with a bit more finesse and elegance than the approach the plugin uses?

6. Links to relevant resources:

  1. uri (Caddyfile directive) — Caddy Documentation
  2. rewrite (Caddyfile directive) — Caddy Documentation
  3. redir (Caddyfile directive) — Caddy Documentation

Honestly, that seems like the best approach. Updating the actual data to have the correct URLs is better, because any other solution will just be hacky.

This would only work to replace the URI on requests which actually reaches your Caddy server. If the request is for a different domain altogether which won’t reach Caddy, then this will never be effectual.

This directive also can’t replace a domain, because it operates on the part of the URI that comes after the domain, which is the path & query.

rewrite and uri are both rewrites, just with slightly different behaviour and feature sets depending on the needs.

redir basically just writes a response with a Location header, but again, this will never run if the request never reaches your server. So it’s not useful here either.

What you’d actually need is the replace_response plugin which can perform streaming string replacements on the responses before they’re sent back to the browser, so you could modify the contents before users click on the links.

But this is a hack, and can harm performance, and means you’re “doing work” on every single request to check for old links and replace them, even for new pages which were created after your site was moved.

It’s way simpler to just update the existing data once and be done with it.


A note for other WordPress users who find themselves in the same boat. I ended up settling on the Better Search Replace WordPress plugin to do the job as it has a dry-run feature, which gave me an insight into what tables would be updated before committing to those changes.

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.