Rails with docker, in production config.hosts seems to be ignored

Viewed 644

We are experiencing different behaviors for different rails environments, in a docker setup, with regards to config.hosts directive in development.rb and production.rb.

We have two docker images for the same app on the same server, "staging" and "production". They are run at the same time in separate containers and on different ports.

Both images are using internally port 3000 and exposing different ports (3002 and 3004) to the docker host.

An apache on another VM is proxying requests to the containers, with the following setup (in two different virtual hosts):

<IfModule mod_proxy.c>
    ProxyRequests Off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyPass / http://192.168.99.102:3002/
    ProxyPassReverse / http://192.168.99.102:3002/
    ProxyPreserveHost Off
    RequestHeader Set X-Forwarded-Ssl "On"
    RequestHeader Set X-Forwarded-Port "443"
    RequestHeader Set X-Forwarded-Host "dev.sitexxx.com"
    RequestHeader set X_FORWARDED_PROTO "https"
</IfModule>

for the development environment and

<IfModule mod_proxy.c>
    ProxyRequests Off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyPass / http://192.168.99.102:3004/
    ProxyPassReverse / http://192.168.99.102:3004/
    ProxyPreserveHost Off
    RequestHeader Set X-Forwarded-Ssl "On"
    RequestHeader Set X-Forwarded-Port "443"
    RequestHeader Set X-Forwarded-Host "www.sitexxx.com"
    RequestHeader set X_FORWARDED_PROTO "https"
</IfModule>

for the production environment.

Now, while in the development rails environment (development.rb), the code:

config.hosts << "dev.sitexxx.com"

works and allows us to browse the website normally, the same code:

config.hosts << "www.sitexxx.com"

does not work in the production environment (production.rb) and we get the usual error:

Blocked host: www.sitexxx.com
To allow requests to www.sitexxx.com, add the following to your environment configuration:

config.hosts << "www.sitexxx.com"

That is actually exactly what we are doing.

To make the site work we need to resort to:

config.hosts.clear

practically disabling protection against dns rebinding attacks.

1 Answers

You need to verify what are the actual Host header (request.get_header("HTTP_HOST")) and x_forwarded_host (request.x_forwarded_host) of the request and add both of these in config.hosts as both need to be whitelisted. In case you run your application in a Kubernetes kluster, Host header could be something like .default.svc.cluster.local.

The problem is the misleading error message. request.host is always shown in the error message which equals to X-Forwarded-Host if it's present. However, it can also be Host header that's not passing the check. There is an open PR to fix the error.

Related