nginx automatic variables with dashes

This has recently come up in my work for a large e-commerce company. We were using nginx as a frontend caching load balancer and wanted to route some requests to different backends depending on a header that had a dash in its name. We also wanted to log another request header. Unfortunately, nginx’s variable parser does not map headers with dashes (and some other characters) to anything usable, so you cannot use something like “$http_x-origin” in a directive.

Quirky behavior to the rescue! You can remap variables with complex names by using the map module as follows:

map $is_args $http_x_origin {
  default $http_x-origin;

The trick is that map does not fully parse its arguments. The syntax is: map A X { default Y; }, with:

  • A any variable, preferably one that does not trigger much internal processing (since nginx configs are declarative, using a variable evaluates it). I use $is_args because it’s cheap to calculate.
  • X is the name for the new variable you’ll be creating, i.e. the map target.
  • Y is the name of the variable you want to access. At this point, it can contain dashes, because map does its own parsing.

The variable will then be available as X.