Using bottle.py in production
Update: I wrote a post about how to call get_url from within a SimpleTemplate template. The same technique works to make any Python variable or function you want globally accessible by default from a SimpleTemplate template.
This is a quick guide to using bottle.py in a (semi-)production environment with lighttpd. Bottle.py is a super-lightweight (one source file!) web framework for Python which I use for quick, single-purpose web scripts. For example, I have used Bottle.py for small web applications to:
- Monitor CPU and HDD temps
- Provide a quick and easy personal file drop location
- Administer hg repositories
This guide will show some techniques to write a URL-agnostic app in Bottle.py and then deploy it, using FCGI and lighttpd. Requirements:
- python>=2.7
- bottle.py>=0.10
- flup
Bottle.py tips
get_url
Use the get_url
function to write a URL-agnostic app. With get_url
, you can mount your app at any root URL on your server. For example, if your app handles the /viewpost
and /listposts
URLs, and you mount it at http://mywebsite.com/blog/
, the final URLs that you would access from your web browser would be http://mywebsite.com/blog/viewpost
and http://mywebsite.com/blog/listposts
. You can only use get_url
with named routes:
import bottle
app = bottle.default_app()
@app.route('/viewposts', name='viewposts')
def handle_viewposts():
return 'first post!'
# Calling get_url from handle_index
@app.route('/index')
def handle_index():
return '<a href="{}">View posts</a>'.format(app.get_url('viewposts'))
You can also use get_url
for dynamic routes (routes with parameters):
@app.route('/get/<name:path>', name='getobj')
def handle_getobj(name):
return bottle.static_file(name, root='/path/to/files')
# Call get_url like this
url = app.get_url('getobj', name='filename.txt')
Deploying with flup
Usually I deploy Python web apps with flup (there's also a Python 3 version). I use FastCGI on a Unix socket, running behind lighttpd. For these examples, assume that the app socket is called /run/lighttpd/myapp.sock
.
Python configuration
For Python 2.7 and flup, use Bottle's builtin flup server, setting the bindAddress
to the path to the socket:
if __name__ == "__main__":
run(server='flup', options={'bindAddress': '/run/lighttpd/myapp.sock'})
lighttpd
Make sure mod_fastcgi
is loaded in your config. To mount an FCGI Bottle app at some URL, say /myapp
, add this to your lighttpd.conf:
fastcgi.server = (
"/myapp" => (
"myapp-fcgi" => (
"socket" => "/run/lighttpd/myapp.sock",
"check-local" => "disable",
"docroot" => "/",
)
)
)
Disabling check-local
allows your app to handle URL requests even if a file of the same name does not exist on the local filesystem. For more information on lighttpd and FastCGI, see the official documentation.