Welcome! Log In Create A New Profile

Advanced

Reverse-proxying: Flask app with Bokeh server on Nginx

J K via nginx
May 12, 2017 05:12AM
I have created a website with Flask that is serving a Bokeh app on a
Digital Ocean VPN. Everything worked fine until I secured the server with
Let's Encrypt following this tutorial
https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-14-04
..

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
<http://bokeh.pydata.org/en/latest/docs/user_guide/server.html#reverse-proxying-with-nginx-and-ssl>.
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
<http://stackoverflow.com/questions/38081389/bokeh-server-reverse-proxying-with-nginx-gives-404/38505205#38505205>
..

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 Flaskfrom flask_sqlalchemy import SQLAlchemyfrom
flask import render_template, request, redirect, url_forfrom
flask_security import Security, SQLAlchemyUserDatastore, UserMixin,
RoleMixin, login_required, roles_accepted, current_userfrom
flask_security.decorators import anonymous_user_requiredfrom
flask_security.forms import LoginFormfrom bokeh.embed import
autoload_serverfrom bokeh.client import pull_sessionfrom wtforms
import StringFieldfrom wtforms.validators import InputRequiredfrom
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_requireddef index():
return render_template('index.html')
@app.route('/re_direct/')@login_requireddef 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()
_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Subject Author Posted

Reverse-proxying: Flask app with Bokeh server on Nginx

J K via nginx May 12, 2017 05:12AM

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

Reinis Rozitis May 12, 2017 06:34AM

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

J K via nginx May 12, 2017 10:30AM

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

Reinis Rozitis May 12, 2017 11:28AM

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

Reinis Rozitis May 12, 2017 11:34AM

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

Francis Daly May 12, 2017 04:48PM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 224
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready