Re :Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Re :Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx

nginx mailing list
Message: 4
Date: Fri, 12 May 2017 18:26:39 +0300
From: "Reinis Rozitis" <[hidden email]>
To: <[hidden email]>
Subject: Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx
Message-ID: <437D05EFD1A24D9292CCE7BE45B2127C@Neiroze>
Content-Type: text/plain; format=flowed; charset="UTF-8";
        reply-type=original

>  3. in the Flask app, I changed the URL
> to:url='https://138.197.132.46:5006/bokeh/'
> Now, when I open the app in the browser I get a 502 Bad Gateway, and the
> Flask log file says the following:
> raise IOError("Cannot pull session document because we failed to connect
> to the server (to start the server, try the 'bokeh serve' command)")

Well seems that the Flask app uses the url also for background requests.

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.


p.s. for best performance you could tweak that the Flask->bokeh requests go
through http but for the html template/output sent to clients there is
another variable or relative paths.


rr



------------------------------

Message: 5
Date: Fri, 12 May 2017 18:33:47 +0300
From: "Reinis Rozitis" <[hidden email]>
To: <[hidden email]>
Subject: Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx
Message-ID: <24A35BED74E7436B9515F58950D01034@Neiroze>
Content-Type: text/plain; format=flowed; charset="UTF-8";
        reply-type=original

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.


rr
 

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():
session=pull_session(url=url,app_path="/company_abc")
bokeh_script=autoload_server(None,app_path="/company_abc",session_id=session.id,url=url_https)
return render_template("company_abc.html", bokeh_script=bokeh_script)

This, however, results in the following error in Chrome:
GET https://www.geomorphix.net/geomorphix/autoload.js?bokeh-autoload-element=dd…6035f61fef5e&bokeh-session-id=hLR9QX79ofSg4yu7DZb1oHFdT14Ai7EcVCyh1iArcBf5 

There's no other explanation. Both, Flask and Bokeh, log files don't contain error messages.
 
 

------------------------------

Message: 6
Date: Fri, 12 May 2017 21:46:30 +0100
From: Francis Daly <[hidden email]>
To: J K via nginx <[hidden email]>
Cc: J K <[hidden email]>
Subject: Re: Reverse-proxying: Flask app with Bokeh server on Nginx
Message-ID: <[hidden email]>
Content-Type: text/plain; charset=us-ascii

On Fri, May 12, 2017 at 04:28:12PM +0200, J K via nginx wrote:

Hi there,

> > location /bokeh/ {
> >     proxy_pass http://127.0.1.1:5006;
> >
> >     # .. with the rest of directives
> > }
> >
> > relaunch the Bokeh app with
> >
> > --prefix=/bokeh/
> >
> > and (if takes part in the url construction rather than application
> > background requests) change the url variable in the Flask app
> >
> > url='http://###.###.###.##:5006'
> > to
> > url='https://yourserver/bokeh/'

> 1. in '/etc/nginx/sites-available/default' I added a new location as follow:
>
> location /bokeh/ {
>
>                    proxy_pass http://127.0.0.1:5006;  # 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 company_abc.py company_xyz.py
> geomorphix.py --prefix=/bokeh/ --allow-websocket-origin=www.example.com
> --allow-websocket-origin=example.com --host=138.197.132.46:5006
> --use-xheaders

you should also use up there as --host.

I suspect that making them both be 127.0.0.1 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
http://nginx.org/en/docs/http/websocket.html

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.

 
Hi Francis,

Thanks for your answer!

As you suggested, I did the following:
1. in '/etc/supervisor/conf.d/bokeh_serve.conf' I changed the host to 127.0.0.1:
[program:bokeh_serve]
command=/opt/envs/virtual/bin/bokeh serve company_abc.py --prefix=/bokeh/ --allow-websocket-origin=www.example.com --allow-websocket-origin=example.com --host=127.0.0.1:5006 --use-xheaders
directory=/opt/webapps/flask_telemetry
autostart=false
autorestart=true
startretries=3
user=nobody
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':
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
3. In the Flask web app code I changed the URL of the route accordingly to 127.0.0.1:
@app.route("/company_abc/")
@login_required
@roles_accepted('company_abc', 'admin')
def geomorphix():
    url='http://127.0.0.1:5006/bokeh'
    session=pull_session(url=url,app_path="/company_abc")
    bokeh_script=autoload_server(None,app_path="/geomorphix",session_id=session.id,url=url)
    return render_template("geomorphix.html", bokeh_script=bokeh_script)

When I enter the website with the Bokeh script in my browser, I get a connection refused error:
GET http://127.0.0.1:5006/bokeh/example/autoload.js?bokeh-autoload-element=9cf799610fb8&bokeh-session-id=8tvMFfJwtVFccTctGHIRPPsT3h6IF6nUFkJ8l6ZQALXl net::ERR_CONNECTION_REFUSED

Looking at the log file of the Bokeh server, everything seems to be fine:
2017-05-15 08:56:19,267 Starting Bokeh server version 0.12.4
2017-05-15 08:56:19,276 Starting Bokeh server on port 5006 with applications at paths ['/company_abc']
2017-05-15 08:56:19,276 Starting Bokeh server with process id: 28771
2017-05-15 08:56:24,530 WebSocket connection opened
2017-05-15 08:56:25,304 ServerConnection created

Also the Flask log file shows no error:
[2017-05-15 08:56:13 +0000] [28760] [INFO] Starting gunicorn 19.6.0
[2017-05-15 08:56:13 +0000] [28760] [INFO] Listening at: http://0.0.0.0:8118 (28760)
[2017-05-15 08:56:13 +0000] [28760] [INFO] Using worker: sync
[2017-05-15 08:56:13 +0000] [28765] [INFO] Booting worker with pid: 28765


The Nginx error log '/var/log/nginx/flask/error.log' is empty.

_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Re :Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx

Francis Daly
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='https://138.197.132.46:5006/bokeh/'

> > 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='http://127.0.0.1:5006/bokeh'

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='https://www.example.com'

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

> > >                    proxy_pass <a href="http://127.0.0.1:5006;">http://127.0.0.1:5006;  # 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 company_abc.py company_xyz.py
> > > geomorphix.py --prefix=/bokeh/ --allow-websocket-origin=www.example.com
> > > --allow-websocket-origin=example.com --host=138.197.132.46:5006
> > > --use-xheaders
> >
> > you should also use up there as --host.
> >
> > I suspect that making them both be 127.0.0.1 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
> > http://nginx.org/en/docs/http/websocket.html
> >
> > 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
> 127.0.0.1:
>
> [program:bokeh_serve]
>
> command=/opt/envs/virtual/bin/bokeh serve company_abc.py --prefix=/bokeh/
> --allow-websocket-origin=www.example.com --allow-websocket-origin=
> example.com --host=127.0.0.1:5006 <http://138.197.132.46:5006/>
>  --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
> 127.0.0.1:
>
> @app.route("/company_abc/")
>
> @login_required
>
> @roles_accepted('company_abc', 'admin')
>
> def geomorphix():
>
>     url='http://127.0.0.1:5006/bokeh'

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 http://127.0.0.1:5006/

> When I enter the website with the Bokeh script in my browser, I get a
> connection refused error:
>
> GET http://127.0.0.1:5006/bokeh/example/autoload.js?bokeh-autoload-element=…
> 9cf799610fb8&bokeh-session-id=8tvMFfJwtVFccTctGHIRPPsT3h6IF6nUFkJ8l6ZQALXl
> net::ERR_CONNECTION_REFUSED

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

http://bokeh.pydata.org/en/latest/docs/user_guide/server.html#reverse-proxying-with-nginx-and-ssl

and another link at

http://stackoverflow.com/questions/38081389/bokeh-server-reverse-proxying-with-nginx-gives-404/38505205#38505205

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

Good luck with it,

        f
--
Francis Daly        [hidden email]
_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Re: Re :Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx

nginx mailing list
In reply to this post by nginx mailing list
Hi Francis,

Initially, without https, everything was running well. I was deploying a Bokeh server with the 'company_abc' app, and used a Flask app to render the website and handle login/redirecting/etc. Everything was behind a Nginx server. 

Then, I installed https the Bokeh app would not be rendered on the website. The Flask app worked fine, as before.

I think what's happening is that Nginx sends a request to the Flask app. Flask then pulls the Bokeh session with
session=pull_session(url=url,app_path="/company_abc")

and creates a script tag with 
bokeh_script=autoload_server(None,app_path="/company_abc/",session_id=session.id,url=url_https)

That's then embedded into the html page by
return render_template("company_abc.html", bokeh_script=bokeh_script)

The script tag looks like this:
<script
src="https://example.com/company_abc/autoload.js?bokeh-autoload-element=c5c9bdb5-40e8-46a2-9bf0-40a9d396ce97" id="c5c9bdb5-40e8-46a2-9bf0-40a9d396ce97"
data-bokeh-model-id=""
data-bokeh-doc-id=""
></script>

Now, when the browser opens the 'company_abc.html' page it sends a request to the Nginx server. This should then proxy to the Bokeh server.
Does this sound correct?

Now, I have done some changes and get a different error. The Bokeh app I'm starting now with  
bokeh serve company_abc.py --allow-websocket-origin=example.com --allow-websocket-origin=www.example.com --port=5006 \
--host="*" --use-xheaders

So, it's running on localhost, port 5006. In the Flask app I redefined the route to the app as follows:
@app.route("/company_abc/")
def company_abc():
    session=pull_session(url=url,app_path="/company_abc")
    url_https='https://example.com/'
    bokeh_script=autoload_server(None,app_path="/company_abc/",session_id=session.id,url=url_https)
    return render_template("company_abc.html", bokeh_script=bokeh_script)

For the Nginx config file I followed the template from the Bokeh User Guide:
location /company_abc/ {
                  proxy_pass http://127.0.0.1:5006;
                  proxy_set_header Upgrade $http_upgrade;
                  proxy_set_header Connection "upgrade";
                  proxy_http_version 1.1;
                  proxy_set_header X-Forwarded-Proto $scheme;
                  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                  proxy_set_header Host $host:$server_port;
                  proxy_buffering off;
        }
}

Now, with these setting I get the following errors in Chrome:
(index):14 Uncaught ReferenceError: Bokeh is not defined
    at (index):14
(anonymous) @ (index):14
(index):37 Uncaught ReferenceError: Bokeh is not defined
    at HTMLDocument.fn ((index):37)

The log file for the Bokeh server shows no errors:
2017-05-17 10:17:49,640 Starting Bokeh server version 0.12.4
2017-05-17 10:17:49,641 Host wildcard '*' can expose the application to HTTP host header attacks. Host wildcard should only be used for testing purpose.
2017-05-17 10:17:49,647 Starting Bokeh server on port 5006 with applications at paths ['/geomorphix']
2017-05-17 10:17:49,647 Starting Bokeh server with process id: 15851
2017-05-17 10:18:08,829 200 GET /geomorphix/ (37.201.192.96) 845.69ms

Interestingly, when I manually execute the lines
session=pull_session(url=url,app_path="/company_abc")
bokeh_script=autoload_server(None,app_path="/company_abc/",session_id=session.id,url=url_https)

The Bokeh log file says that a WebSocket is opened and a ServerConnection is created:
2017-05-17 10:21:09,915 WebSocket connection opened
2017-05-17 10:21:10,769 ServerConnection created

What does the new error mean?
Why is a WebSocket opened and ServerConnection created only when I manually pull a session?

Thanks!

Message: 3
Date: Tue, 16 May 2017 17:49:07 +0100
From: Francis Daly <[hidden email]>
To: J K via nginx <[hidden email]>
Cc: J K <[hidden email]>
Subject: Re: Re :Re: Re:Reverse-proxying: Flask app with Bokeh server
        on Nginx
Message-ID: <[hidden email]>
Content-Type: text/plain; charset=utf-8

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='https://138.197.132.46:5006/bokeh/'

> > 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='http://127.0.0.1:5006/bokeh'

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='https://www.example.com'

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

> > >                    proxy_pass http://127.0.0.1:5006;  # 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 company_abc.py company_xyz.py
> > > geomorphix.py --prefix=/bokeh/ --allow-websocket-origin=www.example.com
> > > --allow-websocket-origin=example.com --host=138.197.132.46:5006
> > > --use-xheaders
> >
> > you should also use up there as --host.
> >
> > I suspect that making them both be 127.0.0.1 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
> > http://nginx.org/en/docs/http/websocket.html
> >
> > 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
> 127.0.0.1:
>
> [program:bokeh_serve]
>
> command=/opt/envs/virtual/bin/bokeh serve company_abc.py --prefix=/bokeh/
> --allow-websocket-origin=www.example.com --allow-websocket-origin=
> example.com --host=127.0.0.1:5006 <http://138.197.132.46:5006/>
>  --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
> 127.0.0.1:
>
> @app.route("/company_abc/")
>
> @login_required
>
> @roles_accepted('company_abc', 'admin')
>
> def geomorphix():
>
>     url='http://127.0.0.1:5006/bokeh'

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 http://127.0.0.1:5006/

> When I enter the website with the Bokeh script in my browser, I get a
> connection refused error:
>
> GET http://127.0.0.1:5006/bokeh/example/autoload.js?bokeh-autoload-element=?
> 9cf799610fb8&bokeh-session-id=8tvMFfJwtVFccTctGHIRPPsT3h6IF6nUFkJ8l6ZQALXl
> net::ERR_CONNECTION_REFUSED

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

http://bokeh.pydata.org/en/latest/docs/user_guide/server.html#reverse-proxying-with-nginx-and-ssl

and another link at

http://stackoverflow.com/questions/38081389/bokeh-server-reverse-proxying-with-nginx-gives-404/38505205#38505205

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

Good luck with it,

        f
--
Francis Daly        [hidden email]


_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Re: Re :Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx

Francis Daly
On Wed, May 17, 2017 at 12:34:17PM +0200, J K via nginx wrote:

Hi there,

> Initially, without https, everything was running well.

Yes.

> I was deploying a
> Bokeh server with the 'company_abc' app, and used a Flask app to render the
> website and handle login/redirecting/etc.

Yes.

> Everything was behind a Nginx server.

No.

Your bokeh server was not behind nginx.

Your bokeh server always listened on port 5006. Your nginx config did
not proxy_pass to port 5006. Your web clients connected directly to
bokeh on port 5006, not going through nginx.


If you go back to the beginning, and configure flask behind nginx
according to the flask documentation (as you had done); and configure
bokeh behind nginx according to the bokeh documentation that you showed,
then you may find that it all Just Works.

Right now, you have an inconsistent mix of configurations.

What you want is that whenever the client browser talks to flask,
it uses a url prefix like https://www.example.comw/flask/, and
whenever the client browser talks to bokeh, it uses a url prefix like
https://www.example.com/bokeh/.

When flask talks to bokeh, it can use a url prefix
like http://127.0.0.1:5006/bokeh/. Or it can use
https://www.example.com/bokeh/. It is probably better if it uses the
first one.


> The script tag looks like this:
>
> <script
>
> src="https://example.com/company_abc/autoload.js?bokeh-
> autoload-element=c5c9bdb5-40e8-46a2-9bf0-40a9d396ce97"
> id="c5c9bdb5-40e8-46a2-9bf0-40a9d396ce97"

Ok, so that gets the client browser to make a request like
https://example.com/company_abc/. You want that to be proxy_pass'ed to
the bokeh server. Does your nginx config say to do that?

> Now, when the browser opens the 'company_abc.html' page it sends a request
> to the Nginx server. This should then proxy to the Bokeh server.
> Does this sound correct?

What is the company_abc.html page?

If it matters, give the full url. Possibly it does not matter here.

> Now, I have done some changes and get a different error. The Bokeh app I'm
> starting now with
>
> bokeh serve company_abc.py --allow-websocket-origin=example.com
>  --allow-websocket-origin=www.example.com --port=5006 \
> --host="*" --use-xheaders

The bokeh documentation you linked to previously uses many fewer arguments.

> So, it's running on localhost, port 5006. In the Flask app I redefined the
> route to the app as follows:
>
> @app.route("/company_abc/")
> def company_abc():
>     url='http://127.0.0.1:5006/'
>     session=pull_session(url=url,app_path="/company_abc")
>     url_https='https://example.com/'
>     bokeh_script=autoload_server(None,app_path="/company_abc/",session_id=
> session.id,url=url_https)
>     return render_template("company_abc.html", bokeh_script=bokeh_script)

I think that the questions I asked about those various url fragments
have not been explicitly answered yet.

> For the Nginx config file I followed the template from the Bokeh User Guide
> <http://bokeh.pydata.org/en/latest/docs/user_guide/server.html#reverse-proxying-with-nginx-and-ssl>
> :
>
> location /company_abc/ {
>                   proxy_pass <a href="http://127.0.0.1:5006;">http://127.0.0.1:5006;
>                   proxy_set_header Upgrade $http_upgrade;
>                   proxy_set_header Connection "upgrade";
>                   proxy_http_version 1.1;
>                   proxy_set_header X-Forwarded-Proto $scheme;
>                   proxy_set_header X-Forwarded-For
> $proxy_add_x_forwarded_for;
>                   proxy_set_header Host $host:$server_port;
>                   proxy_buffering off;
>         }
> }
>
>
> Now, with these setting I get the following errors in Chrome:
>
> GET https://example.com/static/css/bokeh.min.css?v=
> 7246afcfffc127faef7c138bce4742e9

