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) # [email protected]('/')@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 [email protected] http://mailman.nginx.org/mailman/listinfo/nginx
