97 lines
5.7 KiB
Markdown
97 lines
5.7 KiB
Markdown
# Custom locations
|
|
|
|
RustProxy 0.22.3 supports the common location-level controls that are typically used for application reverse proxies. The UI intentionally exposes a safe subset instead of accepting arbitrary Nginx configuration text.
|
|
|
|
## Routing model in 0.16.0
|
|
|
|
The vhost's main backend pool is an internal fallback and is **not** one of the Custom locations. Custom locations are optional overrides only. Request routing is therefore:
|
|
|
|
```text
|
|
exact custom location
|
|
-> priority/regex/prefix custom location according to the documented precedence
|
|
-> main vhost backend pool
|
|
```
|
|
|
|
An empty Custom locations list is valid. Adding `/test`, a regex, a local response or a dedicated-backend location cannot disable `/`, `/abc` or other unmatched paths. Older saved documents that contain the former untouched synthetic `root` prefix `/` entry are normalized automatically. If `/` was deliberately customized with a backend, cache/ACL/header rule, rewrite or local response, it remains a real Custom location and intentionally overrides the main fallback.
|
|
|
|
## Dashboard editor
|
|
|
|
The visual editor is the primary workflow. Every location card now shows a live **Effective behavior preview** at the bottom with the match mode/pattern, proxy or local-response action, selected backend, rewrite behavior, cache policy, ACL composition and request/response header-rule counts. The preview is calculated from the unsaved form state so an administrator can verify intent before saving.
|
|
|
|
Request and response header rules use numbered visual cards with localized **Operation / Header name / Header value** controls. `Set`, `Append` and `Remove` are supported. The Advanced JSON view remains available for automation/copy-paste, but is no longer required for normal editing. The documentation button in the location tab explains precedence, rewrites, local responses, policy composition and common examples.
|
|
|
|
## Match modes
|
|
|
|
Each location has an ID, a pattern and one match mode:
|
|
|
|
| RustProxy mode | Nginx-style equivalent | Behaviour |
|
|
| --- | --- | --- |
|
|
| `prefix` | `location /path/` | Longest matching path prefix. A matching regex may still win. |
|
|
| `prefix_priority` | `location ^~ /path/` | Longest prefix and, when selected, skips regex locations. |
|
|
| `exact` | `location = /path` | Exact normalized path only. Exact matches have highest priority. |
|
|
| `regex` | `location ~ pattern` | Case-sensitive Rust regular expression. Regex locations are tested in configuration order. |
|
|
| `regex_insensitive` | `location ~* pattern` | Case-insensitive Rust regular expression. Regex locations are tested in configuration order. |
|
|
|
|
Routing and ACL checks collapse repeated literal slashes, matching Nginx's usual `merge_slashes on` behaviour. For example `/static/js//events.js` is routed as `/static/js/events.js`. Unless a rewrite is configured, the original request target is still sent to the backend.
|
|
|
|
Encoded separators (`%2f`, `%5c`), encoded `%`, dot segments and other ambiguous path forms are still rejected instead of being silently normalized.
|
|
|
|
## Actions
|
|
|
|
A location can either proxy to a backend or return a local response.
|
|
|
|
### Proxy
|
|
|
|
The location can use the vhost pool or pin traffic to one backend. A dedicated backend can be created from the location editor. Cache policy can inherit from the vhost or be explicitly enabled/disabled for the location.
|
|
|
|
Supported path transformations:
|
|
|
|
- **Preserve** — send the original client path unchanged.
|
|
- **Strip prefix** — remove the matched prefix before proxying.
|
|
- **Replace prefix** — replace the matched prefix with another normalized path prefix.
|
|
- **Regex rewrite** — available for regex locations; Rust regex captures can be referenced as `$1` or `${1}` in the replacement.
|
|
|
|
The query string is preserved. Rewrites change only the upstream path; cache identity remains based on the public client URL.
|
|
|
|
### Local response
|
|
|
|
`Return custom response` is the equivalent of a simple Nginx `return`: choose an HTTP status from 200 through 599, a Content-Type and a response body. RustProxy does not open a backend connection for this action. `HEAD`, `204` and `304` responses do not send a body.
|
|
|
|
For a redirect, use a 3xx status and add a `Location` response header in the visual header configurator.
|
|
|
|
## Request and response headers
|
|
|
|
Every location has a visual header configurator and an Advanced JSON view. Both edit the same data.
|
|
|
|
Supported operations are:
|
|
|
|
- `set` — replace the header with the configured value;
|
|
- `append` — append another header value;
|
|
- `remove` — remove the header.
|
|
|
|
Example JSON:
|
|
|
|
```json
|
|
{
|
|
"request": [
|
|
{"op": "set", "name": "X-App-Route", "value": "api"}
|
|
],
|
|
"response": [
|
|
{"op": "set", "name": "Cache-Control", "value": "no-store"},
|
|
{"op": "remove", "name": "X-Legacy-Header"}
|
|
]
|
|
}
|
|
```
|
|
|
|
Hop-by-hop/framing headers, forwarding identity headers, RustProxy request IDs and WebSocket handshake headers are protected and cannot be overwritten by custom rules. This prevents a location rule from changing transport framing or spoofing the verified client identity.
|
|
|
|
## Access control
|
|
|
|
A location can define its own IPv4/IPv6 CIDR ACL. The location ACL is additive: it cannot override a deny enforced by the host policy, reusable ACL profile or vhost ACL.
|
|
|
|
Authentication, vhost rate limits, country policy, security headers, compression, custom error pages and WebSocket policy still apply through the normal vhost pipeline.
|
|
|
|
## What is intentionally not an Nginx parser
|
|
|
|
Custom locations do **not** execute arbitrary Nginx directives or configuration snippets. RustProxy does not currently implement location-level `try_files`, filesystem aliases/roots, embedded scripting, arbitrary `if` expressions or arbitrary module directives. Use the explicit UI controls and the documented JSON schema instead; unknown fields are rejected on save.
|