Trailing slash and routes - traefik

I recently started experimenting with traefik and I'm swiching over from nginx.
I'm a bit confused by how the paths in Path, PathStrip, PathPrefix and PathPrefixStrip work regarding trailing slashes.
In nginx for proxied requests this is the documentation:
If a location is defined by a prefix string that ends with the slash
character, and requests are processed by one of proxy_pass,
fastcgi_pass, uwsgi_pass, scgi_pass, or memcached_pass, then the
special processing is performed. In response to a request with URI
equal to this string, but without the trailing slash, a permanent
redirect with the code 301 will be returned to the requested URI with
the slash appended. If this is not desired, an exact match of the URI
and location could be defined like this:
location /user/ {
proxy_pass http://user.example.com;
}
location = /user {
proxy_pass http://login.example.com;
}
How would it be possible to replicate this behaviour?
Essentially I’d like traefik to append the trailing slash when not present, so that PathPrefixStrip:/mylocation/ will also match /mylocation and issue a 301 for /location/.
In addition I'm a bit confused by the difference between Path and PathPrefix when used as Modifiers, is there some documentation that explains the difference in their respective behaviour?
Thank you.

This question is old, still helpful for novice traefik users.
This question was probably related with traefik 1.x, here the official matchers documentation for 1.7
It stands:
Path: /products/, /articles/{category}/{id:[0-9]+} Match exact request path. It accepts a sequence of literal and regular expression paths.
...
PathPrefix: /products/, /articles/{category}/{id:[0-9]+} Match request prefix path. It accepts a sequence of literal and regular expression prefix paths.
Also their are very clear about path Path Matcher Usage Guidelines
But this is old and deprecated in favor of the current version. So check the latest documentation
The traefik is very different on 2.x version. You can check the migration guide here
Now you need to setup:
entrypoints
routers
middlewares
services
In your router, the rule property is where your set the Path or PathPrefix matcher. The rule reference are here
Path(/path, /articles/{cat:[a-z]+}/{id:[0-9]+}, ...) Match exact request path. It accepts a sequence of literal and regular expression paths.
PathPrefix(/products/, /articles/{cat:[a-z]+}/{id:[0-9]+}) Match request prefix path. It accepts a sequence of literal and regular expression prefix paths.

Related

Apache 2.4 rewriting directory URLs without trailing slash to https://default_site/dir/ instead of preserving domain

