Reverse Proxy in Python using WSGI - python

app, built with Flask.
I want to have the following routing :
"/" -> my Flask app
"/foo/" -> Reverse proxy toward http://bar/
So far, I don't have any reverse proxy, so my application looks like :
import app
[...]
if __name__ == '__main__':
app.app.secret_key = 'XXX'
app.app.run(debug=True, use_reloader=False)
I would like to have the whole project only in python. I don't want any Apache or nginx stack (the project is not meant to be on public network). I saw that I could use a Python WSGI server, such as "wsgiserver" in cherrypy, so my app would be:
from cherrypy import wsgiserver
import app
d = wsgiserver.WSGIPathInfoDispatcher({
'/': app.app.wsgi_app
})
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8080), d)
if __name__ == '__main__':
server.start()
And if I want to add a reverse proxy in "/foo", I guess I'll just need to :
from cherrypy import wsgiserver
import app
d = wsgiserver.WSGIPathInfoDispatcher({
'/': app.app.wsgi_app,
'/foo/': SOME_WSGI_REVERSE_PROXY
})
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8080), d)
if __name__ == '__main__':
server.start()
So my questions are :
Is there any reverse proxy, written in python, that are WSGI compliant ? (I don't know if any SOME_WSGI_REVERSE_PROXY exists)
Would it work with this kind of implementation ?
Anwser:
As mentioned by accepted anwser, here is the final code:
from cherrypy import wsgiserver
import wsgiproxy.app
import app
app = app.app.wsgi_app
proxy = wsgiproxy.app.WSGIProxyApp("http://bar/")
d = wsgiserver.WSGIPathInfoDispatcher({
'/': app,
'/foo/':proxy
})
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 8080), d)
if __name__ == '__main__':
try:
server.start()
except KeyboardInterrupt:
server.stop()

See the Paste proxy middleware.
http://pythonpaste.org/wsgiproxy/

This seems to be an actively maintained alternative to the original wsgiproxy now:
https://pypi.org/project/WSGIProxy2/

mitmproxy: mitmproxy.org
It's a python proxy with reverse proxy capability.

Related

How to limit the number of processes in python twisted server?

Basically I need to implement non-threaded single process server using twisted
Some analogue of Flask's
app.run(host='0.0.0.0', port=5000, threaded=False, processes=1)
Currently i'm using
if __name__ == '__main__':
reactor_args = {}
from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
reactor.suggestThreadPoolSize(1)
resource = WSGIResource(reactor, reactor.getThreadPool(), app)
site = Site(resource)
reactor.listenTCP(5000, site, backlog=1, interface='0.0.0.0')
reactor.run(**reactor_args)
So what should be done additionally to achieve single process in twisted?
Thanks in advance!

How to make web.py work with livereload

I'm using web.py for an app and I'd like to use livereload while being in development but I can't figure out how to make the two get along?
app.py
import web
from livereload import Server
urls = (
'/', 'index'
)
class index:
def GET(self):
return "Hello, Kitty"
if __name__ == '__main__':
app = web.application(urls, globals()).wsgifunc()
server = Server(app)
server.serve()
I'm following https://github.com/lepture/python-livereload
server = Server(app.wsgi_app)
server.serve()
in my terminal I type
livereload app.py
and I see
[I 161130 14:05:03 server:283] Serving on http://127.0.0.1:35729
[I 161130 14:05:03 handlers:60] Start watching changes
[I 161130 14:05:03 handlers:62] Start detecting changes
but in the browser when loading http://127.0.0.1:35729 I see this
import web
from livereload import Server
urls = (
'/', 'index'
)
class index:
def GET(self):
return "Hello, Pussy"
if __name__ == '__main__':
app = web.application(urls, globals()).wsgifunc()
server = Server(app)
server.serve()
I see the python script rendered as plain tex.
Update
I decided to give the whole thing a second try, and succeeded, good for me :)
from livereload import Server
import web
from nestpas.views import *
from nestpas.urls import *
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
# web.config.debug = False
web.ctx.debug = False
app = web.application(urls, globals(), autoreload=False)
webapp = app.wsgifunc()
if __name__ == '__main__':
## app.run()
server = Server(webapp)
server.watch('static/', 'templates/', 'nestpas/')
server.serve(port=8080, host='localhost')
The files I'm using are stored in static, templates and nestpas which is where the Python modules are stored. I ran into some issues having sessions stored on disk, but I managed to change that as well by using the DBStore instead
from livereload import Server
import web
from nestpas.views import *
from nestpas.urls import *
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
# web.config.debug = False
web.ctx.debug = False
app = web.application(urls, globals(), autoreload=False)
webapp = app.wsgifunc()
# Setup session storage
db = web.database(dbn='sqlite', db='dev.db')
store = web.session.DBStore(db, 'sessions')
session = web.session.Session(app, store)
if __name__ == '__main__':
## app.run()
server = Server(webapp)
server.watch('static/', 'templates/', 'nestpas/')
server.serve(port=8080, host='localhost')
The next goal is to figure out how to use Livereload only when on localhost and not have to think about it when deploying to production.

