Nginx, Passenger and Rails -- a high-level overview November 11, 2011
One of my friends is somewhat new to Rails, and certainly new to rails deployment. He was a bit unclear about what role the different parts of the rails deployment stack (Nginx, passenger and rails) were in serving the request, so I wrote up the following and figured it might help other netizens, soI posted it here. Please drop me a line or leave a comment if something is unclear.
Sometimes, we use the terms "web server" or "application server" interchangeably, but for the purposes of this email, we mean distinctly different things.
NGINX or Apache are web/http servers -- that is, they bind to ports and accept incoming http requests from clients. They are the "front line" when it comes to client machines talking with your server (unless you have a load balancer or caching proxy, like haproxy or Varnish, but that is a discussion for another time.)
So, they accept the incoming connection from the user's computer and then they decide how to "handle" the request. With NGINX or Apache, you can do things like having different "Virtual Hosts", which is where you can set up a different strategy for different requests depending on things like the domain being requested, certain cookies or even if the url matches a certain pattern. Additionally, since NGINX or Apache sit at the front of the connection between the client and the server, it is common to handle things like GZIP encoding here (so your pages are compressed for browsers that support it.)
So: the job of the HTTP server is to handle lots of connections and figure out what "handler" to use. Most HTTP servers include a default filesystem handler that is able to serve static assets off the disk (images, css files, et cetera.)
Because the HTTP server handles raw client connections and is available to the internet, it is a big "attack surface" for malicious code, so it should run with very low permissions and do as little as possible. Even though you use root to start apache, it will change its user to "nobody" once it has opened the ports so hackers can't pwn your box even if they can crack apache remotely.
So, if your HTTP server is nice and small, how do you connect this to your web app's code? Well, that is where an application server comes in. Passenger is an application server (similar to PHP-FPM,) and its job is to connect to an http server and handle requests. The http server says to the application server "here is a bunch of details about the request, like the headers and the body, give me the response" and the application server gives it the response.
Passenger handles the connection between the HTTP server and your application code. When nginx starts up, it starts up passenger which starts your application in a few processes. When a request comes in, it goes to nginx, which gives it to passenger, which gives it to one of your application processes, which handles the request and then responds with the headers and html that are sent to the browser.
This http server and application server distinction can be tricky if you are talking to people whose development stacks combine them -- for instance, you can run Java apps or Node.js apps with a BUILT-IN http server. You could do this with ruby using something like webrick, but that is very slow compared to nginx or apache.