Hello,
After some long and unsuccessful research - I found tons of posts with a similar topic but none was able to resolve my issue - I'm trying to ask for some help also.
I'm running a flask socket.io app using gunicorn (with one worker -w 1) and flask socket.io inside docker:
Launching with:
"gunicorn", "-k", "geventwebsocket.gunicorn.workers.GeventWebSocketWorker", "-w", "1", "app:app", "-b", "0.0.0.0:5000"
The respective python code (async_mode is "gevent":
socketio = SocketIO(app, async_mode=async_mode)
socketio.run(app, host="0.0.0.0", port=5000, debug=True)
I'm running a nginx proxy in front of that, which was working nicely as long as I was using http only. But when I switched to https I got lots of HTTP 400 errors and websockets stopped working.
I did a lot of research and found nginx options as well as hints that gunicorn can only be run with one worker. None worked until I found this short option by Miguel.
socketio = SocketIO(app, async_mode=async_mode,engineio_logger=True)
I did add this and on the gunicorn log I finally got a message that.
htts://mydomain is not within the accepted origins
After searching for hours this led me to this discussion
So what I ended up with was adding the cors option to my socketio constructor:
socketio = SocketIO(app, async_mode=async_mode,cors_allowed_origins="*")
And voila everything was working fine!
Not sure if this is relevant for mostly running in containers where the hostname is maybe not detected or something else. However I started typing this "issue" while I was still researching and thought it might be a interesting find for others that run into a similar problem (as I have come across many similar requests).
Please consider this as a how-to/knowledge documentation and not as an issue :-)
Thanks Miguel! Great stuff!
Using cors_allowed_origins='*' introduces a security risk, because you are allowing anyone to connect and use your service. It's best to explicitly name the origin(s) that you intend to support.
Yeah I'm aware of that should have corrected that in the post, I've actually set it to my domain after the initial test/verification. Thanks!
Hi @reinhard-brandstaedter,
Thanks so much for sharing, I had the same exact issue with the same awful search experience.
Your solution was the first one to work and to explain the source of the problem.
I found a more standard way to fix this issue (with no need to use hard-coded domain in your code or the risky '*').
You can use werkzeug's ProxyFix, which will fix many of the issues of running the app behind a proxy.
For example I'm using url_for with _external=True in my app. Without ProxyFix I got a the url with http protocol instead of the desired https.
ProxyFix fix that issue as well as your original issue as long as the proxy server is configured to pass X-Forwarded-* in the header.
Example usage:
from flask import Flask
from flask_socketio import SocketIO
from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
app.secret_key = 'TODO: replace with a randomly generate secret key' # TODO: you can find how here: https://stackoverflow.com/questions/34902378/where-do-i-get-a-secret-key-for-flask
socketio = SocketIO(app)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
socketio.run(app)
My Nginx configuration:
server {
listen 443 ssl http2;
server_name my.domain.com;
<ssl stuff>
location / {
include proxy_params;
proxy_pass http://127.0.0.1:8000;
}
location /socket.io {
include proxy_params;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://127.0.0.1:8000/socket.io;
}
}
server {
if ($host = my.domain.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name my.domain.com;
}
with /etc/nginx/proxy_params:
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
Hi @pokop
Thanks so much for this. You ended ours of misery for me!
yeah @pokop likewise thank you!
Most helpful comment
Hi @reinhard-brandstaedter,
Thanks so much for sharing, I had the same exact issue with the same awful search experience.
Your solution was the first one to work and to explain the source of the problem.
I found a more standard way to fix this issue (with no need to use hard-coded domain in your code or the risky
'*').You can use werkzeug's ProxyFix, which will fix many of the issues of running the app behind a proxy.
For example I'm using
url_forwith_external=Truein my app. WithoutProxyFixI got a the url withhttpprotocol instead of the desiredhttps.ProxyFixfix that issue as well as your original issue as long as the proxy server is configured to passX-Forwarded-*in the header.Example usage:
My Nginx configuration:
with
/etc/nginx/proxy_params: