查看完整版本: Proxying Gotchas (and tricks) with Nginx

ELM 2007/11/12 19:59

Proxying Gotchas (and tricks) with Nginx

As I continue my migration away from Pound and Lighttpd, I'm discovering dark corners of Nginx. Tonight I ran into a problem proxying from Nginx to a Lighttpd backend that's running Mailman and it turns out to be a gem.

Because I've got a lot of sites to migrate, I'm trying to minimize the changes I make at any given point. Many sites rely on custom Lighty configs and with those I'm simply swapping Nginx in for Pound and proxying to Lighty. Later I'll work on eliminating Lighty.

Anyway, I have a site that's using Mailman, and because Nginx doesn't have CGI support, I'm leaving Lighty in place to handle Mailman for the moment. I tried an Nginx config that looked something like this:[code]location ~ /(mailman|pipermail)/ {
    proxy_pass http://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;
}[/code]This failed to load with the following error:

* Checking nginx' configuration ...
2006/09/04 02:36:33 [emerg] 4067#0: "proxy_pass" may not have URI part in location given by regular expression or inside the "if" statement in /etc/nginx/nginx.conf:7
2006/09/04 02:36:33 [emerg] 4067#0: the configuration file /etc/nginx/nginx.conf test failed
* failed, please correct errors above

This seemed strange. Why would a proxy not be allowed within a regex location?

"Fine", I thought. "I'll just eliminate the regex for now and figure it out later." So I changed the config to look like this:[code]location /mailman/ {
    proxy_pass http://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;
}[/code]This was accepted but I got a 404 whenever I tried to go to /mailman. Lighty is configured to run on 8000 and I could see from the Lighty log that the request was getting passed through. What was odd is that I could also see that the first part of the request header was getting stripped off. For instance, /mailman/subscribe would become just /subscribe and thus generate a 404.

Finally I realized I'd added a trailing slash to the proxy_pass directive in nginx.conf. Removing this solved the problem. I then decided to try the regex again. This too now worked.

My config now looked like this:[code]location ~ /(mailman|pipermail)/ {
    proxy_pass http://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;
}[/code]So what's the gem? Well, apparently you can strip off the location part of the URL by appending the trailing slash to the proxy_pass directive. This is actually a pretty useful feature if you are proxying to a server such as TurboGears that isn't mounted at the document root. Rather than mucking about trying to get the server root set correctly (which I've never managed to do), you can simply have Nginx strip it off.

[Update]

I wanted to give a more concrete example of using this feature, but didn't have one at the time I originally wrote this entry. I'm moving to a new blog and ended up using this.

The new blogging software I'm using runs on top of Zope, which, unless you are a Zope user, can lead to all sorts of mysterious requirements. Well, one of these requirements is that the blog reside mounted at /users (well, not /users specifically, but not the root). I wanted the blog to be the front page. I could solve this in Zope, I know, but it would be a pain to figure out. Enter Nginx:

Solution 1: rewrite urls.

The obvious and traditional (ala Apache) solution would be to use rewrite rules, and this does in fact, work:[code]server {
    listen 80;
    server_name blog.twisty-industries.com;
    location = / {
        rewrite (.*) /users last;
    }

    location / {
        proxy_pass http://127.0.0.3:8082;
        include /etc/nginx/proxy.conf;
    }
}[/code]Is there a downside? Shrug. There is a slightly better way however:

Solution 2: proxy path:[code]server {
    listen 80;
    server_name blog.twisty-industries.com;
    location / {
        proxy_pass http://127.0.0.3:8082/users;
        include /etc/nginx/proxy.conf;
    }
}[/code]I suspect this is a bit more efficient, both in lines of configuration and in request processing time. In short, I like it.
页: [1]
查看完整版本: Proxying Gotchas (and tricks) with Nginx