Nginx: Accelerate Rails, HTTP Tricks
-
Upload
adam-wiggins -
Category
Technology
-
view
15.085 -
download
1
description
Transcript of Nginx: Accelerate Rails, HTTP Tricks
Nginx:Accelerate Rails,HTTP Tricks
Adam WigginsRailsconf 2008
Nginx is a webserver
Nginx replaces ApacheWhich means:
‣Faster‣Smaller memory footprint‣More stable under load‣More secure
Nginx replaces Apache
But more importantly:
But more importantly:
Nginx is a better fitfor Rails
Apache is the right tool:
‣mod_php‣owning your own server hardware
Apache is the right tool:
‣mod_php‣owning your own server hardware
The era now coming to a close.
‣Rails‣cloud computing
The era now upon us:
Which both work best with proxying.
‣Rails‣cloud computing
The era now upon us:
Proxying is Nginx’sprimary mechanism forserving dynamic content
“One thing”
Embrace the constraintof keeping applicationVMs out of the front-endwebserver
Ok cool.
Wait, there’s something funnygoing on here...
Ok cool.
Nginx is not a webserver?
Nginx is an HTTP router
Enough abstraction;let’s see some code
Proxy balancing example
upstream myapp_mongrels { 127.0.0.1:3000; 127.0.0.1:3001;}
location / { proxy_pass http://myapp_mongrels;}
Memcached in front
location / { set $memcached_key $uri; memcached_pass 127.0.0.1:11211; error_page 404 502 = @myapp;}
location @myapp { internal; proxy_pass http://myapp_mongrels;}
Memcached method filter
location / { if ($request_method = GET) { set $memcached_key $uri; memcached_pass 127.0.0.1:11211; error_page 404 502 = @myapp; break; }
proxy_pass http://myapp_mongrels;}
Filtering
Filtering is reaching inand tinkering withrequests and responses
Separate concerns:
Separate concerns:
‣Filters in your app for business logic
Separate concerns:
‣Filters in your app for business logic
‣Filters in your http router for server infrastructure
Separate concerns:
‣Filters in your app for business logic
‣Filters in your http router for server infrastructure
‣Filters in either for application infrastructure
application infrastructure
Separate concerns:
‣Filters in your app for business logic
‣Filters in your http router for server infrastructure
‣Filters in either for
Custom Nginx modulesTime to get hardcore:
http://emiller.info/nginx-modules-guide.html
Granular user access control
The problem:
before_filterThe Rails solution:
The Rails solution: before_filter
before_filter :authorize
def authorize @user = User.find(session[:user_id]) @resource = request.env['REQUEST_URI']
redirect_to '/login' unless @user
redirect_to '/access_denied' unless @user.can_access(@resource)end
Can we do this withouttouching the Rails app’scode?
input filter moduleThe Nginx solution:
input filter moduleThe Nginx solution:
ngx_heroku_gate
before_filter :authorize
static ngx_int_tngx_heroku_gate_init(ngx_conf_t *cf){ phase = cmcf->phases[NGX_HTTP_ACCESS_PHASE];
h = ngx_array_push(&phase.handlers); *h = ngx_heroku_gate_handler;}
before_filter :authorize
def authorize @user = User.find(session[:user_id]) @resource = request.env['REQUEST_URI']
static ngx_int_t ngx_heroku_gate_handler (ngx_http_request_t *req){ user = get_logged_in_user( req->headers_in.cookies);
app_name = get_app_name( req->headers_in.host->value.data);
def authorize @user = User.find(session[:user_id]) @resource = request.env['REQUEST_URI']
redirect_to '/login' unless @user
if (!user){ redirect_to(req, '/login'); return NGX_HTTP_MOVED_TEMPORARILY;}
redirect_to '/login' unless @user
redirect_to '/access_denied' unless @user.can_access(@resource)
if (!user_can_access(user, app)){ redirect_to(req, '/access_denied'); return NGX_HTTP_MOVED_TEMPORARILY;}else{ write_heroku_user_header(req, user); return NGX_OK;}
redirect_to '/access_denied' unless @user.can_access(@resource)
#define X_HEROKU_USER "X-Heroku-User"
static void write_heroku_user_header (ngx_http_request_t *r, u_char *user){ h = ngx_list_push( &r->headers_in.headers);
h->hash = 1; h->key.len = sizeof(X_HEROKU_USER) - 1; h->key.data = (u_char *) X_HEROKU_USER; h->value.len = strlen((char *)user); h->value.data = user;}
The Rails solution: before_filter
before_filter :authorize
def authorize @user = User.find(session[:user_id]) @resource = request.env['REQUEST_URI']
redirect_to '/login' unless @user
redirect_to '/access_denied' unless @user.can_access(@resource)end
static ngx_int_tngx_heroku_gate_handler(ngx_http_request_t *req){ user = get_logged_in_user(req->headers_in.cookies); app_name = get_app_name(req->headers_in.host->value.data);
if (!user) { redirect_to(req, '/login'); return NGX_HTTP_MOVED_TEMPORARILY; }
if (!user_can_access(user, app)) { redirect_to(req, '/access_denied'); return NGX_HTTP_MOVED_TEMPORARILY; } else { write_heroku_user_header(req, user); return NGX_OK; }}
The Nginx solution: input filter
A word on performance
Closing thoughts /the future
HTTP is the enablingprotocol for the eraof cloud computing
http://igvita.com/2008/02/11/nginx-and-memcached
http://nginx.ru
Adam Wigginshttp://adam.blog.heroku.com
http://emiller.info/nginx-modules-guide.html