Traefik (Docker) Not Setting X-Forwarded-* Headers? - docker

I'm attempting to run Apache in Docker, behind a Traefik reverse proxy for https. Everything works, except that when I access a folder URL without a trailing slash, Apache redirects me to non-https (i.e. https://www.example.com/folder -> http://www.example.com/folder/). This is caused Apache mod_dir DirectorySlash, as described here & here. The solution is to use a rewrite rule, which kicks in before DirectorySlash, like this:
# Redirect to HTTPS before Apache mod_dir DirectorySlash redirect to HTTP
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteCond %{LA-U:REQUEST_FILENAME} -d
RewriteRule ^/(.*[^/])$ https://%{HTTP_HOST}/$1/ [R=301,L,QSA]
However, the issue is Traefik seems not to be setting the X-Forwarded-* headers. Here's a screenshot of the headers I'm getting:
Here are the labels I'm using in my Apache docker-compose file:
labels:
- traefik.enable=true
- traefik.port=80
- traefik.frontend.rule=PathPrefix:/web #Apache is accessible under https://example.com/web/
I've tried various combinations of labels, but no matter what I do, the x-forwarded-* headers always seem to be missing. For example (ref, ref):
- "traefik.frontend.headers.SSLProxyHeaders=X-Forwarded-Proto:https"
- "traefik.frontend.headers.SSLRedirect=true"
I've even tried just getting Traefik to add my own custom headers and can't get those to show up (ref):
- "traefik.https.middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test"
...However, just to convince myself that I'm not crazy & this is actually running behind Traefik, & Traefik can add headers that I can see, this does work & cause the X-Frame-Options header to appear in Firefox:
- traefik.frontend.headers.frameDeny=true
So in summary, the question is: why isn't Traefik setting the x-forwarded-* headers (which I can then use in my Apache RewriteRules) - and how can I get it to do so?

For anyone who finds this & is wondering, my issue was twofold:
1) X-Forwarded-* headers are not viewable in the browser. You can see them on the server with i.e. phpinfo(), or by dumping the $_SERVER variable:
2) The reason the redirects weren't working (to fix the DirectorySlash issue) is because in addition to the RewriteRules listed above, your htaccess must include RewriteOptions AllowNoSlash. From the Apache documentation:
By default, mod_rewrite will ignore URLs that map to a directory on disk but lack a trailing slash, in the expectation that the mod_dir module will issue the client with a redirect to the canonical URL with a trailing slash. [...] the AllowNoSlash option can be enabled to ensure that rewrite rules are no longer ignored. This option makes it possible to apply rewrite rules within .htaccess files that match the directory without a trailing slash, if so desired.

Have you tried
traefik.frontend.passHostHeader: true
If it's possible, I'd recommend to let the http to https redirection to be sorted by traefik:
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.http.redirect]
entryPoint = "https"
[entryPoints.https]
address = ":443"
[entryPoints.https.tls]

Related

Traefik rewrite-middleware breaks all routes

I have traefik config in my docker-compose file which routes traffic between several apps and I'd like to add a middleware to app-main to forward all www.hostname requests to hostname. I've added the following lines
- "traefik.http.middlewares.cutwww.redirectregex.regex=^https?://(?:www\\.)?(.+)"
- "traefik.http.middlewares.cutwww.redirectregex.replacement=https://$${1}"
- "traefik.http.middlewares.cutwww.redirectregex.permanenttrue"
nearby line 80 and enabled this middleware in line 83 with
- "traefik.http.routers.${APP_NAME}-main.middlewares=traefik-compress,cutwww"
After that, all my working routes to app-main have stopped to work (error 404). Please point me what's wrong in this config

How to correctly expose a docker server with ngrok?

I have a docker installation running on my machine and I can access the site on my browser by going to mysite.local (defined to map to 127.0.0.1 in hosts file)
When I run ngrok http mysite.local it works fine but when I open the http://random_id.ngrok.io link
ngrok console shows:
GET / 301 Moved Permanently
I get a NET::ERR_CERT_COMMON_NAME_INVALID error and If I click on advanced->proceed to... http://random_id.ngrok.io (unsafe), it just shows
Tunnel www.random_id.ngrok.io not found
Worth nothing this rule in .htaccess even though it looks fine to me
RewriteCond %{HTTP_HOST} !^mysite.local
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
UPDATE ngrok http -host-header=rewrite mysite.local seems indeed to work but:
css and oher assets fail to load (the only css-related rule in .htaccess is: AddType text/css .chunk.css AddType text/css .css)
Looks like the rewrite rule is the issue to me.
Your rule states:
If the http host does not start with mysite.local,
then redirect to https://www.HOST/[...]
I'd recommend either removing the rewrite rule entirely or use ngrok's http host header rewrite functionality:
ngrok http -host-header=rewrite mysite.local

