Reverse-proxying: Flask app with Bokeh server on Nginx

Francis Daly francis at
Tue May 16 16:49:07 UTC 2017

On Mon, May 15, 2017 at 11:59:27AM +0200, J K via nginx wrote:

Hi there,

To recap:

you had installed a "flask" web server and a "bokeh" web server. You
put the "flask" one behind nginx, so that clients would talk to nginx
and to bokeh.

And the clients were happy to talk http to nginx and http to bokeh.

Then you enabled https on nginx, so that clients would talk https to
nginx and http to bokeh.

And the clients did not want to talk http to bokeh after talking https
to nginx.

So right now, you are trying to put the "bokeh" web server behind
nginx too.

There are various ips and ports and url prefixes that appear in various
configuration files; it is worth making sure that you are very clear on
what each one is for. That will make it possible to see what needs to
be done to put bokeh behind nginx.

> > >  3. in the Flask app, I changed the URL
> > > to:url=''

> > You can't mix 'https://' and :5006 port  in same url - this way the
> > request
> > goes to port 5006 but it expects to be also encrypted but if I understand
> > correctly bokeh doesn't support SSL.

> > What I forgot to add you need to change the 'url' (note the domain part)
> > to:
> >
> > url='https://yourdomain/bokeh/'
> >
> > by looking at your error messages it seems that the 'url' is also directly
> > used for client requests (probably placed in the html templated) - which
> > means you can't use plain IP because then the browser most likely will just
> > generate a SSL certificate and domain mismatch.

> Thanks for answering again.
> I followed your advise and change the Flask app script so that I have one
> URL to pull the Bokeh session and another one to create the HTML script:
> def company_abc():
> url=''

So: what is that url for?

Is it a thing that the client web browser will try to access, or a thing
that something internal to flask will try to access, or a thing that
something internal to bokeh will try to access?

When you can say what it is, then it may become clear what value it
should have.

> session=pull_session(url=url,app_path="/company_abc")
> url_https=''

Same question. What is the purpose of that? Which of (browser, flask,
bokeh) will try to use it?

> > >                    proxy_pass;  # you suggested
> > 127.0.
> > > *1*.1, but I figured that was a typo
> >
> > The proxy_pass address should be wherever your "bokeh" http server is
> > actually listening.
> >
> > Which probably means that whatever you use up there...
> >
> > > command=/opt/envs/virtual/bin/bokeh serve
> > > --prefix=/bokeh/
> > > --host=
> > > --use-xheaders
> >
> > you should also use up there as --host.
> >
> > I suspect that making them both be will be the easiest
> > way of reverse-proxying things; but I also suspect that the
> > "--allow-websocket-origin" part suggests that you may want to configure
> > nginx to reverse proxy the web socket connection too. Notes are at
> >
> >
> > It will be helpful to have a very clear picture of what talks to what,
> > when things are working normally; that should make it easier to be
> > confident that the same links are in place with nginx in the mix.

> As you suggested, I did the following:
> 1. in '/etc/supervisor/conf.d/bokeh_serve.conf' I changed the host to
> [program:bokeh_serve]
> command=/opt/envs/virtual/bin/bokeh serve --prefix=/bokeh/
> --allow-websocket-origin=
> --host= <>
>  --use-xheaders

What is "--allow-websocket-origin" for? Is it causing any breakage here?

(Can you temporarily run with all websocket origins allowed, until
things work; and then add back the restrictions to confirm that things
still work?)

> 2. I configure nginx to reverse proxy the web socket connection by adding
> the following lines to each location block in '/etc/nginx/sites-available/
> default':

That may or may not be needed in "each location". Maybe it is only needed
in the "bokeh" location; the intended data flow diagram will show how
things should be configured.

> 3. In the Flask web app code I changed the URL of the route accordingly to
> @app.route("/company_abc/")
> @login_required
> @roles_accepted('company_abc', 'admin')
> def geomorphix():
>     url=''

Same question as above: is that something that flask uses, or something
that the web browser uses?

Because the web browser will fail to access

> When I enter the website with the Bokeh script in my browser, I get a
> connection refused error:
> GET…
> 9cf799610fb8&bokeh-session-id=8tvMFfJwtVFccTctGHIRPPsT3h6IF6nUFkJ8l6ZQALXl

That makes it look like the "url=" is something that the web browser uses.

The web browser should only be accessing your https://nginx-server
service, so urls that the web browser will use should refer to that.

Possibly "url='/bokeh'" will Just Work for you.

You mentioned the bokeh documentation at

and another link at

in your first mail. Does your current nginx configuration resemble either
of those?

Good luck with it,

Francis Daly        francis at

More information about the nginx mailing list