Redirect old forum URLs to new Discourse URLs using permalinks

Redirecting Old Forum URLs to New Discourse URLs using permalinks

If you’ve moved from other forum software to Discourse using one of our import scripts, then you probably want all your hard-earned Google search results to continue pointing to the same content. Discourse has a built-in way to handle this for you as an alternative to writing nginx rules, using the permalinks lookup table.

The permalinks table allows you to set two things: a url to match, and what that url should show. There are a few options for defining where the url should redirect to. Set one of these:

  • topic_id: to show a topic
  • post_id: to show a specific post within a topic
  • category_id: to show a category
  • external_url: to redirect to a url that may not belong to your Discourse instance

For example, if your original forum’s topic urls looked like http://example.com/discussion/12345, and the url for that topic after the import is http://example.com/t/we-moved/987, then you can setup the mapping like this:

cd /var/discourse
./launcher enter app
rails c
Permalink.create(url: '/discussion/12345', topic_id: 987)

Discourse will then perform a redirect with http response status code 301 (permanently moved) to the correct url for topic id 345. The 301 should cause search engines to update their records and start using the new urls.

If you want some urls to redirect away from Discourse, you can do so by setting external_url:

Permalink.create(url: '/discussion/12345', external_url: 'http://archived.example.com/discussion/12345')

Additional Information

To find the id of a subcategory, you can look it up by the slug like this:

Category.find_by_slug('products').id

To delete the permalink for that url, do this:

Permalink.find_by_url("/blah").destroy

There can be only one permalink record per url, so just search by url.

Creating a topic map from MyBB to Discourse

Discourse to WordPress redirect questions

Permalink Normalization


Last Reviewed by @SaraDev on 2022-06-03T20:00:00Z

Last edited by @martin 2024-12-16T06:03:09Z

Check documentPerform check on document:
36 Likes

Is it possible to store the rewrite rule directly in the discourse docker cluster? There is a web server that takes care of http and ssl, can I add something there?

location /threads/ {
    rewrite ^/threads/(.*)\.\d+/?$ /t/$1 permanent;
}

I don’t see how that can possibly work since nginx doesn’t know the new topic IDs. The /threads IDs need to be converted to the Discourse topic id.

if I call /threads/name.1234 then it is rewritten to /t/name and then it shows me the correct post, the id is not used at that moment, I just tested that.

Probably only when you’re lucky and Discourse and your old forum generate the same slugs (and the slug doesn’t start with a number), but that’s probably good enough.

If you want to change the NGINX as you suggest, you can look at the web template in discourse_docker to see how to change the nginx config inside the container. Here’s an example:

1 Like

thank you very much, I think it would be enough of a distraction

do i have to make this change with every update?

No. You’ll add that to your app.yml and it’ll get applied at every rebuild.

To save time testing you might:

cd /var/discourse
./launcher enter app
apt update
apt-get install -y vim nano

Then user vim or nano to edit whatever you want to see that it does what you think (and save 10-20 minutes per rebuild).You can restart nginx with `sv restart nginx.

None of the above is tested, but it should be close.

1 Like

thanks for the help, i have adjusted the nginx config and it works as desired.

1 Like

where in the app.yml must this be written so that the nginx is automatically adjusted? in the run area for the custom commands?

because (<unknown>): found unknown escape character while parsing a quoted scalar if i add this:

  - replace:
      filename: "/etc/nginx/conf.d/discourse.conf"
      from: "# auth_basic_user_file /etc/nginx/htpasswd;"
      to: "# auth_basic_user_file /etc/nginx/htpasswd;

      location /threads/ {
          rewrite ^/threads/(.*)\.\d+/?$ /t/$1 permanent;
      }"

Have a look at Set up Let’s Encrypt with multiple domains / redirects and use the same kind of thing as in that example that adds to the nginx config.

You can put it in the after_ssl hook (that you would add) as in that one.

i get still the same error I think it has something to do with my formatting.

1 Like