Edge rules
Edge rules match incoming HTTP requests and handle them at Railway's edge before they reach your service. You can block, allow, challenge, redirect, or override caching for matching requests.
Edge rules require a public domain and a plan with an edge-rule allowance. Add a Railway-provided or custom domain before you configure rules. The rule editor displays the limit for your plan.
How edge rules work
Railway evaluates edge rules at the nearest edge location. Rules are configured for a service in the selected environment and apply to every domain attached to that service.
The order of your rules determines how Railway handles a request:
- Railway evaluates enabled rules from top to bottom.
- A rule runs its action when its configured match expression evaluates to true.
- The first matching terminal action decides the request outcome. Block, allow, challenge, and redirect are terminal actions.
- An override cache action changes caching behavior and continues to later rules.
- If no terminal action matches, Railway forwards the request to your service.
A challenge is terminal for a visitor without valid challenge clearance. After the visitor passes the challenge, Railway continues evaluating later rules on subsequent matching requests.
Saved changes propagate to Railway's edge locations within a few seconds.
Configure edge rules
Use the rule builder in your service settings to create and order rules:
- Open the service in the environment you want to configure.
- Navigate to the service Settings.
- In the Edge section, find Edge Rules.
- Click Add a rule, or click Manage Rules to edit existing rules.
- Optional: Enter a name that describes the rule.
- Configure one or more request conditions.
- Select the action Railway runs when the conditions match.
- Add other rules, then drag them into evaluation order.
- Click Save.
Toggle a rule off to keep its configuration without evaluating it. Remove every rule and save to clear the ruleset.
Match requests
Each condition compares a request attribute with a value. The available operators depend on the attribute.
| Attribute | Operators | Behavior |
|---|---|---|
| Client IP | is, is not, is in, is not in | Matches an IPv4 address or CIDR range, such as 203.0.113.7 or 203.0.113.0/24. Requests without an IPv4 source don't match. |
| Host | is, is not, is in, matches | Matches the lowercase, canonical hostname without a port. |
| Path | is, is not, contains, matches | Matches the normalized path without the query string. Path comparisons are case-sensitive. |
| Header | is, is not, contains, matches | Requires a header name. Header names are case-insensitive, and header values are case-sensitive. |
The is in and is not in operators accept comma-separated values in the
builder. Use matches for wildcard patterns. The * character matches zero
or more characters, so /admin* matches /admin and /admin/users. With any
other operator, * is a literal character.
Combine conditions with and or or. You can also add nested groups that
match all, any, or none of their conditions. A negative comparison against a
missing value doesn't match. For example, Header x-client is not mobile
doesn't match a request without the x-client header.
Choose an action
Each rule has one action. Terminal actions stop evaluation when they match, while an override cache action continues to later rules.
| Action | Behavior | Terminal |
|---|---|---|
| Block | Returns an HTTP status from 400 through 499. The default is 403, and you can add a response body. | Yes |
| Allow | Forwards the request to your service and skips all later rules. Put allow rules above broader block or challenge rules to create exceptions. | Yes |
| Challenge | Shows a browser verification page to visitors without valid clearance. A cleared visitor continues through later rules. | Yes, until cleared |
| Redirect | Redirects to another host or an exact HTTP or HTTPS URL. Supported status codes are 301, 302, 307, and 308. Host redirects can preserve the original path and query string. | Yes |
| Override cache | Caches matching responses for a fixed time or bypasses the edge cache. A fixed time can range from 1 second through 30 days. See CDN caching. | No |
Order rules safely
Place narrow exceptions before broad terminal rules. For example, to let an
office network reach /admin while blocking everyone else:
- Add an allow rule that matches both
/admin*and the office IPv4 CIDR. - Add a block rule below it that matches
/admin*.
The allow rule admits requests from the office network and skips the block rule. Other requests don't match the allow rule, so Railway evaluates and applies the block rule.
Edit rules as JSON
Click Edit as JSON in the rule editor to work with the complete ruleset. Railway validates the whole ruleset before saving it. If validation fails, Railway displays diagnostics and doesn't change the saved rules.
The following ruleset implements the ordered allow and block rules described
above, then bypasses caching for /api requests:
{
"version": 1,
"rules": [
{
"description": "Allow office access to admin",
"priority": 10,
"enabled": true,
"if": {
"and": [
{
"attr": "http.path",
"op": "matches",
"value": "/admin*"
},
{
"attr": "ipv4.src",
"op": "in",
"value": ["203.0.113.0/24", "198.51.100.7"]
}
]
},
"then": {
"action": "allow"
}
},
{
"description": "Block other admin requests",
"priority": 20,
"enabled": true,
"if": {
"attr": "http.path",
"op": "matches",
"value": "/admin*"
},
"then": {
"action": "block",
"params": {
"status": 403,
"body": "Forbidden"
}
}
},
{
"description": "Bypass cache for API requests",
"priority": 30,
"enabled": true,
"if": {
"attr": "http.path",
"op": "matches",
"value": "/api*"
},
"then": {
"action": "cache_override",
"params": {
"bypass": true
}
}
}
]
}Configure the ruleset
The ruleset object contains the schema version and the ordered rules.
| Field | Required | Description |
|---|---|---|
version | Yes | Schema version. Set this to 1. |
rules | Yes | Array of rule objects. |
Each rule supports these fields:
| Field | Required | Description |
|---|---|---|
description | No | Human-readable rule name, up to 256 characters. |
priority | Yes | Unique unsigned integer that determines evaluation order. Lower values run first. |
enabled | No | Whether Railway evaluates the rule. Defaults to true. |
if | Yes | Condition clause or a nested and, or, or not expression. |
then | Yes | Action object with an action name and optional params. |
id | No | Stable rule ID. Omit it when creating a rule so Railway assigns a rul_ ID. |
Configure condition JSON
A condition clause uses attr, op, and value. Add key when attr is
http.header:
{
"attr": "http.header",
"key": "x-client-type",
"op": "eq",
"value": "mobile"
}Use the attribute and operator identifiers in the following table.
| Attribute identifier | Supported operator identifiers |
|---|---|
ipv4.src | eq, neq, in, not_in |
http.host | eq, neq, in, matches |
http.path | eq, neq, contains, matches |
http.header | eq, neq, contains, matches |
The in and not_in operators require an array of strings. All other
operators require one string.
Combine conditions by nesting them under and, or, or not:
{
"or": [
{
"attr": "http.path",
"op": "matches",
"value": "/internal*"
},
{
"not": {
"attr": "http.header",
"key": "x-client-type",
"op": "eq",
"value": "trusted"
}
}
]
}Configure action JSON
The action object uses one of these shapes.
| Action | Parameters |
|---|---|
block | Optional status from 400 through 499 and optional body up to 4,096 bytes. |
allow | No parameters. |
challenge | No parameters. |
redirect | Exactly one of host or location. Optional status is 301, 302, 307, or 308. Host redirects also accept preserve_path and preserve_query booleans, which default to true. |
cache_override | Exactly one of ttl_seconds from 1 through 2592000, or bypass set to true. |
Review limits and validation
Railway enforces your plan's rule count and validates each ruleset before it reaches the edge. The editor reports validation errors next to the affected rule or field.
In addition to the plan limit, a ruleset has these limits:
- 64 KiB for the complete JSON ruleset.
- 32 condition clauses per rule.
- Four levels of condition expression depth.
- 256 characters per condition value and description.
- 64 entries in an
inornot_invalue array. - Eight
*wildcards per pattern.
Related documentation
Explore these resources to learn about the networking features that interact with edge rules:
- Use WAF for service-wide Under Attack Mode.
- Review CDN for edge caching behavior and configuration.
- Read Edge networking to learn how requests reach Railway's edge locations.
- Configure domains to attach Railway-provided and custom domains to a service.