Create a default vhost to serve http request in uwsgi - python

I've uwsgi 2.0.19 on Linux running with the python plugin. I serve http(s) traffic with different applications each for a specific record of my managed domain using such kind of configuration to register them to the front uwsgi servers.
subscribe2 = server=x.x.x.x:4443,key=domain.com,sni_key=/etc/ssl/private/domain.com.key,sni_cert=/etc/ssl/certs/domain.com.crt
subscribe2 = server=x.x.x.x:4443,key=domain.com:443,sni_key=/etc/ssl/private/domain.com.key,sni_cert=/etc/ssl/certs/domain.com.crt
subscribe2 = server=y.y.y.y:4443,key=domain.com,sni_key=/etc/ssl/private/domain.com.key,sni_cert=/etc/ssl/certs/domain.com.crt
subscribe2 = server=y.y.y.y:4443,key=domain.com:443,sni_key=/etc/ssl/private/domain.com.key,sni_cert=/etc/ssl/certs/domain.com.crt
Now when I reach one of the front servers to access a not-existing host, I received such error (the TCP connexion is closed I assume)
curl: (52) Empty reply from server
I would like to be able to have a default/catchall key for such case, that permits to return an HTTP status 404 as I would do in Apache using the _default_ vhost. is it possible.

In order to implement this, you need to define a fallback application using the http-subscription-fallback-key on the front uwsgi server
http-subscription-fallback-key=default
default is a standard application registered on the frontal uwsgi like any other application
subscribe2 = server=x.x.x.x:4443,key=default
subscribe2 = server=x.x.x.x:4443,key=default:80

Related

How to configure apache to support websockets

I wrote server in python and now I would like to configure apache web server to support websockets.
My server returns information when a client sends queries to these addresses:
def make_app():
return tornado.web.Application([
(r"/playgame", EmptyGame),
(r"/playgame/", EmptyGame),
(r"/playgame/(.*)", PlayerGameWebsocket)
])
How to configure the server to support regular user traffic but also to enable websockets when the client establishes such a connection?
I user apache2.4 server.
Ok, it turned out that the solution is trivial. If someone ever looked for an answer, just add a simple redirection to the application in the virtual host configuration which listens on localhost:
ProxyPassMatch "/playgame/(.*)" "ws://127.0.0.1:8888/playgame/$1"
ProxyPassReverse "/playgame/(.*)" "ws://127.0.0.1:8888/playgame/$1"
Thanks to such syntax, we can even pass additional data, e.g. "/playgame/123".
We connect from the client without specifying the port:
var adr = "ws://serverip/playgame/" + gameid;
var ws = new WebSocket(adr);

Python socket.io server error 400 (NodeJS server works)

I'm trying to make JavaScript client to a Python websocket server through an Apache2 proxy.
The client is dead simple:
const socket = io({
transports: ['websocket']
});
I have a NodeJS websocket server and a working Apache2 reverse proxy setup.
Now I want to replace the NodeJS server with a Python server - but none of the example implementations from socket.io works. With each of the my client reports an "error 400" when setting up the websocket connection.
The Python server examples come from here:
https://github.com/miguelgrinberg/python-socketio/tree/master/examples/server
Error 400 stands for "Bad Request" - but I know that my requests are fine because my NodeJS server understands them.
When not running behind a proxy then all Python examples work fine.
What could be the problem?
I found the solution - all the Python socket.io server examples that I refered to are not configured to run behind a reverse proxy. The reason is, that the socket.io server is managing a list of allowed request origins and the automatic list creation is failing in the reverse proxy situation.
This function creates the automatic list of allowed origins (engineio/asyncio_server.py):
def _cors_allowed_origins(self, environ):
default_origins = []
if 'wsgi.url_scheme' in environ and 'HTTP_HOST' in environ:
default_origins.append('{scheme}://{host}'.format(
scheme=environ['wsgi.url_scheme'], host=environ['HTTP_HOST']))
if 'HTTP_X_FORWARDED_HOST' in environ:
scheme = environ.get(
'HTTP_X_FORWARDED_PROTO',
environ['wsgi.url_scheme']).split(',')[0].strip()
default_origins.append('{scheme}://{host}'.format(
scheme=scheme, host=environ['HTTP_X_FORWARDED_HOST'].split(
',')[0].strip()))
As you can see, it only adds URLs with {scheme} as a protocol. When behind a reverse proxy, {scheme} will always be "http". So if the initial request was HTTPS based, it will not be in the list of allowed origins.
The solution to this problem is very simple: when creating the socket.io server, you have to either tell him to allow all origins or specify your origin:
import socketio
sio = socketio.AsyncServer(cors_allowed_origins="*") # allow all
# or
sio = socketio.AsyncServer(cors_allowed_origins="https://example.com") # allow specific