What do you want nginx to do with that request?

What have you configured nginx to do with that request?

The request starts with /static/, not /company_abc/, so nginx will not
try to send it to the bokeh server.

> Interestingly, when I manually execute the lines
>
> url='http://127.0.0.1:5006/'
> session=pull_session(url=url,app_path="/company_abc")
> url_https='https://example.com/'
> bokeh_script=autoload_server(None,app_path="/company_abc/",session_id=
> session.id,url=url_https)

What do you mean by "manually execute the lines"?

Is this a thing that you expect the client browser to do, or a thing
that you expect the flask server to do, or something else?

> The Bokeh log file says that a WebSocket is opened and a ServerConnection
> is created:
>
> 2017-05-17 10:21:09,915 WebSocket connection opened
> 2017-05-17 10:21:10,769 ServerConnection created
>
>
> What does the new error mean?
> Why is a WebSocket opened and ServerConnection created only when I manually
> pull a session?

I am not seeing any nginx errors being shown here.

I suspect that if you can show one minimal complete configuration, and
show one request, and show the response that you get, and describe the
response that you want instead, then someone may be able to help you
find the next step.

At the moment, I'd say start again on a test system and follow one recipe
exactly; when you see things working, then you can start changing things
to better match the configuration that you want.

Good luck with it,

        f
