Reverse-proxying: Flask app with Bokeh server on Nginx

I have created a website with Flask that is serving a Bokeh app (0.12.4) on a Digital Ocean VPN. Everything worked fine until I secured the server with Let’s Encrypt following this tutorial.

In step 3 of the tutorial the Nginx configuration file is changed, which might be the crux of the problem I’m getting:

When I go on the website, the Flask content is rendered perfectly. However, the Bokeh app is not running. In the Inspection Console I get the following Error (note that I hashed out the IP address of my website):

Mixed Content: The page at 'https://example.com/company_abc/' was loaded over HTTPS,
but requested an insecure script 'http://###.###.###.##:5006/company_abc/autoload.js?bokeh-autoload-element=f…aab19c633c95&bokeh-session-id=AvWhaYqOzsX0GZPOjTS5LX2M7Z6arzsBFBxCjb0Up2xP'.
This request has been blocked; the content must be served over HTTPS.

I understand that I might have to use a method called reverse proxying, which is described here. However, I wasn’t able to get it to work.

Does anybody have an idea how to solve this? A similar problem was described here.

Here are my modified server files:

‘/etc/nginx/sites-available/default’:

``

upstream flask_siti {
        server 127.0.0.1:8118 fail_timeout=0;
}
server {
        listen 443 ssl;

        server_name example.com www.example.com;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_dhparam /etc/ssl/certs/dhparam.pem;
        ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
        ssl_session_timeout 1d;
        ssl_session_cache shared:SSL:50m;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security max-age=15768000;

        charset utf-8;
        client_max_body_size 75M;

        access_log /var/log/nginx/flask/access.log;
        error_log /var/log/nginx/flask/error.log;

        keepalive_timeout 5;

        location / {
                # checks for static file, if not found proxy to the app
                try_files $uri @proxy_to_app;
        }

        location @proxy_to_app {
                proxy_redirect off;
                proxy_set_header Host $http_host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://flask_siti;
        }
}

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

``

‘/etc/supervisor/conf.d/bokeh_serve.conf’:

[program:bokeh_serve]
command=/opt/envs/virtual/bin/bokeh serve company_abc.py company_xyz.py --allow-websocket-origin=www.example.com --allow-websocket-origin=example.com --host=###.###.###.##:5006 --use-xheaders
directory=/opt/webapps/flask_telemetry
autostart=false
autorestart=true
startretries=3
user=nobody

``

‘/etc/supervisor/conf.d/flask.conf’:

[program:flask]
command=/opt/envs/virtual/bin/gunicorn -b :8118 website_app:app
directory=/opt/webapps/flask_telemetry
user=nobody
autostart=true
autorestart=true
redirect_stderr=true

``

And here is my Flask app (Note that I hashed out security related info):

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask import render_template, request, redirect, url_for
from flask_security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin, login_required, roles_accepted, current_user
from flask_security.decorators import anonymous_user_required
from flask_security.forms import LoginForm
from bokeh.embed import autoload_server
from bokeh.client import pull_session
from wtforms import StringField
from wtforms.validators import InputRequired
from werkzeug.contrib.fixers import ProxyFix

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://###:###@localhost/telemetry'
app.config['SECRET_KEY'] = '###'
app.config['SECURITY_REGISTERABLE'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = 'username'
app.config['SECURITY_POST_LOGIN_VIEW'] = '/re_direct'
app.debug = True
db = SQLAlchemy(app)

# Define models
roles_users = db.Table('roles_users',
        db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
        db.Column('role_id', db.Integer(), db.ForeignKey('role.id')))

class Role(db.Model, RoleMixin):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(80), unique=True)
    description = db.Column(db.String(255))

class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(255), unique=True)
    password = db.Column(db.String(255))
    active = db.Column(db.Boolean())
    confirmed_at = db.Column(db.DateTime())
    roles = db.relationship('Role', secondary=roles_users,
                            backref=db.backref('users', lazy='dynamic'))

class ExtendedLoginForm(LoginForm):
    email = StringField('Username', [InputRequired()])

# Setup Flask-Security
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
security = Security(app, user_datastore, login_form=ExtendedLoginForm)

