Rev. Johnny Healey's Blog

Just another WordPress.com weblog

Badass Resumes Julep Configuration

with 2 comments

When I first switch Badass Resumes to julep and nginx from apache, I expected to spend a few days tweaking the configuration and then I would document the process in a blog post (like this one).  Ultimately though, I ended up forgetting about it for several months, during which time it has chugged along with no maintenance whatsoever.

So, I present to you, many months late, the julep and nginx setup that is currently running badass resumes.

The Julep Configuration

The julep configuration is pretty straightforward.  The site had previously been running on mod_wsgi, so I just used the existing wsgi file to configure the app.  I made the scoreboard available to check on it periodically, though I haven’t ended up using it too much.

from julep import config
from julep import scoreboard
from julep import preload

from wsgiref import simple_server

import logging
logging.basicConfig(level=logging.DEBUG,filename="/var/log/julep/julep.log")

badass_resumes = config.NetworkServer(
    address = '127.0.0.1',
    port = 5557,
    wsgi_file = "/var/www/badassresumes/resumes.wsgi",
    access_log = "/var/log/julep/resumes.log",
    error_log = "/var/log/julep/resumes.err.log",
    preload = [preload.preload_django,]
)

scoreboard_server = config.NetworkServer(
    address = '127.0.0.1',
    port = 8687,
    app = scoreboard.ScoreboardWSGIApplication([
        badass_resumes,
    ])
)

The WSGI File

When I switched from mod_wsgi to julep, I didn’t actually need to change the wsgi file.  It is a standard django configuration.


<span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;">import os,sys</span>
<pre>sys.path.append("/var/www/badassresumes/")
os.environ['DJANGO_SETTINGS_MODULE'] = 'badassresumes.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

The nginx Configuration

The nginx configuration is also pretty simple.  The julep instance serving on port 5557 is used as the upstream server that handles the actual requests.  Exceptions are made for the media and admin media folders.  The final location for handling internal requests is used to support the X-Accel-Redirect header (so that the resumes can be served by nginx rather than being handled by the julep processes).

upstream badass-resumes {
    server localhost:5557;
}

server {
    listen 80;
    server_name badassresumes.com badass-resumes.com;

    access_log  /var/log/nginx/resumes.access.log;

    location / {
        proxy_pass http://badass-resumes;
        proxy_redirect  off;
        proxy_set_header        Host    $http_host;
        proxy_set_header        X-Forwarded-For  $proxy_add_x_forwarded_for;
    }

    location /robots.txt {
        alias /var/www/badassresumes/shared/robots.txt;
    }

    location /admin/media {
        alias /var/lib/python-support/python2.5/django/contrib/admin/media;
    }

    location /media {
        alias /var/www/badassresumes/current/files/media;
    }

    location /var/www/badassresumes/badassresumes/generated/ {
        root /;
        internal;
    }
}

server {
    listen 443;

    server_name badassresumes.com badass-resumes.com;

    access_log  /var/log/nginx/resumes-ssl.access.log;

    ssl on;
    ssl_certificate /etc/nginx/ssl/resumes.crt;
    ssl_certificate_key /etc/nginx/ssl/resumes.key;

    location / {
        proxy_pass http://badass-resumes;
        proxy_redirect  off;
        proxy_set_header        Host    $http_host;
        proxy_set_header        X-Forwarded-For  $proxy_add_x_forwarded_for;
    }

    location /robots.txt {
        alias /var/www/badassresumes/shared/robots.txt;
    }

    location /admin/media {
        alias /var/lib/python-support/python2.5/django/contrib/admin/media;
    }

    location /media {
        alias /var/www/badassresumes/current/files/media;
    }

    location /var/www/badassresumes/badassresumes/generated/ {
        root /;
        internal;
    }
}

Written by revjohnnyhealey

January 30, 2010 at 7:28 pm

Posted in Uncategorized

what the hell is julep?

leave a comment »

A couple of weeks ago, Zellyn Hunter, a coworker of mine, pointed me towards a description of unicorn, a backend web server for running rails/rack applications.  As a django person, he was interested in seeing if the same basic preforking model could be implemented in a WSGI server to achieve the same results.

After drinking a bunch and watching hackers, he managed to convince me that this was a good idea.

So, the next day, I started working on re-implementing unicorn in python.  After several name changes, the proof of concept that I built has evolved into julep.  I’m happy to say that I’ve managed to put it into production on one of my own sites, badass resumes.