--
Francis Daly        [hidden email]
_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx
Reply | Threaded
Open this post in threaded view
|

Re: Re: Re :Re: Re:Reverse-proxying: Flask app with Bokeh server on Nginx

nginx mailing list
In reply to this post by nginx mailing list
Hi Francis,

you set me on the right track and I developed the solution. I differentiate the name of the Bokeh app (now company_abc-app) and the user (company_abc) and then created a location in the Nginx config file for the Bokeh app, specifically. Everything else goes through Flask, if it's not static. I posted the full source code here: https://stackoverflow.com/questions/43743029/reverse-proxying-flask-app-with-bokeh-server-on-nginx/44150473#44150473

Thanks a lot for your help!

Cheers!
 
Message: 3
Date: Tue, 16 May 2017 17:49:07 +0100
From: Francis Daly <[hidden email]>
To: J K via nginx <[hidden email]>
Cc: J K <[hidden email]>
Subject: Re: Re :Re: Re:Reverse-proxying: Flask app with Bokeh server
        on Nginx
Message-ID: <[hidden email]>
Content-Type: text/plain; charset=utf-8

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='https://138.197.132.46:5006/bokeh/'

> > 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='http://127.0.0.1:5006/bokeh'

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='https://www.example.com'

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

> > >                    proxy_pass http://127.0.0.1:5006;  # 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 company_abc.py company_xyz.py
> > > geomorphix.py --prefix=/bokeh/ --allow-websocket-origin=www.example.com
> > > --allow-websocket-origin=example.com --host=138.197.132.46:5006
> > > --use-xheaders
> >
> > you should also use up there as --host.
> >
> > I suspect that making them both be 127.0.0.1 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
> > http://nginx.org/en/docs/http/websocket.html
> >
> > 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
> 127.0.0.1:
>
> [program:bokeh_serve]
>
> command=/opt/envs/virtual/bin/bokeh serve company_abc.py --prefix=/bokeh/
> --allow-websocket-origin=www.example.com --allow-websocket-origin=
> example.com --host=127.0.0.1:5006 <http://138.197.132.46:5006/>
>  --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
> 127.0.0.1:
>
> @app.route("/company_abc/")
>
> @login_required
>
> @roles_accepted('company_abc', 'admin')
>
> def geomorphix():
>
>     url='http://127.0.0.1:5006/bokeh'

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 http://127.0.0.1:5006/

> When I enter the website with the Bokeh script in my browser, I get a
> connection refused error:
>
> GET http://127.0.0.1:5006/bokeh/example/autoload.js?bokeh-autoload-element=?
> 9cf799610fb8&bokeh-session-id=8tvMFfJwtVFccTctGHIRPPsT3h6IF6nUFkJ8l6ZQALXl
> net::ERR_CONNECTION_REFUSED

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

http://bokeh.pydata.org/en/latest/docs/user_guide/server.html#reverse-proxying-with-nginx-and-ssl

and another link at

http://stackoverflow.com/questions/38081389/bokeh-server-reverse-proxying-with-nginx-gives-404/38505205#38505205

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

Good luck with it,

        f
--
Francis Daly        [hidden email]



_______________________________________________
nginx mailing list
[hidden email]
http://mailman.nginx.org/mailman/listinfo/nginx