_redirects doesn't work as expected

GitLab has _redirects. I thought this would be a perfect opportunity to redirect www.example.com => example.com.

So I tried this:

# www -> non-www
https://www.example.com/* https://example.com/:splat 301

This site is hosted on GitLab Pages.

But then a funny issue appeared: the redirect only works for non-existent pages.

For example:

  1. Existing page
>curl -L -I https://www.example.com/qa
HTTP/1.1 302 Found
Content-Type: text/html; charset=utf-8
Location: //www.example.com/qa/
Permissions-Policy: interest-cohort=()
Vary: Origin
X-Request-Id: 01K3JTJV6DSX5JHQPVEXB7ACPP
Date: Tue, 26 Aug 2025 09:15:42 GMT

HTTP/1.1 200 OK
Cache-Control: max-age=600
Content-Length: 33602
Content-Type: text/html; charset=utf-8
Etag: "a940c5e6f3d8078d5c6f2b4b0b4646b912c7c0bdb205544f642e6130e2bf02dc"
Expires: Tue, 26 Aug 2025 09:25:42 UTC
Last-Modified: Tue, 26 Aug 2025 00:56:23 GMT
Permissions-Policy: interest-cohort=()
Vary: Origin
X-Request-Id: 01K3JTJVEG4EXVRFHESSSHZTS3
Date: Tue, 26 Aug 2025 09:15:42 GMT

We can see that it redirected back to www.example.com/qa.

  1. Non-existent page
>curl -L -I https://www.example.com/fake
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=utf-8
Location: https://example.com/fake
Permissions-Policy: interest-cohort=()
Vary: Origin
X-Request-Id: 01K3JTM1PF91KEAY6B6R8N065C
Date: Tue, 26 Aug 2025 09:16:22 GMT

HTTP/1.1 404 Not Found
Content-Length: 16371
Content-Type: text/html; charset=utf-8
Permissions-Policy: interest-cohort=()
Vary: Origin
X-Request-Id: 01K3JTM27900VABQ4F7944RAGQ
Date: Tue, 26 Aug 2025 09:16:22 GMT

And here the redirect did work!


Is this expected behavior for _redirects on GitLab Pages, or am I missing something in the configuration?

Can you share the validation being OK following these debug steps?

I added two subdomains (www and podcast):

# www -> non-www
https://www.example.com https://example.com 301
https://www.example.com/ https://example.com/ 301
https://www.example.com/* https://example.com/:splat 301

# podcast -> /podcast/
https://podcast.example.com https://example.com/podcast/ 301
https://podcast.example.com/ https://example.com/podcast/ 301
https://podcast.example.com/* https://example.com/podcast/ 301

Validation looks fine:

6 rules
rule 1: valid
rule 2: valid
rule 3: valid
rule 4: valid
rule 5: valid
rule 6: valid

When I test it, I see this behavior:

>curl -L -I https://podcast.example.com
HTTP/1.1 200 OK
Cache-Control: max-age=600
Content-Length: 30503
Content-Type: text/html; charset=utf-8
...

>curl -L -I https://podcast.example.com/fakepage
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=utf-8
Location: https://example.com/podcast/
...

HTTP/1.1 200 OK
Cache-Control: max-age=600
Content-Length: 40684
Content-Type: text/html; charset=utf-8
...

So the redirect does not happen for an existing page, but it does happen for a non-existent one.

Interesting, thanks. One last thought before I ask to create a bug report issue - 301 redirects are cached by the browser permanently. Maybe there is a previous test session “hardcoded” in browser cache. Can you test with different empty-cache (incognito) browsers to verify and rule that out?

I tested with curl (no browser cache involved) and also from a mobile browser.

But…

I think I’ve found the answer… and frankly speaking, I don’t like it :slightly_smiling_face:

https://docs.gitlab.com/user/project/pages/redirects

Files take priority over redirects. If a file exists on disk, GitLab Pages serves the file instead of your redirect. For example, if the files hello.html and world.html exist, and the _redirects file contains the following line, the redirect is ignored because hello.html exists:

/project-slug/hello.html /project-slug/world.html 302

GitLab does not support Netlify force option to change this behavior.

This explains everything. and at the same time, it doesn’t really solve much :slightly_smiling_face:

Honestly — that makes the feature far less useful. It does not work as a solution for domain canonicalization (www → apex, subdomain → path, etc.). And I don’t really see real-world scenarios where domain-level redirects would be effective under these limitations.

Glad you found the root cause. I don’t know exactly how GitLab Pages are implemented, need to defer what I found in the docs. I’d suggest opening an issue with your proposal and feedback, linking this topic and discuss with engineers :slight_smile:

Thnx! I just filed an issue with description and suggestion:

:backhand_index_pointing_right: https://gitlab.com/gitlab-org/gitlab/-/issues/565802

Leaving the link here in case anyone else runs into the same problem.

1 Like