Rewrite with redirect or redirect with regex

Hello!
Sorry for the repost from Github issue, but the issue is closed, and I’m afraid, nobody cares.

I ran single language blog with URLs like: /posts/<title>/, but now blog became multilanguage, and URLs changed to /en/<title>/, /ru/<title>/ and so on.
Default language is Russian, so, for now, rewrite looks like:

rewrite /posts {
  r (.*)
  to /ru{1}
}

This allows me to serve links from the wild internet, but I have a problem with Google: it gets angry when /posts/pyat-samyh-poleznyh-statey-bloga-amplifera/ and /ru/pyat-samyh-poleznyh-statey-bloga-amplifera/ has the same content and I need 301 here.

Is there any way to do something like:

redir /posts {
  r (.*)
  to /ru{1}
}

or

rewrite /posts {
  r (.*)
  to /ru{1}
  status 301
}

?

Thanks in advance.

Currently its not possible regex match with group reference and respond with 301 with either rewrite or redir directives.

The closest you will get is to direct /posts/<title> to a script that responds with a Location header. Like this.

Caddyfile

localhost:80
fastcgi / 127.0.0.1:9000 php
rewrite /posts {
	r (.*)
	to /_redirect.php?/ru{1}
}

_redirect.php

<?php
header('Status: 301 Moved Permanently');
header('Location: http://'.$_SERVER['HTTP_HOST'].$_SERVER['QUERY_STRING']);

Another option is to just use a PHP script on its own to do the matching

Caddyfile

localhost:8080
fastcgi / 127.0.0.1:9000 php
rewrite /posts {
	to /posts/index.php
}

/posts/index.php

<?php
$uri = preg_replace('/^\/posts(.*)/', '/ru$1', $_SERVER['REQUEST_URI']);
if($uri !== null){
	header('Status: 301 Moved Permanently');
	header('Location: http://'.$_SERVER['HTTP_HOST'].$uri);
}else{
	header('Status: 404 Not Found');
}

Not ideal. But it works for the moment to resolve your problem.


@matt: I think this issue has occurred because of the need to separate the responsibilities of the redir and rewrite directives. I think its worth discussing how to overcome this limitation and what the best solution is.

Since we have status on rewrite should we just add support for 3xx errors? I also noticed the if-matcher on redir is broken in some manner. Perhaps its easier to deprecate that in favor of rewrite with status and only use redir for simple 1-to-1 redirects?

Try this Caddyfile for redir bug.

localhost:8080
redir 301 {
	if {uri} starts_with /posts
	/ru/{uri}
}

Running curl -I http://localhost:8080/aaaa against this matches and redirects to /ru/aaaa same goes for if you try a condition with if {uri} match ^/posts/(.*). It seem’s as though the result of the conditional matcher is being ignored.

@slightfoot thanks for the suggestion!
I’ll try your solution but I fear adding PHP server for static files serving is a little overhead :wink:

Yea agreed. The config should support it. You could of course for the moment add a redir directive for each post if there’s not too many.

1 Like
# ls -l public/ru/|wc -l
114

Not as small as I want it to be in that case…