# Views
@app.route('/')
@anonymous_user_required
def index():
    return render_template('index.html')

@app.route('/re_direct/')
@login_required
def re_direct():
    identifier = current_user.    username
print(identifier)
    return redirect(url_for(identifier))

@app.route('/index/')
@login_required
@roles_accepted('admin')
def admin():
    return render_template('admin.html')

@app.route("/company_abc/")
@login_required
@roles_accepted('company_abc', 'admin')
def company_abc():
    url='http://###.###.###.##:5006'
    session=pull_session(url=url,app_path="/company_abc")
    bokeh_script=autoload_server(None,app_path="/company_abc",session_id=session.id,url=url)
    return render_template("company_abc.html", bokeh_script=bokeh_script)

@app.route("/company_xyz/")
@login_required
@roles_accepted('company_xyz', 'admin')
def company_xyz():
    url='http://###.###.###.##:5006'
    session=pull_session(url=url,app_path="/company_xyz")
    bokeh_script=autoload_server(None,app_path="/company_xyz",session_id=session.id,url=url)
    return render_template("company_xyz.html", bokeh_script=bokeh_script)

app.wsgi_app = ProxyFix(app.wsgi_app)

if __name__ == '__main__':
    app.run()

``

Hi,

The URL you are passing to autoload_server is http, it needs to be https (whatever https nginx endpoint is in front of the bokeh server). The autoload_server injects a script from whatever URL you give it. If you give it an HTTP URL, then it will inject a script that loads the Bokeh app from an HTTP address. The won't work if the page you are embedding in is HTTPS (browsers will refuse to load insecure content onto a secure page).

Bryan

···

On May 12, 2017, at 03:43, cas.xyz via Bokeh Discussion - Public <[email protected]> wrote:

I have created a website with Flask that is serving a Bokeh app (0.12.4) on a Digital Ocean VPN. Everything worked fine until I secured the server with Let's Encrypt following this tutorial.

In step 3 of the tutorial the Nginx configuration file is changed, which might be the crux of the problem I'm getting:

When I go on the website, the Flask content is rendered perfectly. However, the Bokeh app is not running. In the Inspection Console I get the following Error (note that I hashed out the IP address of my website):

Mixed Content: The page at 'https://example.com/company_abc/' was loaded over HTTPS,

but requested an insecure script

'http://###.###.###.##:5006/company_abc/autoload.js?bokeh-autoload-element=f…aab19c633c95&bokeh-session-id=AvWhaYqOzsX0GZPOjTS5LX2M7Z6arzsBFBxCjb0Up2xP'.

This request has been blocked; the content must be served over HTTPS.
I understand that I might have to use a method called reverse proxying, which is described here. However, I wasn't able to get it to work.

Does anybody have an idea how to solve this? A similar problem was described here.

Here are my modified server files:

'/etc/nginx/sites-available/default':

upstream flask_siti {

        server
127.0.0.1:8118 fail_timeout=0;
}

server
{

        listen
443 ssl;

        server_name example
.com www.example.com;

        ssl_certificate
/etc/letsencrypt/live/example.com/fullchain.pem;

        ssl_certificate_key
/etc/letsencrypt/live/example.com/privkey.pem;

        ssl_protocols
TLSv1 TLSv1.1 TLSv1.2;

        ssl_prefer_server_ciphers on
;

        ssl_dhparam
/etc/ssl/certs/dhparam.pem;

        ssl_ciphers
'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';

        ssl_session_timeout
1d;

        ssl_session_cache shared
:SSL:50m;

        ssl_stapling on
;

        ssl_stapling_verify on
;

        add_header
Strict-Transport-Security max-age=15768000;

        charset utf
-8;

        client_max_body_size
75M;

        access_log
/var/log/nginx/flask/access.log;

        error_log
/var/log/nginx/flask/error.log;

        keepalive_timeout
5;

        location
/ {

# checks for static file, if not found proxy to the app

                try_files $uri
@proxy_to_app;

}

        location
@proxy_to_app {

                proxy_redirect off
;

                proxy_set_header
Host $http_host;

                proxy_set_header X
-Forwarded-For $proxy_add_x_forwarded_for;

                proxy_pass http
://flask_siti;

}
}