Redirect unvalid subdomain to specific URL with Traefik

I would like to redirect invalid URL to a 404 error with traefik and Docker
Example :
https://sub1.domain.com is a valid doamin referenced in traefik, so nothing happen
https://invalid.domain.com doesn't exist in Traefik configuration, so it will redirect to https://error.domain.com
I have searched in the official documentation and the only thing I found was about redirection , but I don't know how to use them to do my purpose.
You should be able to do this by specifying a redirect and a replacement. You'll also need to make sure that the Host rule matches any subdomains. Here's a config for docker-compose:
services:
traefik:
# ...existing config
sub1:
# ...existing config
error:
# ...existing config
labels:
# Match all subdomains
- traefik.frontend.rule=HostRegexp:{subdomain:[a-z]+}.domain.com
- traefik.frontend.redirect.regex=^https?://(.*).domain.com
- traefik.frontend.redirect.replacement=https://error.domain.com
# Set priority to low number so matches after other rules
- traefik.frontend.priority=1
It's even easier if you don't mind about the domain changing but instead just want to show an error as you don't need the traefik.frontend.redirect labels

Apache - Domain for localhost to access folders as http://folder.local

I'm running XAMPP on Ubuntu and I'd like to create a virtual host for my projects, so that I have a tld assigned to my server root directory (for example .local) and folders inside it accessible through URLs as http://foldername.local.
Also, how much more complicated would it be to use .htaccess to have http://someotherdomain.local redirect to the /foldername path in the server root?
I've managed to do it on my own. It is possible to do it, however you'll need to install a DNS server.
Note: I decided to use .dev as my local domain, so in the following
examples, the dev part will refer to my chosen domain. Keep that in
mind.
Install and configure DNS Server
It shouldn't matter which one it is, but you'll need to know how to configure it properly. The configuration depends on which DNS server you chose. I went for dnsmasq. It's lightweight and very handy.
An important note for Ubuntu users is that since Ubuntu 11.10 there is
already a light version called dnsmasq-base installed, which will
cause conflicts during installation. I won't be explaining here how to
get around this, because there are many instructions available elsewhere.
Once you have your DNS server installed, you should configure it to listen for the address equal to your desired domain.
In my case with dnsmasq, that meant opening /etc/dnsmasq.conf and
changing line #62 to this: address=/dev/127.0.1.1
Configure Web server
Assuming that you already have some kind of Server software installed, you need to make a few tweaks.
First, you should edit your hosts file to map your desired domain to your localhost.
in my case of XAMPP for Linux on Ubuntu, this means I opened
/etc/hosts and changed lines
127.0.0.1 localhost
127.0.1.1 tomica-ubuntu
to
127.0.0.1 localhost
127.0.1.1 tomica-ubuntu dev
This will redirect http://dev to my local server.
Next, create a new virtual host with a couple of specific options, like this:
In my case, that means opening
/opt/lampp/etc/extra/httpd-vhosts.conf and adding this at the end of
the file:
<VirtualHost *:80>
DocumentRoot "/opt/lampp/htdocs/dev"
ServerName dev
ServerAlias *.dev
<Directory /opt/lampp/htdocs/dev>
AllowOverride All
</Directory>
</VirtualHost>
For the sake of brevity, I won't explain this piece of code, since
documentation is also available.
After all this is done, start your DNS and Web servers, or restart them if they're already running.
Configure .htaccess
Open root folder of your newly created host. That's the folder devined in your . In my case, that's /opt/lampp/htdocs/dev. In there, create a .htaccess file and put this in it:
# Specify order of index files; if none exist, show files list
DirectoryIndex index.php index.html
# Interpret .html files as .php scripts
AddHandler php5-script .php .html
# THE MAGIC - Redirect subdomains of .dev to their respective folders
RewriteEngine on
Options +FollowSymlinks
RewriteBase /
RewriteCond %{HTTP_HOST} !^www\.dev$ [NC]
RewriteCond %{HTTP_HOST} ^(www\.)?(.*)\.dev(.*)?$ [NC]
RewriteRule !^%2\.dev%3?/$ http://dev/%2%{REQUEST_URI}/ [P]
Again, explaining all this would require too much space and time. Just copy/paste and don't worry :) But don't forget to change my dev to anything you chose for your domain name.
AND THAT'S IT! By now you should be able to browse your project using addresses like http://folder.dev/, http://www.folder.dev, http://folder.dev/file.html, http://folder.dev/subfolder/document.txt etc.
As a bonus, I will add just one more advice. The reason why I did all this is so that I could more easily develop my Laravel and WordPress prjects. However, with Laravel, you should redirect the url http://lvproject.dev/ to the location of /lvproject/public. And here is the .htaccess file that enables just that. Open your /lvproject folder, create a .htaccess file and place this code in it:
RewriteBase /lvproject/
RewriteCond %{REQUEST_URI} lvproject/index\.php [NC]
RewriteRule index\.php(.*)$ public/ [L]
Two drawbacks of this solution are: 1) RewriteBase rule needs to be set anew for every new project (i.e. you need to manually create .htaccess in each new project); 2) Your project will be available from both http://lvproject.dev/ and http://lvproject.dev/public/, which is not cool, but I'm too lazy at the moment to get it fixed :)