This is a relatively recent behavioral change and appears to be related only to requests which include a "Upgrade-Insecure-Requests: 1" request header.
Apache has started rewriting such requests for sites which are HTTP-only to an HTTPS URL using the default site name instead of just adding the / at the end of the requested URL.
Example: URL submitted in browser: http://www.example.com/blah
Intended redirect: 301 to http://www.example.com/blah/
Instead redirects: 301 to https://default.site.configured/blah/
This happens whether it's a named virtual on the same address as the default server or a virtual using a separate address with separate Listen directives.
I understand all the arguments in favor of the idea that everything should always be encrypted and I don't want to get into a debate about that. This site doesn't consider the tradeoffs desirable at this time.
The default site does have SSL and is configured to redirect HTTP->HTTPS, but the www.foo.com site is not configured that way and does not wish to implement SSL at this time.
Is there any way to get Apache 2.4 to disregard that "Upgrade" header and simply rewrite the URL as desired rather than altering the domain name?
After banging on this some more, I finally found the source of my woes.
This happens when you have IP based virtual hosts and did not configure a name for them using the "ServerName" directive.
tl;dr: If you are having this problem, try adding a "ServerName www.example.com" directive within the VirtualHost definition for the site and that should resolve it.
Details:
It does not happen until you encounter a URL that requires a rewrite other than adding a trailing /. (i.e. if you get a request that doesn't contain the "Upgrade-Insecure-Requests: 1" header, it only gets the trailing / added, but if you get one with that header, it also tries to rewrite the protocol to https which triggers the full URL rewrite).
In my case, the default host name had an SSL configuration, so it didn't fall back to HTTP after the rewrite or reject the rewrite as invalid.
YMMV, I did not continue to do an exhaustive test of all permutations once I found the solution.

how to use X-Forwarded-Prefix in file backend

I'm try to configure traefik with file backend to contact a grafana server in a LXC container.
This is my configuration file:
[file]
# rules
[backends]
[backends.backend2.servers.server1]
url = "http://192.168.255.250:3000"
[frontends]
[frontends.frontend2]
entryPoints = ["http"]
backend = "backend2"
passHostHeader = true
[frontends.frontend2.routes]
[frontends.frontend2.routes.route0]
rule = "PathPrefixStrip: /grafana"
Grafana backend listen on /
So, I can contact http://example.com/grafana but I have a redirection to http://example.com/login which does not work. But http://example.com/grafana/login responding (without css, certainly because grafana seems to use relative url).
According to the documentation :
Use a *Strip matcher if your backend listens on the root path (/) but should be routeable on a specific prefix. For instance, PathPrefixStrip: /products would match /products but also /products/shoes and /products/shirts.
Since the path is stripped prior to forwarding, your backend is expected to listen on /.
If your backend is serving assets (e.g., images or Javascript files), chances are it must return properly constructed relative URLs.
Continuing on the example, the backend should return /products/shoes/image.png (and not /images.png which Traefik would likely not be able to associate with the same backend).
The X-Forwarded-Prefix header (available since Traefik 1.3) can be queried to build such URLs dynamically.
It seems that I have to use the X-Forwarded-Prefix header but I do not know how to use it (I did not see anything in the documentation). Maybe you can help me solve this problem ?
Regards
jmc
In fact, the problem does not come from traefik. I just forgot to specify the path in /etc/grafana.ini (root_url field). I thought it was not necessary since the incoming query does not contain the path /grafana (because we use PathPrefixStrip). But in fact, grafana needs it to indicate effective url to client.
Regards.
jmc

How to combine PathPrefixStrip with Redirect:Regex?

My configuration looks like this:
frontend
traefik.frontend.rule=Host:my.domain;PathPrefixStrip:/mypath/
traefik param
--entrypoints="Name:http Address::80 Redirect.EntryPoint:https Redirect.Regex:http://my.domain/(.*)$ Redirect.Replacement:https://my.domain/$1 Redirect.Permanent:true"
My goal is to redirect HTTP requests on a given path to its HTTPS endpoint. However, the path prefix removal seems to be happening before the "main" redirect.regex/replacement logic, which is breaking some requests. For example:
http://my.domain/mypath/v1/foo
Will become:
https://my.domain/v1/foo
While I expected it to be:
https://my.domain/mypath/v1/foo
Anyway to workaround this issue?
Please note that regex and replacement do not have to be set in the redirect structure if an entrypoint is defined for the redirection (they will not be used in this case).
https://docs.traefik.io/v1.5/configuration/entrypoints/#redirect-http-to-https
Note also that Redirect.Permanent:true come in 1.6
Try something like that:
--entrypoints="Name:http Address::80 Redirect.Regex:http://my.domain/(.*)$ Redirect.Replacement:https://my.domain/mypath/$1 Redirect.Permanent:true"

Does 301 redirect in htaccess have to use full path?

When changing file or directory names or "prettifying" URLs via .htaccess, I have always previously used this format:
Redirect 301 /oldfile.htm /newfile
However, according to this article, I have been doing it incorrectly all these years:
The last section is the full path to the new file. This is a
fully-qualified URL, meaning you need the http://
(http://www.domain.com/new-file.html).
Are they correct? I always use a redirect check script after writing my rules, and they always check out, even with relative paths.
The truth can be found in official docs, that says
The new URL should be an absolute URL beginning with a scheme and hostname. In Apache HTTP Server 2.2.6 and later, a URL-path beginning with a slash may also be used, in which case the scheme and hostname of the current server will be added.

How to rewrite Location response header in a proxy setup with Apache?

I have a primary proxy which sends requests to a secondary proxy on which OpeenSSO is installed.
If the OpenSSO agent determines that the user is not logged in, it raises a 302 redirect to the authentication server and provides the original (encoded) URL that the user requested as a GET parameter in the redirect location header.
However, the URL in the GET variable is that of the internal (secondary) proxy server, not the original proxy server. Therefore, I would like to edit/rewrite the "Location" response header to give the correct URL.
E.g.
http://a.com/hello/ (Original requested URL)
http://a.com/hello2/ (Secondary proxy with OpenSSO agent)
http://auth.a.com/login/?orig_request=http%3A%2F%2Fa.com%2Fhello2%2F (302 redirect to auth server with requested URL of second proxy server encoded in GET variable)
http://auth.a.com/login/?orig_request=http%3A%2F%2Fa.com%2Fhello%2F (Encoded URL is rewritten to that of the original request)
I have tried pretty much all combinations of headers and rewrites without luck so I'm thinking it may not be possible. The closest I got was this, but the mod_headers edit function does not parse environment variables.
# On the primary proxy.
RewriteEngine On
RewriteRule ^/(.*)$ - [E=orig_request:$1,P]
Header edit Location ^(http://auth\.a\.com/login/\?orig_request=).*$ "$1http%3A%2F%2Fa.com%2F%{orig_request}e"
ProxyPassReverse
ProxyPassReverse should do this for you:
This directive lets Apache adjust the URL in the Location, Content-Location and URI headers on HTTP redirect responses.
I'm not sure why your reverse proxy isn't behaving this way already, assuming you're using a pair of ProxyPass and ProxyPassReverse directives to define it.
Editing the Location Header
If you want to be able to edit the Location header as you describe, you can do it as of Apache 2.4.7:
For edit there is both a value argument which is a regular expression, and an additional replacement string. As of version 2.4.7 the replacement string may also contain format specifiers.
The "format specifiers" mentioned in the docs include being able to use environment variables, e.g. %{VAR}e.
You might also want to consider modifying your application such that the orig_request URL parameter is relativized, thus potentially eliminating the need for Header edits with environment variables.
Relative Path Location Header
You can also try using a relative path in your Location header, which would eliminate the need to explicitly map one domain to the other. This is officially valid as of RFC 7231 (June 2014), but was was widely supported even before that. You can relativize your Location header using Apache Header edit directives (even prior to version 2.4.7, since it wouldn't require environment variable substitution). That would look something like this:
Header edit Location "(^http[s]?://)([a-zA-Z0-9\.\-]+)(:\d+)?/" "/"