Okay cool, I guess I was testing locally without realizing it. I can reproduce now.
The 411 is being produced by nginx before ever getting to Rails. After some investigation, it turns out that this is the correct behavior. From the HTTP/1.1 4.4 spec, on Message Length:
For compatibility with HTTP/1.0 applications, HTTP/1.1 requests containing a message-body MUST include a valid Content-Length header field unless the server is known to be HTTP/1.1 compliant. If a request contains a message-body and a Content-Length is not given, the server SHOULD respond with 400 (bad request) if it cannot determine the length of the message, or with 411 (length required) if it wishes to insist on receiving a valid Content-Length.
Whether or not a PUT implies a message-body is arguable, but it seems nginx leans on the “yes, it does” side, so you must specify a Content-Length. See some reasoning here: Is an HTTP PUT request required to include a body? - Stack Overflow
curl seems to automatically specify a Content-Length for you if there’s a message-body present (to see this, try replacing -H 'Content-Length: 0' with just -d ''). But if there’s not one, you’ll have to do it manually.
Hope this helps.
EDIT: Yeah @BarryCarlyon basically hit the nail right on the head.