Problem with redirect regex after upgrade 3.0

The following redirection.json stopped working after I upgraded from Ghost 1.0 to 3.0.

[{
  "from":"^((?!\/content\/images).*?)/?$",
  "to":"https://www.domain.com/blog$1/",
  "permanent":false
  }]

We are trying to rewrite

blog.domain.com/this-is-article-1

to

https://www.domain.com/blog/this-is-article-1

and EXCLUDE rewriting when /content/images/ is in the url

It has been working well up to the point we upgraded. Now, every url we give will be written into https://www.domain.com/blog$1/. For some reason, the $1 captured group is not printing.

I have spent a few days trying to resolve this but it looks to me more like a bug than my incorrect regex.

Does anyone have similar experience? Thanks a lot.

Marcus

I think the to syntax should look like this:

  "to": "/blog/$1/"

Hi David. Doing this-

[{
  "from":"^.*?(\/(?!\/content\/images).*?)/?$",
  "to":"/blog/$1/",
  "permanent":false
  }]

gave me

https://blog.domain.com/blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//blog//article-1/

Are you trying to redirect from installation of Ghost to another?

My blog is hosted at the subdomain blog.xyzdomain.com.

I have downloaded the blog posts, and hosted them as static pages on Amazon S3.

They are currently deployed under a subpath xyzdomain.com/blog

So, i need to redirect articles from

https://blog.xyzdomain.com/article-1 to https://xyzdomain.com/blog/article-1

Hello David, I’ve got a similar use case.

In order to generate live Gatsby previews, I’m trying to redirect every Ghost preview link to a corresponding Gatsby client path.

{
	"from": "/p/(.*)//",
	"to": "/http://localhost:8000/preview/$1/",
	"permanent": false
}

However, this configuration wrongly results in a redirection from http://localhost:3001/p/0123/ to http://localhost:3001/http://localhost:8000/preview/0123/.

Is there any workaround? Thank you.

Why are you hosting them as static web pages? Could you not host Ghost there on the subpath?

I’d be interested to know if you have previews working within Gatsby, are you using the Admin API to get draft posts?

My ghost server is too slow and cannot handle high traffic.

Regardless, I think the question here is how to actually get the regex to work in Ghost 3.0.

I tried everything and it simply does not work!

  {
  "from":"^\\/(.*)/$",
  "to":"/blog/$1",
  "permanent":false
  },

Why does this regex result in http://localhost:2368/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/article-1? It makes no sense at this is surely a bug with the platform.

It makes perfect sense! You’ve written a regex that matches any path in Ghost and redirects it to /blog/[matched path]…

When Ghost gets a request for /blog/article-1 it will automatically redirect to /blog/article-1/ because all urls in Ghost must end with a trialing slash.

Now your regex "^\\/(.*)/$" matches /blog/article-1/ so it redirects to /blog/$1 which in this case would be /blog/blog/article-1/which again matches your regex and so it redirects again. And so on forever.

You need to write a more targeted regex, that doesn’t match things that start with /blog/ - here’s a starting point: https://regex101.com/r/AKcDZQ/1/

1 Like

Your “to” field starts with a /, which makes Ghost think this is a relative path…

I thought it was a way to tell Ghost to treat it as a regex. Because, you see, regex patterns are usually contained between two forward slashes. However, my assumptions–mixed with the brief documentation on the whole redirect.json topic–led me to the wrong outcome.

Removing the first slash does route me to localhost:8000, but it does not expand any captured group. Hence, I get redirected to http://localhost:8000/preview/$1/, with a literal $1 at the end of the path.

Hello David.

Yes, I’m using the Admin API. It would have been easier if the posts.read and pages.read methods accepted a uuid as URL parameter, but I got it working nonetheless.

The only missing piece is the redirect rule. Once that falls into place, I could call it a day and maybe contribute with a tutorial. How does one apply for that?

Thank you

Hi Hannah, you provided the following example

^\/(?!blog\/?).*

I took the example- and I added a capturing group, in order to retrieve it later again using $1. Surely this is more than sufficiently targeted now.

[{
  "from":"^\/(?!content\/images\/?)(.*)",
  "to":"/blog/$1/",
  "permanent":false
  }]

However it still redirects to

http://localhost:2368/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/blog/article-1//////////////////////////////////////////////////////////

What gives? Are you saying that we cannot use (.*)?

How do we write one general rule to match all URLs then? Surely this is not at all how conventional regex works.

Hi tortoise, your regex reads: match what starts with a slash, not followed by content/images/ (either with or without trailing slash), followed by 0 or more of anything.

With this definition in mind, you can now see why your redirection creates a loophole: when you redirect from /article-1 to /blog/article-1, the latter still matches the pattern. That’s because /blog/article-1 does start with a slash, is not followed by content/images, and is followed by 0 or more characters. Same goes for /blog/blog/article-1, and so on, and so on.

The piece of advice that @Hannah has tried to get across is that you should also exclude any entry that starts with /blog/. In your case, you should rewrite your regex, like so

1 Like

Would you benefit more from using JavaScript to redirect people to the Gatsby preview? Considering the editor would have to have JavaScript enabled then it would be pretty safe to rely on JavaScript to redirect them with a script that executes when someone tries to navigate to a preview :slight_smile:

Well, yes, it would work. AFAIK, there are two ways to do so: the first is to edit the {{ghost_head}} and place my script there; the second is to fork a Ghost theme and edit its source code. They both have drawbacks, though. The former is fast and low-keyed, but I can’t keep track of it with, let’s say, Git. The latter is traceable with Git, but it’s cumbersome and time-consuming to set up.

However, if I look between the lines, I can read that redirects.json is currently not an option, is it? So, in the end, the decision must be between those two. Are there other viable options I’m not aware of?

Thank you

With that reasoning redirects.json is probably the worst as it would have to be tracked in it’s own repo and manually uploaded to your Ghost admin. I have this very small snippet that would redirect the Ghost site to your Jamstack site:

Not really. I’m running Ghost inside a docker container, and I mounted its content directory to a volume inside my repository. This way, I can easily track the redirects.json file.

# docker-compose.yaml
version: '2.0'

services:
  ghost:
    image: ghost:3-alpine
    ports:
      - "3001:2368"
    environment:
      url: http://localhost:3001
    volumes:
      - .ghost:/var/lib/ghost/content
# .gitignore
.ghost/*
!.ghost/data
.ghost/data/*
!.ghost/data/redirects.json

Anyway, I’ll temporarily do as you’ve suggested. Thank you very much!

1 Like