server
{

    listen
80;

    server_name example
.com www.example.com;

return 301 https://$host$request_uri;
}

'/etc/supervisor/conf.d/bokeh_serve.conf':

[program:bokeh_serve]

command
=/opt/envs/virtual/bin/bokeh serve company_abc.py company_xyz.py --allow-websocket-origin=www.example.com --allow-websocket-origin=example.com --host=###.###.###.##:5006 --use-
xheaders
directory
=/opt/webapps/
flask_telemetry
autostart

false
autorestart

true
startretries
=3

user
=nobody

'/etc/supervisor/conf.d/flask.conf':

[program:flask]

command
=/opt/envs/virtual/bin/gunicorn -b :8118 website_app:
app
directory
=/opt/webapps/
flask_telemetry
user

nobody
autostart

true
autorestart

true
redirect_stderr
=true

And here is my Flask app (Note that I hashed out security related info):

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask import render_template, request, redirect,
url_for

from flask_security import Security, SQLAlchemyUserDatastore, UserMixin, RoleMixin, login_required, roles_accepted,
current_user

from flask_security.decorators import
anonymous_user_required

from flask_security.forms import LoginForm
from bokeh.embed import
autoload_server

from bokeh.client import
pull_session

from wtforms import StringField
from wtforms.validators import InputRequired
from werkzeug.contrib.fixers import ProxyFix

app
= Flask(__name__)

app
.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://###:###@localhost/telemetry'

app
.config['SECRET_KEY'] = '###'

app
.config['SECURITY_REGISTERABLE'] = True

app
.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app
.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = 'username'

app
.config['SECURITY_POST_LOGIN_VIEW'] = '/re_direct'

app
.debug = True

db
= SQLAlchemy(app)

# Define models

roles_users
= db.Table('roles_users',

        db
.Column('user_id', db.Integer(), db.ForeignKey('user.id')),

        db
.Column('role_id', db.Integer(), db.ForeignKey('role.id')))

class Role(db.Model, RoleMixin):

    id
= db.Column(db.Integer(), primary_key=True)

    name
= db.Column(db.String(80), unique=True)

    description
= db.Column(db.String(255))

class User(db.Model, UserMixin):

    id
= db.Column(db.Integer, primary_key=True)

    username
= db.Column(db.String(255), unique=True)

    password
= db.Column(db.String(255))

    active
= db.Column(db.Boolean())

    confirmed_at
= db.Column(db.DateTime())

    roles
= db.relationship('Role', secondary=roles_users,

                            backref
=db.backref('users', lazy='dynamic'))

class ExtendedLoginForm(LoginForm):

    email
= StringField('Username', [InputRequired()])

# Setup Flask-Security

user_datastore
= SQLAlchemyUserDatastore(db, User, Role)

security
= Security(app, user_datastore, login_form=ExtendedLoginForm)

# Views
@app.route('/')
@anonymous_user_required
def index():

return render_template('index.html')

@app.route('/re_direct/')
@login_required
def re_direct():

    identifier
= current_user.
username
    
print(identifier)

return redirect(url_for(identifier))

@app.route('/index/')
@login_required
@roles_accepted('admin')
def admin():

return render_template('admin.html')

@app.route("/company_abc/")
@login_required
@roles_accepted('company_abc', 'admin')
def company_abc():

    url
='http://###.###.###.##:5006'

    session
=pull_session(url=url,app_path="/company_abc")

    bokeh_script
=autoload_server(None,app_path="/company_abc",session_id=session.id,url=url)

return render_template("company_abc.html", bokeh_script=bokeh_script)

@app.route("/company_xyz/")
@login_required
@roles_accepted('company_xyz', 'admin')
def company_xyz():

    url
='http://###.###.###.##:5006'

    session
=pull_session(url=url,app_path="/company_xyz")

    bokeh_script
=autoload_server(None,app_path="/company_xyz",session_id=session.id,url=url)

return render_template("company_xyz.html", bokeh_script=bokeh_script)

app
.wsgi_app = ProxyFix(app.wsgi_app)

if __name__ == '__main__':

    app
.run()

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/db19830a-1c2f-4156-a871-89dad92888f2%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Thanks Bryan for your quick explanation.