How to change the directory public assets are served from in rails?

My setup:
thin running on port 1234 with --prefix /foobar
apache running on port 80
apache reverse proxies /foobar to thin on port 1234
I would like the static assets to not be served via the proxy to thin, but instead be served at /assets directly via apache instead.
I have to use a relative path because I don't know the host name/ip of the rails application before startup (it's app-in-a-box that should be able to be moved around).
I found config.action_controller.asset_host in production.rb, but I can't set that to a relative path. When I do it gets confused and creates really bogus URLs.
How can I make this work?
You don't need to call it through the config block in the environment, you can call it from the application controller, which gives you access to the request object. So you could do:
class ApplicationController < ActionController::Base
before_filter :set_asset_url
def set_asset_url
ActionController::Base.asset_host = "http://#{request.host}"
end
end
It feels a little hackish but I know of no better way.
and if you need to worry about ssl and different ports, you could go crazy:
ActionController::Base.asset_host = "http#{request.ssl? ? 's' : ''}://#{request.host_with_port}"
This depends in your server environment somewhat, but basically you want something along the lines of what is described here: http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/
First, I want to thank Geoff and darkliquid. I took what was in darkliquid's link and worked on it to make it work for my case. The big challenge was that I wasn't serving the rails application from the root of the webserver.
Notes:
thin is run with --prefix '/railsapp' on port 9999.
This works for windows and linux. W00T!
I have to use the LA-U (look-ahead) to get the final filename apache would use.
The IS_SUBREQ check is to prevent the look-ahead (a sub request) from ever returning the proxy.
The /railsapp/index.html rewrite is required because otherwise another rule in my apache conf would rewrite it to /index.html, which is a default 'here's what's here' page; 404s are served elsewhere, though.
Here's the relevant part of the apache configuration:
# Only proxy the thin stuff.
<Proxy /railsapp/*>
Order deny,allow
Allow from all
</Proxy>
## Add an alias for filename mapping.
Alias /railsapp "/website/root/railsapp/public"
## We need the Rewrite Engine for this.
RewriteEngine on
<IfDefine debug>
## If debugging, turn on logging.
RewriteLogLevel 9
RewriteLog "/website/logs/http.rewrite.log"
</IfDefine>
## Check for a static root page.
RewriteRule ^/railsapp/?$ /railsapp/index.html [QSA]
## Check for Rails caching.
RewriteRule ^(/railsapp/[^.]+)$ $1.html [QSA]
## Redirect all non-static requests to Rails.
# Don't proxy on sub-requests (needed to make the LA-U work).
RewriteCond %{IS_SUBREQ} false
# Use look-ahead to see if the filename exists after all the rewrites.
RewriteCond %{LA-U:REQUEST_FILENAME} !-f
# Proxy it to Rails.
RewriteRule ^/railsapp(.*)$ http://127.0.0.1:9999%{REQUEST_URI} [P,QSA,L]
## Make sure Rails requests are reversed correctly.
ProxyPassReverse /railsapp http://127.0.0.1:9999/railsapp
## Disable keepalive; railsappd doesn't support them.
SetEnv proxy-nokeepalive 1

Resources