Trouble Sending iOS push notifications from Google App Engine

I'm working on my first iOS app that uses push notifications. I have a python script that lets me to send push notifications from my machine but I'm unable to get this working with the Google App Engine Launcher.
When I run this on GAE I get nothing - no errors and no push notifications. What am I doing wrong? I know the code for sending the actual notification is working properly but I'm not able to duplicate this on Google's servers.
Here is the script I'm trying to run with GAE Launcher:
import os
import cgi
import webapp2
from google.appengine.ext.webapp.util import run_wsgi_app
import ssl
import json
import socket
import struct
import binascii
TOKEN = 'my_app_token'
PAYLOAD = {'aps': {'alert':'Push!','sound':'default'}}
class APNStest(webapp2.RequestHandler):
def send_push(token, payload):
# Your certificate file
cert = 'ck.pem'
# APNS development server
apns_address = ('gateway.sandbox.push.apple.com', 2195)
# Use a socket to connect to APNS over SSL
s = socket.socket()
sock = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile=cert)
sock.connect(apns_address)
# Generate a notification packet
token = binascii.unhexlify(token)
fmt = '!cH32sH{0:d}s'.format(len(payload))
cmd = '\x00'
message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
sock.write(message)
sock.close()
send_push(TOKEN, json.dumps(PAYLOAD))
application = webapp2.WSGIApplication([
('/apns', APNStest)
], debug=True)
def main():
run_wsgi_app(application)
if __name__ == "__main__":
main()
So the solution was very simple as I expected. I had enabled billing for the project on cloud.google.com but needed to have billing enabled at appengine.google.com as well. Stupid mistake that set me back 2 days.

Integrating fanstatic with tornado web?

I'm attempting to integrate fanstatic.org with tornadoweb and was curious if anyone has any prior knowledge or any code that may reflect how this is done? I've been reading the documentation and i believe it can be done since tornado does provide a wsgi interface.
thanks
import tornado.wsgi
from fanstatic import Fanstatic
from your_tornado_app import MainHandler # tornado.web.RequestHandler
app = tornado.wsgi.WSGIApplication([
(r"/", MainHandler),
])
app = Fantastic(app)
if __name__ == '__main__':
from wsgiref.simple_server import make_server
server = make_server('127.0.0.1', 8080, app)
server.serve_forever()

How do you run the Tornado web server locally?

Is it possible to run Tornado such that it listens to a local port (e.g. localhost:8000). I can't seem to find any documentation explaining how to do this.
Add an address argument to Application.listen() or HTTPServer.listen().
It's documented here (Application.listen) and here (TCPServer.listen).
For example:
application = tornado.web.Application([
(r'/blah', BlahHandler),
], **settings)
# Create an HTTP server listening on localhost, port 8080.
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8080, address='127.0.0.1')
In the documetaion they mention to run on the specific port like
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
application.listen(8000)
tornado.ioloop.IOLoop.instance().start()
You will get more help from http://www.tornadoweb.org/documentation/overview.html and http://www.tornadoweb.org/documentation/index.html
Once you've defined an application (like in the other answers) in a file (for example server.py), you simply save and run that file.
python server.py
If you want to daemonize tornado - use supervisord. If you want to access tornado on address like http://mylocal.dev/ - you should look at nginx and use it like reverse proxy. And on specific port it can be binded like in Lafada's answer.

Categories

Resources