If I understood correctly, for pull_session I have to use the URL of the Bokeh server (wiith http), then for autoload_server I have to give a https URL. I changed the Flask app accordingly:

@app.route("/company_abc/")
@login_required
@roles_accepted(‘company_abc’, ‘admin’)
def company_abc():
url=‘http://###.###.##.##:5006
session=pull_session(url=url,app_path="/company_abc")
url_https=‘https://###.###.##.##:5006
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)

``

However, now Chrome gives a timeout error:

GET https://###.###.##.##:5006/company_abc/autoload.js?bokeh-autoload-ele…3a05236e25c1&bokeh-session-id=49OKYuGPJHEtLEu6TL7TwFYHJ72AIj0Ma6IoNdNlxlpl net::ERR_TIMED_OUT

``

On the other side, I can visit http://###.###.##.##:5006/company_abc in Chrome and it works fine

Do you have any idea what could be broken?

Thanks,

Julian

Is there anything in the bokeh server output indicating that a connection was initiated? If not, the request is never making it to the Bokeh server (and that is maybe my guess if there issue in the browser is a timeout). In that case I'd suspect it's probably an nginx config issue. Are there any any errors/messages in the nginx log?

Bryan

···

On May 12, 2017, at 10:02, 'Julian' via Bokeh Discussion - Public <[email protected]> wrote:

Thanks Bryan for your quick explanation.

If I understood correctly, for pull_session I have to use the URL of the Bokeh server (wiith http), then for autoload_server I have to give a https URL. I changed the Flask app accordingly:
@app.route("/company_abc/")
@login_required
@roles_accepted('company_abc', 'admin')
def company_abc():
    url='http://###.###.##.##:5006'
    session=pull_session(url=url,app_path="/company_abc")
    url_https='https://###.###.##.##:5006'
    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)

However, now Chrome gives a timeout error:
GET https://###.###.##.##:5006/company_abc/autoload.js?bokeh-autoload-ele…3a05236e25c1&bokeh-session-id=49OKYuGPJHEtLEu6TL7TwFYHJ72AIj0Ma6IoNdNlxlpl net::ERR_TIMED_OUT

On the other side, I can visit http://###.###.##.##:5006/company_abc in Chrome and it works fine

Do you have any idea what could be broken?

Thanks,
Julian

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/4f2cdb68-a1e5-449f-9406-53f7218dc419%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.

Thanks, again, Bryan.

Here are copies of the log files after I tried to load the website and got the timeout error:

  • Error log for bokeh serve:
    2017-05-15 11:40:10,969 Starting Bokeh server version 0.12.4

2017-05-15 11:40:10,978 Starting Bokeh server on port 5006 with applications at paths [’/company_abc’, ‘/company_xyz’]

2017-05-15 11:40:10,978 Starting Bokeh server with process id: 1577

2017-05-15 11:40:14,774 WebSocket connection opened

2017-05-15 11:40:15,858 ServerConnection created

``

  • Log of Flask:
    [2017-05-15 11:40:05 +0000] [1564] [INFO] Starting gunicorn 19.6.0

[2017-05-15 11:40:05 +0000] [1564] [INFO] Listening at: http://0.0.0.0:8118 (1564)

[2017-05-15 11:40:05 +0000] [1564] [INFO] Using worker: sync

[2017-05-15 11:40:05 +0000] [1569] [INFO] Booting worker with pid: 1569

``

  • The error log for the Nginx server in normal mode was empty. The debug more error file is attached.
  • The access log for the Nginx server is attached, as well.

error.log (1.08 MB)

access.log (7.69 KB)

From a different support group I got the advise to start the Bokeh server with --prefix=/bokeh/ and then create a bokeh location block in the Nginx config file. Furthermore, it was suggested to have the --host IP address (bokeh serve) and the proxy_pass IP (in Nginx config) identical. With these changes, the location block in the Nginx config file reads as follows:
location /bokeh/ {

proxy_pass http://127.0.0.1:5006;

proxy_redirect off;

proxy_set_header Host $http_host;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection “upgrade”;

}

``

Then I changed the bokeh serve options as follows:

