290 words
1 minute

An Nginx Port-Forwarding Pitfall

2025-04-01
Views —

I recently made a serious mistake while configuring Nginx port forwarding. Here is what happened.

Our game server used WSS, and Nginx needed to forward many paths to backend WebSocket ports. For example, wss://xxx.com/10000 should reach ws://xxx.com:10000. The requested range was around ports 10000–11000. I did not want to write a thousand separate rules, so I found this configuration online:

location ~* ^/(?<port>\d+)$ {
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}

At first glance, it seemed to work: take the number after / and use it as the backend port.

Then a colleague noticed the problem. Although our security group exposed only the intended game-server ports, this rule allowed a user to reach any local port indirectly through Nginx’s public port 80 or 443. A small deployment might appear to work normally, but scanning could expose sensitive internal services as traffic grew.

Restrict the destination port#

My first thought was to use if. I had also encountered the Nginx community’s “If Is Evil” discussion about unexpected behavior in some configurations, so I decided to restrict the numeric match instead.

These are the two patterns recorded in the original post:

location ~* ^/(?<port>(20[0-9]\{3\}))$ {
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}

Or:

location ~* ^/(?<port>2[0-1]\d\d\d)$ {
proxy_pass http://127.0.0.1:$port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
}

The intent was to match only an allowed range and reject other ports, rather than pass arbitrary user-supplied numbers to the upstream.

Translation note: the original post describes a 10000–10999 match, but the two restricted patterns above do not implement that range as written. One also escapes the repetition braces. They are preserved here as historical examples; validate the actual pattern and allowed port range before using the configuration.

An Nginx Port-Forwarding Pitfall
https://blog.coding1024.com/en/posts/ef62fe3f/
Author
huangjx
Published at
2025-04-01
License
CC BY-NC-SA 4.0

Comments

Questions, ideas and experiences are welcome. Please be kind and avoid sharing private information.

Loading comments…