How to get WSGI servers to close a connection after each response?

The API for Python's wsgiref module precludes hop-by-hop headers (as defined in RFC 2616).
I'm unclear on how to get the server to terminate a connection after a response (since there doesn't seem to be a way to add Connection: close).
This problem comes up in testing small WSGI apps and Bottle micro-services. Calls from curl get blocked by open connections from a browser. I have to click a browser refresh to terminate the connection so that the pending curl request can be answers.
Obviously, this should be a server side decision (terminate connection after a response) rather than client-side. I'm unclear how to implement this.
This is really predicated on your WSGI server you are hosting your framework via. The best solution with bottle is to run it through gevent.
botapp = bottle.app()
for Route in (mainappRoute,): #handle multiple files containing routes
botapp.merge(Route)
botapp = SessionMiddleware(botapp, beakerconfig) #in case you are using beaker sessions
botapp = WhiteNoise(botapp) #in case you want whitenoise to handle static files
botapp.add_files(staticfolder, prefix='static/') #add static route to whitenoise
server = WSGIServer(("0.0.0.0", int(80)), botapp) #gevent async web server
def shutdown():
print('Shutting down ...')
server.stop(timeout=60)
exit(signal.SIGTERM)
gevent.signal(signal.SIGTERM, shutdown)
gevent.signal(signal.SIGINT, shutdown) #CTRL C
server.serve_forever() #spawn the server
You can purge the whitenoise and bottle configs if they aren't necessary, I kept them there as an example, and a suggestion that you use them if this is outward facing.
This is purely asynchronous on every connection.

Connection refused on socket.connect (Django app deployed on uWSGI + Nginx)

I have a Django application deployed on a VM using uWSGI & Nginx setup.
I would like to print some data, by passing the required information to a printer that is configured on the same network using a socket:
printer_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
printer_socket.connect(('10.125.125.2', 9001))
printer_socket.send(bytes(source='data', encoding='utf-8'))
Note: the IP address and the port are here for illustration purposes.
Problem: I get a Err 111 Connection refused error, however. The error is triggered at the printer_socket.connect step.
Additional information: The python code that initializes the socket, connects to the required IP address/Port and sends the data works fine when it's run from the python interactive shell.
Question: What do I need to configure in order to allow opening sockets from a django web application, deployed using uWSGI and Nginx?
Please keep in mind that the configuration of the project is out of the scope of this question. I don't have troubles configuring the app. The app works fine. I am specifically interested in how to allow opening sockets from a web app, served using uWSGI + Nginx setup
UPDATE
Here's the .ini configuration file for the uWSGI.
[uwsgi]
project = App
uid = user
base = /home/%(uid)
chdir = %(base)/%(project)
home = %(base)/Venv/%(project)
module = %(project).wsgi:application
# daemonize = %{base}/uwsgi/%{project}.log
logto = /home/user/logs/uwsgi/%{project}.log
master = true
processes = 5
socket = /run/uwsgi/%(project).sock
chown-socket = %(uid):www-data
chmod-socket = 777
vacuum = true
buffer-size=32768
Thank you.

Web2py client server not working

I'm trying to run a project which holds data in web2py server and web2py based client shows the visualization. When running both server and client , the chrome console on clinet side shows:
XMLHttpRequest cannot load http://127.0.0.1:8075/?format=json.
No 'Access-Control- Allow-Origin' header is present on the requested resource.
Origin 'http://127.0.0.1:8080' is therefore not allowed access. (index):1
[ERROR] Cannot connect to data server: http://127.0.0.1:8075?format=json
I'm running above with web2py2.9.5 on linux.
It looks like your web2py client page is served on port 8080 but is then making an Ajax request to port 8075, which violates the same origin policy enforced by web browsers.
If you can't serve both from the same origin, you can get around this by using JSONP or by setting up CORS.

Categories

Resources