bokeh serve company_abc.py --prefix=/bokeh/ --allow-websocket-origin=www.example.com --allow-websocket-origin=example.com --host=www.example.com --host=127.0.0.1:5006 --use-xheaders

``

Note that I added www.geomorphix.net as host, because without it I got an error saying that this address wasn’t in the host whitelist.

I also changed the corresponding route in the Flask app as follows:

def company_abc():

url=‘http://127.0.0.1:5006/bokeh

session=pull_session(url=url,app_path="/company_abc")

url_https=‘https://www.example.com/bokeh

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)

``

With these settings I got the following error message in the Chrome console:

Bokeh: BokehJS not loaded, scheduling load and callback at Mon May 15 2017 15:05:08 GMT+0200 (W. Europe Daylight Time)

autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:51 Bokeh: injecting script tag for BokehJS library: http://www.example.com/bokeh/static/js/bokeh.min.js?v=9d3af13f493d36073a89714f6a5240c6

autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:52 Mixed Content: The page at ‘https://example.com/company_abc/’ was loaded over HTTPS, but requested an insecure script ‘http://www.example.com/bokeh/static/js/bokeh.min.js?v=9d3af13f493d36073a89714f6a5240c6’. This request has been blocked; the content must be served over HTTPS.

load_libs @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:52

(anonymous) @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:101

(anonymous) @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:106

autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:49 failed to load library http://www.example.com/bokeh/static/js/bokeh.min.js?v=9d3af13f493d36073a89714f6a5240c6

s.onerror @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:49

load_libs @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:52

(anonymous) @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:101

(anonymous) @ autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy…:106

``

The ‘bokeh serve’ log file reads as follows:

2017-05-15 13:04:57,517 Starting Bokeh server version 0.12.4

2017-05-15 13:04:57,526 Starting Bokeh server on port 5006 with applications at paths [’/company_abc’, ‘/company_xyz’, ‘/geomorphix’]

2017-05-15 13:04:57,526 Starting Bokeh server with process id: 5102

2017-05-15 13:05:03,029 WebSocket connection opened

2017-05-15 13:05:03,909 ServerConnection created

2017-05-15 13:05:08,602 200 GET /bokeh/company_abc/autoload.js?bokeh-autoload-element=50558e41-0bea-4759-8368-e6581a7beb43&bokeh-session-id=chm4gGmyJy2QLqxmt2SSAdetgg51fFe0uFnMTsLAnp4 (72.142.78.202) 16.24ms

``

And the Flask log file looks like this:

[2017-05-15 13:04:51 +0000] [5091] [INFO] Starting gunicorn 19.6.0

[2017-05-15 13:04:51 +0000] [5091] [INFO] Listening at: http://0.0.0.0:8118 (5091)

[2017-05-15 13:04:51 +0000] [5091] [INFO] Using worker: sync

[2017-05-15 13:04:51 +0000] [5096] [INFO] Booting worker with pid: 5096

``

Hi,

I developed a solution and posted the source code here: https://stackoverflow.com/questions/43743029/reverse-proxying-flask-app-with-bokeh-server-on-nginx/44150473#44150473

It’s basically setting up a location for the Bokeh app and the Flask app in the Nginx config file, and using different names for the app (company_abc-app) and the user (company_abc).

Thanks for the help!

Cheers!

Hi Julian,

Thanks for the link and the SO answer, I have upvoted it. If you have a chance, please look over the project docs:

  http://bokeh.pydata.org/en/latest/docs/user_guide/server.html

If you have any suggestions for things to add or clarify they would be very appreciated.

Thanks,

Bryan

···

On May 24, 2017, at 01:29, 'Julian' via Bokeh Discussion - Public <[email protected]> wrote:

Hi,

I developed a solution and posted the source code here: https://stackoverflow.com/questions/43743029/reverse-proxying-flask-app-with-bokeh-server-on-nginx/44150473#44150473

It's basically setting up a location for the Bokeh app and the Flask app in the Nginx config file, and using different names for the app (company_abc-app) and the user (company_abc).

Thanks for the help!

Cheers!

--
You received this message because you are subscribed to the Google Groups "Bokeh Discussion - Public" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/615727bf-69ab-4033-9352-8a1ec260fe08%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.