Discourse socketed: outer nginx rate limiting when opening emoticons

I have discourse running socketed behind an outer nginx proxy. It works: i can see my posts, create new ones, do backups, restores, etc.

I have used the settings from the inner nginx in the discourse docker (when it was standalone). Therefore i also copied the rate limiting from there, and adapted it a bit, it is presented below.

There is a problem though with my setup: it seems outer nginx is rate-limiting the emoticons box:
image

cat /var/log/nginx/error.log
[...]
2018/09/05 18:03:51 [error] 32008#32008: *235 limiting requests, excess: 20.295 by zone "flood", client: 193.186.16.206, server: chat.tbp.land, request: "GET /images/emoji/apple/strawberry.png?v=6 HTTP/2.0", host: "chat.tbp.land", referrer: "https://chat.tbp.land/"
2018/09/05 18:03:51 [error] 32008#32008: *235 limiting requests, excess: 20.295 by zone "flood", client: 193.186.16.206, server: chat.tbp.land, request: "GET /images/emoji/apple/pear.png?v=6 HTTP/2.0", host: "chat.tbp.land", referrer: "https://chat.tbp.land/"

What i did with the limit zones was place them inside the http context, and not in server, but i don’t think that’s a problem as limit_req can be placed in http.

Did i miss anything by any chance?

This is my rate-limiting config placed in http context:

#=================================================
#               Rate limit EVERYTHING!!!!!!!

# rate limiting zones
limit_req_zone $binary_remote_addr zone=flood:10m rate=15r/s;
limit_req_status 429;

limit_conn_zone $binary_remote_addr zone=connperip:10m;
limit_conn_status 429;

# rate limiting zones are applied for all servers!
limit_conn connperip 20;
limit_req zone=flood burst=20 nodelay;

#=================================================

I see another related post: 429 too many emoji requests 😥 but so far i don’t see any solution.

1 Like

Okay, bear with me for a little bit more please. I hope i’m on the right track:

I have the feeling that the rate-limiting in the discourse configuration is a bit more nuanced than I initially understood.

In the http context i see a group of servers which i suppose represents the ruby backend:

upstream discourse { server 127.0.0.1:3000; }

In the discourse server context i see the only rate limited location: (which is not indented nicely :stuck_out_tongue:)

  location @discourse {
    limit_conn connperip 20;
    limit_req zone=flood burst=12 nodelay;
    limit_req zone=bot burst=100 nodelay;
    [...]
    proxy_pass http://discourse;
  }

compared to:

   # cache emojis
    location ~ /images/emoji/ {
      expires 1y;
      add_header Cache-Control public,immutable;
    }

This means that i misunderstood the rate limiting configuration as initially I was expecting that EVERYTHING is rate limited!!!

Now i am thinking that the rate limiting is actually set only for the requests which are sent to the ruby backend. The emoticons (and for that matter the rest of assets and uploads) are served by nginx and not by ruby, and they don’t have any rate limiting.

If this is the case, then my idea to rate-limit everything is wrong because I am rate-limiting the inner nginx which serves the static content that shouldn’t be limited.

And this means that i have to take my rate limiting out of the http context and place it inside every server. <- do i really have to do that? inside each? But… that’s a lot of work to do though :cry: (think that i have multiple subdomains which mostly do 301 redirects and only a few proxy_pass)

HA! (again)

I found a way to disable the rate limiting only for my discourse server:

#=================================================
#               Rate limit EVERYTHING!!!!!!! (:blush: except for discourse)

map $http_host $rate_limit_except_discourse {
    "chat.tbp.land"     "";                 # in case of an empty string, limit_req_zone won't be applied!
    default             $binary_remote_addr;
}

# log_format derp '[$time_local] "$http_host" >$rate_limit_except_discourse<';
# access_log /var/log/nginx/derp.log derp;

# rate limiting zones
limit_req_zone $rate_limit_except_discourse zone=flood:10m rate=15r/s;
limit_req_status 429;

limit_conn_zone $rate_limit_except_discourse zone=connperip:10m;
limit_conn_status 429;

# rate limiting zones are applied for all servers!
limit_conn connperip 20;
limit_req zone=flood burst=20 nodelay;

#=================================================

I create a new variable named $rate_limit_except_discourse in which, based on $http_host i enable or disable rate limiting: when chat.tbp.land == $http_host then $rate_limit_except_discourse will have the value "" (nothing), and for all the other websites (by using the default keyword) i use the normal $binary_remote_addr;.

In this way I don’t have to copy-pasta the same lines in all my servers and the rate limiting is left for inner nginx (the one in the discourse container).


SUCCES! :triumph:

4 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.