Some time ago I had the requirement to limit the number of requests per IP to a CouchDB-instance. I couldn’t find an option for CouchDB to achieve that, but as communication with CouchDB is based on HTTP-requests I thought that it should be possible to use nginx as reverse proxy with rate-limiting capabilities for CouchDB. The CouchDB-wiki lists some basic steps how to use nginx as reverse proxy, but rate limiting isn’t mentioned there.
Beside the actual rate limiting I noticed that nginx won’t work, because it doesn’t support chunked request-bodies out of the box, which CouchDB seems to rely onto. But to the rescue there is a nginx module called ngx_chunkin, which adds chunkin support to nginx. To get that module in Debian you need to install nginx-extras from the repository (available since squeeze-backports). The configuration of that module is straight forward as described on the wiki page. All you have to do is to put the following code snippet into the server-context of your nginx configuration:
chunkin on; error_page 411 = @my_411_error; location @my_411_error { chunkin_resume; }
Having solved that issue, doing the actual rate limiting was the next step. Therefore nginx ships the module ngx_http_limit_req_module. All I had to do was to configure a zone for the limited requests in the http-context of the configuration:
limit_req_zone $binary_remote_addr zone=couchdb_write:10m rate=10r/s;
and the logic what to rate limit (writing requests in my case) into the server-context:
location / { # POST, PUT, DELETE ... requests will get rate limiting if ($request_method !~* GET) { rewrite ^(.*)$ /throttled$1 last; } proxy_pass http://127.0.0.1:5985; proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /throttled { internal; limit_req zone=couchdb_write burst=10000; rewrite /throttled(.*) $1 break; proxy_pass http://127.0.0.1:5985; proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
So if you put together the chunkin support and the rate limiting, you’ll get the following piece of configuration for a server which does rate limiting of writing CouchDB-requests using nginx:
limit_req_zone $binary_remote_addr zone=couchdb_write:10m rate=10r/s; server { listen 5984; chunkin on; error_page 411 = @my_411_error; location @my_411_error { chunkin_resume; } location / { # POST, PUT, DELETE ... requests will get rate limiting if ($request_method !~* GET) { rewrite ^(.*)$ /throttled$1 last; } proxy_pass http://127.0.0.1:5985; proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /throttled { internal; limit_req zone=couchdb_write burst=10000; rewrite /throttled(.*) $1 break; proxy_pass http://127.0.0.1:5985; proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
I really enjoyed figuring that out, because it was a lot of fun to be able to use a great tool (nginx) to extend another great tool (CouchDB), because they’re using the same protocol (HTTP).