In fact what you try to avoid pretty much looks like a microservice architecture (Martin Fowler article). Basically it proposes minimal self-contained services which are multiplexed to act as a whole, instead of one monolithic application. It has its pro and cons, but today it is considered more a good. At least at big scale.
Thus one way of designing your application is a microservice architecture, and running several internal servers isn't a problem. Just note that some complexity in this approach is shifted to infrastructure. That is to say you need quality deployment, monitoring, etc.
The idea of Andew's answer is correct. But specifically CherryPy is a full-featured HTTP server. You don't generally need another intermediate point of failure, gunicorn or so, and you can avoid WSGI altogether. Just use HTTP, i.e. nginx acts as reverse HTTP proxy to CherryPy internal HTTP servers.
In simplest way it looks like the following.
python 2 app
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
},
'/' : {
'tools.proxy.on' : True
}
}
class App:
@cherrypy.expose
def index(self):
return type({}.keys()).__name__
if __name__ == '__main__':
cherrypy.quickstart(App(), '/app1', config)
python 3 app
#!/usr/bin/env python3
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8081,
'server.thread_pool' : 8
},
'/' : {
'tools.proxy.on' : True
}
}
class App:
@cherrypy.expose
def index(self):
return type({}.keys()).__name__
if __name__ == '__main__':
cherrypy.quickstart(App(), '/app2', config)
nginx config
server {
listen 80;
server_name ngx-test;
root /var/www/ngx-test/www;
location /app1 {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /app2 {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
For full-blown CherryPy deployment take a look at this answer.