Skip to content

[Feature Request] Add listening port-based routing rule support #4993

@joeshae

Description

@joeshae

Problem Description

Currently, Xray's routing rules support matching based on destination port (port), source port (sourcePort), and various other criteria, but there is no way to route traffic based on which port the server is listening on. This creates significant limitations when trying to implement port-based traffic distribution in multi-port deployment scenarios.

Current Behavior

In the current implementation:

  • port in RuleObject matches the destination port (the port the client wants to connect to, e.g., 80, 443)

  • sourcePort matches the client's source port

  • inboundTag can differentiate between different inbounds, but requires separate inbound configurations

Proposed Solution

Add a new field listenPort or serverPort to the RuleObject:

{
  "routing": {
    "rules": [
      {
        "listenPort": "25001-26000",
        "outboundTag": "out-group-1"
      },
      {
        "listenPort": "26001-27000", 
        "outboundTag": "out-group-2"
      }
    ]
  }
}

This would match against the port that the server accepted the connection on, not the destination port in the traffic.

Why This Is Important

  1. Scalability: Allows port-based routing without creating hundreds of duplicate inbounds
  2. Simplicity: Maintains single user database instead of duplicating across inbounds
  3. Compatibility: Works well with frontend proxies (HAProxy, Nginx) that use PROXY protocol
  4. Real-world need: Many proxy services use port numbers to differentiate service levels or routing paths

Alternative Considerations

We've explored workarounds like:

  • Using source IP manipulation (breaks client IP preservation)
  • Creating multiple inbounds (configuration explosion)
  • Using user-based routing (not applicable for protocols without user identification)

None of these solutions are practical for large-scale deployments.

Implementation Notes

The listening port information should already be available in the connection context, as it's needed for the initial socket accept. This feature would simply expose it to the routing engine.

Backward Compatibility

This would be a new optional field, so existing configurations would continue to work without modification.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions