Is it possible to host redash under something else than root, for instance http://host/redash/ ?

Thanks.

2 Likes

Not really. Why would you want to do that?

So to be able to host several web apps on this host. I was thinking of having nginx in front of other apps, besides redash.

So here’s a solution if anyone else needs…

After creating a new nginx location /redash and proxying to host:5000, redash will request root uri’s like /scripts, /images, /views. So the solution is to inspect content served like html files, and replace strings and add /redash.

nginx has a module called http_sub_module. It is not compiled by default so you’ll need to compile nginx from sources, which is very easy.

You have to use the appropriate options for ubuntu (or you linux flavour. It’s easy, just run nginx -V, and copy the output. Then you’ll just add “–with-http_sub_module”.

The compile process is straight forward and is documented online:

./configure <your os options> --with-http_sub_module
make
make install

For some reason, /usr/sbin/nginx was not replaced by the new version I had to copy it from /usr/share/nginx/sbin/nginx.

Then just need to configure your new location:

  location /redash/ {
    #rewrite xhr requests from plugins.xxxx.js (dashboards.html, /api/*)
    #also rewrites href-base attribute in a bunch of html files
    sub_filter '192.168.2.115' '192.168.2.115/redash';
    #rewrite several requests done to root (/images, /styles, /scripts)
    sub_filter '="/images/' '="/redash/images/';
    sub_filter '="/styles/' '="/redash/styles/';
    sub_filter '="/scripts/' '="/redash/scripts/';
    #rewrite /views xhr requests made from scripts.xxxxx.js (/views/app_header.html, /views/edit_dashboard.html, /views/index.html)
    sub_filter '"/views/' '"/redash/views/';
    #rewrite this particular image referenced in
    sub_filter '/images/redash_icon_small.png' '/redash/images/redash_icon_small.png';
    #search for all occurences of these strings
    sub_filter_once off;
    #inspect these types of content (* would inspect all content types)
    sub_filter_types application/javascript text/html text/css text/xml text/css text/javascript application/json text/plain;

    #proxy stuff from redash setup
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass       http://rd_servers/;
  }

You can now access redash with http://host/redash

1 Like

missed login/logout 302 redirects… so you need an additional proxy_redirect rule:

location /redash/ {
    #rewrite xhr requests from plugins.xxxx.js (dashboards.html, /api/*)
    #also rewrites href-base attribute in a bunch of html files
    sub_filter '192.168.2.115' '192.168.2.115/redash';
    #rewrite several requests done to root (/images, /styles, /scripts)
    sub_filter '="/images/' '="/redash/images/';
    sub_filter '="/styles/' '="/redash/styles/';
    sub_filter '="/scripts/' '="/redash/scripts/';
    #rewrite /views xhr requests made from scripts.xxxxx.js (/views/app_header.html, /views/edit_dashboard.html, /views/index.html)
    sub_filter '"/views/' '"/redash/views/';
    #rewrite this particular image referenced in
    sub_filter '/images/redash_icon_small.png' '/redash/images/redash_icon_small.png';
    #search for all occurences of these strings
    sub_filter_once off;
    #inspect these types of content (* would inspect all content types)
    sub_filter_types application/javascript text/html text/css text/xml text/css text/javascript application/json text/plain;

#change redirect headers to /login
proxy_redirect ~*\/login /redash/login?next=/redash/;

#proxy stuff from redash setup
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass       http://rd_servers/;
  }

.

1 Like

Thank you for the follow up and sharing the solution!

Hello, i´m using redash.3.0.0.b3134
this solution works until the login… after a login the webserver give a white site… nothing else… any ideas?

@c.lazz hi there. I’ve since moved to iis as reverse proxy to redash:5000.

What url do you get on the “white site”?

1 Like

Hello, tanks for answering…

https://$host/redash

html ng-app=“app” ng-strict-di>
head lang=“en”>
meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
meta charset=“UTF-8”>
base href="/">
title>Redash

link rel="icon" type="image/png" sizes="32x32" href="/redash/images/favicon-32x32.png">
link rel="icon" type="image/png" sizes="96x96" href="/redash/images/favicon-96x96.png">
link rel="icon" type="image/png" sizes="16x16" href="/redash/images/favicon-16x16.png">

link href="/styles.681aa4ab9869dd2a6d16.css" rel=“stylesheet”>

body>
section>
div ng-view>
/section>
script type=“text/javascript” src="/manifest.31fe86837ebc20ae3f84.js">/script>
/html>

ok, so you can see that your js and css are loading from root:

/styles/…css
/manifest.asdlkdsd.js

They must point to your redash folder:

/redash/styles/…css
/redash/manifest…js

your images are loading ok though.

I think it’s because since v2 folders like /styles/ and /views/ don’t exist anymore. So my sub_filters don’t work anymore.

In my iis rules I take care of the following in outbound rules. Now I replace eveery tag that can have a root url:

<outboundRules>
	<clear />
	<rule name="redirectLogin" preCondition="IsRedirect2" stopProcessing="true">
		<match serverVariable="RESPONSE_Location" pattern="(^https?://)(.*)/(login)(.*)" />
		<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
		<action type="Rewrite" value="https://{R:2}/redash/login?next=https%3A%2F%2F{R:2}%2Fredash" />
	</rule>
	<rule name="linksabsolutos.v2" preCondition="ResponseIsHtml1">
		<match filterByTags="A, Base, Form, Img, Link, Script" pattern="^/(.*)" />
		<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
		<action type="Rewrite" value="/redash{R:0}" />
	</rule>
	<rule name="Rewrite image URLs in CSS response" preCondition="IsCSS">
		<match filterByTags="None" pattern="url\(/fonts/" />
		<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
		<action type="Rewrite" value="url(/redash/fonts/" />
	</rule>
	<rule name="linksabsolutos" preCondition="ResponseIsHtml1">
		<match filterByTags="A, Base, Form, Img, Link, Script" pattern="^http(s)?://192.168.2.25:5000/(.*)" />
		<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
		<action type="Rewrite" value="http{R:1}://fqdn/redash/{R:2}" />
	</rule>
	<rule name="scripts url absolutos" preCondition="" enabled="false" patternSyntax="ECMAScript">
		<match filterByTags="Link, Script" pattern="^/(styles|scripts|views)/(.*)" />
		<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
		<action type="Rewrite" value="/redash/{R:1}/{R:2}" />
	</rule>
	<rule name="url em scripts" preCondition="scripts e json">
		<match filterByTags="None" pattern="&quot;/(images|styles|scripts|views|api)/([^&quot;]*)" />
		<conditions logicalGrouping="MatchAll" trackAllCaptures="true" />
		<action type="Rewrite" value="&quot;/redash/{R:1}/{R:2}" />
	</rule>
	
	<preConditions>
		<preCondition name="ResponseIsHtml1">
			<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
		</preCondition>
		<preCondition name="scripts e json" logicalGrouping="MatchAny">
			<add input="{RESPONSE_CONTENT_TYPE}" pattern="(application|text)/(javascript|json|x-json|x-javascript|html)" />
		</preCondition>
		<preCondition name="IsCSS">
			<add input="{RESPONSE_CONTENT_TYPE}" pattern="text/css" />
		</preCondition>
		<preCondition name="IsRedirection">
			<add input="{RESPONSE_STATUS}" pattern="3\d\d" />
		</preCondition>
		<preCondition name="IsRedirect2">
			<add input="{RESPONSE_STATUS}" pattern="3[0-9][0-9]" />
		</preCondition>
	</preConditions>
</outboundRules>

Ok i got it…

here´ s the nginx config…

location /redash/ {
   sub_filter ="/ ="/redash/;
   sub_filter ="/manifest. ="/redash/manifest.;
   sub_filter ="/vendor. ="/redash/vendor.;
   sub_filter ="/app. ="/redash/app.;
   sub_filter ="/styles. ="/redash/sytles.;
   sub_filter ="/styles ="/redash/sytles;
   sub_filter ="/scripts. ="/redash/scripts.;
   sub_filter ="/images ="/redash/images;
   sub_filter ="/fonts ="/redash/fonts;
   sub_filter ="/views ="/redash/views;
   sub_filter ="/js ="/redash/js;
   sub_filter ="/forgot ="/redash/forgot;

   sub_filter ="/images/redash_icon_small.png  ="/redash/images/redash_icon_small.png;
   sub_filter_once off;
   sub_filter_types application/javascript text/html text/css text/xml text/css text/javascript application/json text/plain text/javascript";

    proxy_redirect ~*\/login /redash/login?next=/redash/;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass       http://redash_servers/;
}

It seems everything is working except the Icons for datasource, settings and search
I cannot find the location for this to remap

1 Like

Some links are broken… whet a new user enter his password… the next screen is / toplevel…
When the user is logged in, the symbols for settings and datasources and other are missing
The shortcut of the Icon from redash in the upper left side shows to toplevel ;-(

Anyone other use redash with nginx and host not under root / toplevel and can help?

So not to drop this going further. I really think this is a necessary capability.

I have everything working on v3 but using IIS as can be seen above.

Now on v4 redash added a new way of making life harder for us who need to proxy redash… on app.js we now have a calculated url:

e.exports = n.p + “images/redash_icon_small.png”

Why??? This evaluates to an absolute url!!! Geez…

Anyway, nothing I can think of to work around this… everything works except the small redash icon that appears as broken to the users…

Hi Guys…

I have the exact same need here… :frowning:
Does the configuration provided by @c.lazz work on v4 or should it be adjusted somehow ?

I may have not configured it properly but any request I send to /redash/* return the login redirect (including the login page).

Same need here.
Typical example is testing new versions without setting up a second machine. I spent several hours fiddling with get_login_url to get a proper login response with no luck until I found this forum item. I understand it may be a problem with code interaction with the underlying Flask platform.
The temporary solution I have used that will work with version 4 is to just create another “server” section in the nginx conf file and serve the second redash at another port. It’s not an elegant solution from a presentation point of view.

In my situation, we use nginx + docker swarm.
The solution will be like create a service, list url/redash and route all the links from url/redash to redash url:port.
Current redash version: Redash 3.0.0+b3147
TS code:

import { NextFunction, Request, Response, Router } from 'express';
import * as _ from 'lodash';
import * as request from 'request';
import { ExpressWrapper } from '../common-tools-ts/utils-api/express-wrapper';

export const getRouter = ExpressWrapper.createRouter();

getRouter.get('*', (req: Request, res: Response, next: NextFunction) => {
  let url = req.url.replace('/redash/', '/');
  url = url.replace('/redash', '/');

  const options = {
    headers: req.headers,
    url: 'http://192.168.56.111:5100' + url
  };

  request.get(options, (err, response) => {
    if (response.headers['content-type'] === 'image/png') {
      //
    } else if (response.headers['content-type'] === 'application/javascript') {
      if (url.includes('app')) {
        response.body = response.body.replace('a.get("/api/config")', 'a.get("/redash/api/config")');
      }
    } else {
      response.body = response.body.replace(/src=\"\//g, 'src="/redash/');
      response.body = response.body.replace(/href=\"\//g, 'href="/redash/');
    }

    if (!err && response) {
      res
        .header(response.headers)
        .status(response.statusCode)
        .send(response.body);
      next();
    } else {
      next();
    }
  });
});

Hi, is there any news in this topic?
I am also having trouble hosting redash under a different URL, say /redash.

Thanks,
Gabriel

2 Likes

Hello,
is there any progression on this request? maybe some supported configuration from redash rather than manual modifications to the NGINX configurations? this solution is problematic as it can left undone after software upgrades (since it’s not part of the default configurations).

Any updates on this subject?
It will be very helpful to include a configuration option of serving redash under a relative path, rather than manual updates on NGINX container which can be vanished during upgrades.

Thanks

2 Likes

Hi
i have used the same configuration but after login it shows the blank page.
it’s redirecting me on http://mydomain/redash/#/redash/redash/

my used configuration

location /redash/ {
sub_filter ="/ ="/redash/;
sub_filter ="/manifest. ="/redash/manifest.;
sub_filter ="/static. ="/redash/static.;
sub_filter ="/vendor. ="/redash/vendor.;
sub_filter ="/app. ="/redash/app.;
sub_filter ="/styles. ="/redash/sytles.;
sub_filter ="/styles ="/redash/sytles;
sub_filter ="/scripts. ="/redash/scripts.;
sub_filter ="/images ="/redash/images;
sub_filter ="/fonts ="/redash/fonts;
sub_filter ="/views ="/redash/views;
sub_filter ="/js ="/redash/js;
sub_filter ="/forgot ="/redash/forgot;

sub_filter ="/images/redash_icon_small.png ="/redash/images/redash_icon_small.png;
sub_filter_once off;
sub_filter_types application/javascript text/html text/css text/xml text/css text/javascript application/json text/plain text/javascript";

proxy_redirect ~*\/login /redash/login?next=/redash/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass       http://localhost:5000/;

}