Generating Static HTML from TurboGears (Part 2)
Filed under: nginx turbogearsIn my previous article , I showed that it's pretty easy to have TurboGears generate static HTML files. However, unless they get served somehow, it's pretty useless. In my quest to figure out Nginx, I decided to make this work.
The Nginx Configuration:
location / {
default_type text/html;
types { text/html html; }
root /var/www/public_html/cache;
if (-f $request_filename.html) {
rewrite (.*) $request_uri.html last;
}
proxy_pass 127.0.0.1:8000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
The TurboGears Code
You'll need to add a directory under project/static for storing the cached HTML files. I call mine "cache". I think it's a good name so you should too =)
Add the following to your project's controllers.py:
class StaticOutFilter ( BaseFilter ):
def before_finalize ( self ):
if cherrypy.response.status is None:
request = filter ( None, cherrypy.request.path.split ( '/' ) )
path = os.path.join ( 'var/www/public_html/cache/', *tuple ( request ) ) + '.html'
try:
os.makedirs ( os.path.dirname ( path ) )
except ( OSError, IOError ):
pass # should log this
file ( path, 'w' ).writelines ( cherrypy.response.body )
class Root ( controllers.RootController ):
_cp_filters = [ StaticOutFilter ( ) ]
# rest of root controller follows ...
At this point, whenever Nginx receives a request, it appends ".html" to the end of the URL and checks that it exists in the cache directory. If it does, it serves the static HTML file, if it doesn't it passes the request on to TurboGears which will generate the file.
Now clearly this simple setup is rife with limitations:
- Changes made in the TurboGears app won't be reflected unless you manually remove the relevant HTML file(s).
- Even if you do remove the files, truly dynamic content (such as displaying a username) won't be reflected.
The first problem is fairly trivial to solve. Assuming you provide an interface for editing content on your TurboGears site, simply add some code that cleans out the relevant cache file.
The second problem is much trickier. There are lots of ways to address it, depending upon your application's needs, but some ideas that come to mind are:
- Add a decorator that indicates whethor or not a page is cacheable and have the filter check this attribute prior to trying to cache it.
- Use AJAX to manage dynamic items.
- For the specific example given of the username (and user-customizable items), it might make sense to have a separate view of the site for authenticated users that bypasses Nginx and goes straight to TurboGears (i.e. myaccount.domain.com rather than www.domain.com). If most of your traffic consists of anonymous users then this might be ideal. Serve static content to anonymous users and dynamic content to authenticated users.
Anyway, this aspect is left as an exercise for the reader (or perhaps myself at a later date). If you have suggestions, feel free to make a comment.






