11

I'm trying to serve an interactive bokeh figure via heroku. The figure I'm trying to have served is essentially equivalent to this one (example, code). I'm new to both bokeh and heroku so I'm pretty sure I'm missing something pretty basic -- I think what I'm trying to do should be quite straightforward.

First, I can serve my figure locally using the bokeh serve --show myapp command. Where myapp is the name of the python module that includes the bokeh figure. Note that the --show flag just prompts bokeh to open a browser window once the figure is built and the server is running.

Next, I've setup a heroku account, and created my first app, following the steps in the Heroku - Getting Started With Python tutorial. My git repository includes myapp, a requirements.txt file, and Procfile.

Alas, something is not working and I'm stumped. I have tried a bunch of different options in my Procfile and none have worked. Since the bokeh serve ... command starts a server, shouldn't a Procfile that looks like this do the trick:

web: bokeh serve --port $PORT myapp

Should that work? Perhaps I'm missing something and I need to create a flask app that wraps around my bokeh app but as far as I can tell, that doesn't seem necessary. Maybe someone knows of a nice tutorial that pulls all of these steps together, I haven't found a complete one yet.

Update: I'm pasting a bit of my heroku logs below. How do you handle this --host whitelist issue?

2016-07-17T05:00:46.513139+00:00 heroku[slug-compiler]: Slug compilation started
2016-07-17T05:00:46.366909+00:00 heroku[api]: Deploy 9b63d8a by me@me.com
2016-07-17T05:00:46.367087+00:00 heroku[api]: Release v4 created by me@me.com
2016-07-17T05:00:46.624937+00:00 heroku[web.1]: State changed from crashed to starting
2016-07-17T05:00:55.188978+00:00 heroku[web.1]: Starting process with command `bokeh serve --port=39665 myapp.py`
2016-07-17T05:00:57.876287+00:00 app[web.1]: 2016-07-17 05:00:57,876 Starting Bokeh server on port 39665 with applications at paths ['/myapp']
2016-07-17T05:00:57.868758+00:00 app[web.1]: 2016-07-17 05:00:57,868 Starting Bokeh server version 0.12.0
2016-07-17T05:00:57.876378+00:00 app[web.1]: 2016-07-17 05:00:57,876 Starting Bokeh server with process id: 3
2016-07-17T05:00:58.800309+00:00 heroku[web.1]: State changed from starting to up
2016-07-17T05:00:59.970326+00:00 app[web.1]: 2016-07-17 05:00:59,970 Rejected connection from host 'myapp.herokuapp.com' because it is not in the --host whitelist
2016-07-17T05:00:59.973495+00:00 app[web.1]: 2016-07-17 05:00:59,970 403 GET / (XX.XX.XXX.XX) 1.29ms
2016-07-17T05:00:59.975282+00:00 heroku[router]: at=info method=GET path="/" host=myapp.herokuapp.com request_id=xxxxxxxxxxxxx fwd="XX.XX.XX.XX" dyno=web.1 connect=1ms service=4ms status=403 bytes=219
tommy.carstensen
  • 8,962
  • 15
  • 65
  • 108
jhamman
  • 5,867
  • 19
  • 39

2 Answers2

9

I'm just going to answer my own question since I was eventually able to get this to work and nobody else has answered it yet.

I ended up with a Procfile that looked like this:

web: bokeh serve --port=$PORT --host=myapp.herokuapp.com --host=* \
     --address=0.0.0.0 --use-xheaders myapp.py

a bit of background on what all of these arguments mean (as far as I can tell):

--port: specifies the port that the bokeh server will listen on, $PORT is set by heroku

--host=myapp.herokuapp.com and --host=*: specify the host name as myapp.heroku..., the wildcard is supposed to allow all hosts to be accepted. I'm not sure this in needed anymore.

--address=0.0.0.0: I think this tells bokeh to figure out on its own, which IP address it will be on.

--use-xheaders: causes bokeh to override the remote IP and URI scheme/protocol

I'm happy to make edits to this or accept a more knowledgeable users answer if there are issues with this approach.

jhamman
  • 5,867
  • 19
  • 39
  • Were you able to deploy it with flask? I have a working flask app locally, but cannot figure out how to make it work on Heroku. Here is the [bokeh_plot.py](https://www.dropbox.com/s/ohaa388wpmkvpxt/bokeh_plot.py?dl=0) and [app.py](https://www.dropbox.com/s/owla19e58hgijgd/app.py?dl=0) containing the flask code. Script app.py contains a subprocess where the bokeh server is started so the application can start by simply running `python app.py` and the app is succesfully rendered in localhost:5000. Now, I don't know how to modify bokeh_subprocess to make it work on Heroku. – multigoodverse Jul 21 '16 at 11:06
  • I never got a flask app running with my setup. I just used the `bokeh serve` command and was able to skip the `flask` step. – jhamman Jul 21 '16 at 19:36
  • I see, but you need a web framework if you need to add other content along your bokeh chart, right? – multigoodverse Jul 21 '16 at 20:53
  • --address of 0.0.0.0 means "listen on all network interfaces" ; it may be the default anyway? – Havoc P Jul 24 '16 at 10:32
  • --host=* is a security problem and should not be needed. This tells bokeh to trust any client-provided Host header, and put that host in front of URLs it generates. – Havoc P Jul 24 '16 at 10:34
  • --use-xheaders is needed and tells bokeh to trust "x headers" set by the Heroku reverse proxy. These are headers Heroku adds to pass on info about the client. – Havoc P Jul 24 '16 at 10:36
  • to make flask+bokeh work on Heroku I think you need two different web workers because you need to listen on two different ports. – Havoc P Jul 24 '16 at 10:38
  • @HavocP I tried to add another web worker in Procfile by making it look like this: `web: gunicorn app:app web: bokeh serve --port=$PORT --host=bokehapp.herokuapp.com --host=* --address=0.0.0.0 --use-xheaders bokeh_plot.py`. That showed the graph at bokeh.herokuapp.com/bokeh_plot, but it didn't show the content served by Flask. It seems the server is reading the second line only. Do you have any idea on this? – multigoodverse Jul 28 '16 at 06:17
  • each Heroku app can only have one web worker iirc. so you would need two different Heroku apps, or some kind of intermediate process that listens on the one port and routes to bokeh or flask as needed. – Havoc P Jul 28 '16 at 11:47
  • @jhamman if you don't mind, could you share a sample requirements.txt and Proctofile for a basic bokeh&heroku app ? – zwlayer Mar 27 '17 at 20:40
6

The accepted answer didn't work for me as written (likely due to a bokeh version difference), but since this is still one of the top hits for this question, here is my minor modification that did work:

web: bokeh serve --port=$PORT --num-procs=0 --allow-websocket-origin=myapp.herokuapp.com --address=0.0.0.0 --use-xheaders myapp.py
ttunstall
  • 63
  • 1
  • 4