If you’re interested in trying out julep, feel free to check out the google code page.  So far, it has been tested on python 2.5 and 2.6, but could potentially run on 2.4 if the wsgiref library is installed.  In the coming days, I’ll work on documenting it and putting up more information about the deployment details of badassresumes.  I’m also planning a series of benchmarks to see how well it does scale.

As with any free software project, you’re thoughts and ideas are welcome.

Written by revjohnnyhealey

October 30, 2009 at 11:20 pm

Posted in Code, julep, python

Djangocon X-Sendfile Lightning Talk

with 2 comments

Here’s the source code and slides from my Djangocon lightning talk about the X-Sendfile header.


from django.http import HttpResponse,Http404
from django.core.servers.basehttp import FileWrapper
from django.conf import settings

import mimetypes
import os

def basic_sendfile(fname,download_name=None):
    if not os.path.exists(fname):
        raise Http404

    wrapper = FileWrapper(open(fname,"r"))

    content_type = mimetypes.guess_type(fname)[0]
    response = HttpResponse(wrapper, content_type=content_type)
    response['Content-Length'] = os.path.getsize(fname)

    if download_name:
        response['Content-Disposition'] = "attachment; filename=%s"%download_name

    return response

def x_sendfile(fname,download_name=None):
    if not os.path.exists(fname):
        raise Http404

    content_type = mimetypes.guess_type(fname)[0]
    response = HttpResponse('', content_type=content_type)
    response['Content-Length'] = os.path.getsize(fname)
    response['X-Sendfile'] = fname

    if download_name:
        response['Content-Disposition'] = "attachment; filename=%s"%download_name

    return response

if getattr(settings,'SENDFILE',False) == 'x_sendfile':
    sendfile = x_sendfile
else:
    sendfile = basic_sendfile

Here are the slides: X-Sendfile Slides

Written by revjohnnyhealey

September 10, 2009 at 11:44 pm

Posted in Uncategorized

with one comment

Here’s a little snippet that you can stick into your .bashrc file. It creates a hash of the hostname and uses that to color the ps1 variable, so that hosts with similar names look different when you are shelled into them.

function colorps1() {
    word=`hostname --short`
    hash=`echo "$word" | md5sum`

    fullstr=""
    for l in `echo $word | sed 's/\(...\)/\1\n/g'`; do
        control=""
        endcontrol='\[33[00m\]'
        case "${hash:0:1}" in
            0)
            control='\[33[1;30m\]'
            ;;
            1)
            control='\[33[0;31m\]'
            ;;
            2)
            control='\[33[0;32m\]'
            ;;
            3)
            control='\[33[0;33m\]'
            ;;
            4)
            control='\[33[0;34m\]'
            ;;
            5)
            control='\[33[0;35m\]'
            ;;
            6)
            control='\[33[0;36m\]'
            ;;
            7)
            control='\[33[0;37m\]'
            ;;
            8)
            control='\[33[1;30m\]'
            ;;
            9)
            control='\[33[1;31m\]'
            ;;
            a)
            control='\[33[1;32m\]'
            ;;
            b)
            control='\[33[1;33m\]'
            ;;
            c)
            control='\[33[1;34m\]'
            ;;
            d)
            control='\[33[1;35m\]'
            ;;
            e)
            control='\[33[1;36m\]'
            ;;
            f)
            control='\[33[1;37m\]'
            ;;
        esac
        hash=${hash:1}

        fullstr="$fullstr$control$l"
    done
    fullstr="\[33[1;31m\]\\u@$fullstr$endcontrol \[33[1;34m\]\W \$ \[33[00m\]"
    export PS1=$fullstr
}

colorps1

Written by revjohnnyhealey

August 24, 2009 at 11:31 pm

Posted in bash, Uncategorized

First Post

with 2 comments

Hello, world!

I have finally entered the 21st century with my own blog.  In an attempt to keep it from becoming inane and unreadable, I’m going to stick to writing only about technology.  Just to clarify, here are lists of things I plan to post and not post about.

Things I will post:

  • Ideas about Free Software
  • Opinions about Python, Ruby, Lisp, Scheme
  • Code snippets
  • Responses to other technology-centric blogs

Things I will not post:

  • Opinions about politics, religion, or art
  • Stories about what I ate for breakfast
  • Beer Recipes

If I post anything that doesn’t seem to be technology-related, I give you permission to publicly berate me in the comments.

Written by revjohnnyhealey

August 24, 2009 at 1:50 am

Posted in Meta

Follow

Get every new post delivered to your Inbox.