Showing posts with label web development. Show all posts
Showing posts with label web development. Show all posts

Tuesday, January 31, 2012

My twelve-factor app development environment (Unicorn and Pound)

I've been hugely influenced by the twelve-factor app manifesto written by Heroku. I really like building apps on Heroku and think it's pretty great for prototyping things, because it totally abstracts the need to think about devops in the early stages of a project. I don't think Heroku is a panacea (I don't have experience running something large on it), but it's great for getting something going quickly.

That manifesto illustrates how you end up building your app if you launch it on Heroku. I've found the  principles greatly increase my productivity no matter what platforms I'm using. One thing that did take me a little while to figure out: most of my apps are SSL-only, and I always want to interact with them over SSL in my development environment because odd things can creep up in production if you never test SSL locally. (Most of the advice that Rails blogs give always point you towards shutting off SSL in development mode which seems crazy to me)

At first I couldn't quite figure out how to make SSL work while complying with factor 7, Port Binding. I was still using Phusion Passenger with SSL configured as I described in this very old article (which still gets a lot of traffic).

Now here's what I do. I run the Pound reverse proxy using this configuration:

# http://lvh.me
ListenHTTP
  Address 127.0.0.1
  Port    80

  Service
    BackEnd
      Address 127.0.0.1
      Port    8080
    End
  End
End

# https://lvh.me
ListenHTTPS
  Address 127.0.0.1
  Port    443
  Cert    "/usr/local/etc/pound.pem"
  AddHeader "X_FORWARDED_PROTO: https"

  Service
    BackEnd
      Address 127.0.0.1
      Port    8080
    End
  End
End

The /usr/local/etc/pound.pem file is a locally-generated, locally-signed SSL certificate.

When I want to view an SSL-only app in my local browser, I just start Unicorn (my app container of choice) which defaults to port 8080. Then I visit https://lvh.me which is helpfully set to the loopback address 127.0.01. That hits Pound, which terminates the SSL connection (after a warning about the self-signed certificate), and proxies the web request to Unicorn.

This is very similar to what happens when the app runs in production on Heroku's systems, except that they use a Procfile in the root directory of the app to configure Unicorn. Per factor 7, it allows Heroku to bind my Unicorn instance to any arbitrary port:

web: bundle exec unicorn -p $PORT -c config/unicorn.rb

Tuesday, May 15, 2007

Build a Toy First

So far in my career I've only developed web applications for internal use -- intranet sites and the like. Recently I gave myself the challenge to create a simple public web app over the course of the weekend. Writing the code took only the weekend, but getting the deployment configuration right, and optimizing to withstand just the small trickle of traffic I was seeing took two more weeks.

I thought I knew Rails and Apache and MySQL and other technologies inside and out, but once I had to really cope with real-world obstacles I was knocked on my ass. My original configuration was not fast enough, and I had to implement caching to make things more responsive. I set up a number of monitoring systems to automatically restart my dispatchers if something went wrong. I found an awesome SSH client for my Treo which I had to use when my server started acting up and I was away from my home computer.

I also learned that the Internet is international -- I unconsciously assumed that most of my users would be based in the United States, but that's exactly wrong. I've got users from Växjö to Santiago de Compostela.

The site itself isn't much to look at -- I'm no graphic designer -- but it represents a major lesson for me in how to deploy a public-facing site. I'm greatly influenced by it while pursuing my other projects -- for instance, I now bake caching considerations directly into my code. I am not relying on flash[:notice] to pass messages back to the user. I'm either creating separate notification pages that can be cached, or I'm using Ajax to just update small parts of the page with status messages.

Saturday, March 10, 2007

First web app launch

I launched my first web application today! It's a small site to help people find potential company co-founders:

FounderFinder.com


It's getting pretty good reviews from the site I originally got the idea from.