57 KiB
RustProxy 0.25.0+ — Full Web Server / PHP-FPM Plan
Status: design and implementation TODO
Target: RustProxy 0.25.0 +
Baseline reviewed: RustProxy 0.24.2
1. Goal
RustProxy 0.25.0 should remain a reverse proxy exactly as it is today, while optionally becoming a full web server for a vhost:
- serve static files directly from disk;
- serve directory indexes;
- support HTTP validators and byte ranges;
- execute PHP through PHP-FPM / FastCGI;
- provide structured
try_filesand internal rewrite behavior; - support Nginx-style location matching already present in RustProxy;
- provide presets for common applications such as Drupal, WordPress, Laravel and Symfony;
- allow fully custom structured configuration;
- keep all current proxy, cache, ACL, authentication, TLS, HTTP/2, HTTP/3, WebSocket, header and security behavior intact for existing configurations.
The feature must be additive. A 0.24.2 configuration loaded by 0.25.0 must continue to behave as a reverse proxy without requiring edits and without silently changing routing semantics.
2. Non-negotiable compatibility rules
2.1 Do not reinterpret existing configuration
The meaning of the following existing fields must not change:
Vhost.backends;Vhost.routes;PathRoute.path_prefix;PathRoute.match_type;PathRoute.backend_id;PathRoute.cache;PathRoute.acl;PathRoute.headers;PathRoute.rewrite;PathRoute.response;- vhost/global ACLs;
- Basic Auth;
- Tinyauth;
- rate limits;
- security headers;
- response compression;
- transform configuration;
- cache configuration;
- listener selection;
- HTTP/1.1, HTTP/2 and HTTP/3 behavior;
- WebSocket behavior;
- backend balancing/health/affinity;
- custom pages;
- revision/CAS configuration publication.
In particular, the current PathRewrite remains an upstream proxy path rewrite. It must not be silently changed into an internal web-server rewrite.
2.2 Existing route precedence stays unchanged
Keep the existing location matching rules:
- exact;
- longest prefix;
prefix_priority/ Nginx^~skips regex evaluation;- first matching regex/regex-insensitive route in configuration order;
- longest ordinary prefix;
- vhost fallback.
Repeated literal slashes keep the existing normalized routing behavior. Existing rejection of ambiguous encoded separators, encoded %, dot segments, controls and malformed path forms must remain.
2.3 Existing vhosts remain proxy vhosts by default
If the new web configuration is absent or disabled:
- vhost validation remains equivalent to 0.24.2;
- a backend pool remains required;
- the main vhost backend remains the fallback;
- existing Custom Locations remain optional overrides;
- local
returnbehavior remains unchanged; - no local filesystem or FastCGI operation is performed.
2.4 No arbitrary Nginx configuration parser
Do not add a raw nginx.conf execution/parser path.
RustProxy should expose structured configuration that can represent the common Nginx behaviors needed for application hosting. Unknown fields remain rejected.
2.5 No hidden preset behavior
A preset generates ordinary RustProxy configuration. After generation, every field is editable. Runtime behavior must never depend on a hidden wordpress=true or drupal=true flag.
3. Baseline behavior in 0.24.2 that must be preserved
The current code already provides useful building blocks and they should be reused rather than replaced:
- vhost/frontend selection is tied to the accepted local listener address and TLS state;
- exact/wildcard hostname ownership is already separated from path matching;
- main backend fallback is separate from user Custom Locations;
- Custom Locations already support:
- prefix;
^~-style priority prefix;- exact match;
- case-sensitive regex;
- case-insensitive regex;
- existing proxy rewrites support:
- preserve;
- strip prefix;
- replace prefix;
- regex replacement with captures;
- route ACLs are additive to host/profile/vhost ACLs;
- global, vhost and route header rules already exist;
- a route can already generate a local response without opening an upstream connection;
- authentication and ACL decisions run before upstream I/O;
- the immutable compiled snapshot is published only after validated revisioned configuration writes;
- the response pipeline already centralizes security headers, server headers, diagnostics and compression.
0.25.0 should add local web origins to this architecture, not create a separate HTTP stack.
4. User-facing vhost model
Add a dedicated WWW / Web Server tab inside the existing vhost editor.
Recommended tab order:
Details
Backends
Health
Locations
WWW
Auth
SSL
Cache
Transform
Security
Pages
Advanced
Do not create separate top-level modules for Drupal, WordPress or PHP.
4.1 UI mode
The UI may display a derived mode:
Proxy;Web Server;Mixed.
Prefer deriving the label from actual configuration instead of making a new required runtime mode field.
Examples:
- no
webconfig -> Proxy; web.enabled=true, local web fallback, no proxy routes -> Web Server;web.enabled=trueplus proxy routes/backends -> Mixed.
4.2 WWW tab — main sections
Web root
- Enable Web Server;
- document root;
- fallback target;
- index files;
- autoindex;
- default MIME type;
- symlink policy;
- default static security policy;
- effective path preview.
Application preset
- Custom;
- Static website;
- SPA;
- Generic PHP front controller;
- WordPress;
- Drupal modern;
- Drupal legacy
q=routing; - Joomla;
- Laravel;
- Symfony;
- Nextcloud;
- phpMyAdmin.
The preset is a generator only.
PHP / FastCGI
- enable PHP;
- PHP-FPM profile;
- Unix socket or TCP endpoint;
- test connection;
- connect/read/write timeout;
- maximum connections;
- request body limit;
- default FastCGI params;
- custom FastCGI params;
- optional PATH_INFO behavior;
- effective
SCRIPT_FILENAMEpreview.
Static files
- index list;
- directory redirect;
- autoindex;
- validator behavior;
- Range support;
- dotfile policy;
- executable/source-file deny policy;
- optional per-location root/alias.
Routing / front controller
- structured
try_fileseditor; - internal URI fallback;
- named internal location fallback;
- internal rewrites;
- rewrite flow
last/break; - query-string behavior;
- internal redirect limit.
Advanced
- named internal locations;
- FastCGI params;
- MIME overrides;
- route-specific web handler configuration;
- conditional rules from an explicit safe allowlist;
- effective behavior preview.
5. Proposed persisted configuration
The exact Rust types can be adjusted during implementation, but the compatibility properties below should remain.
5.1 Add an optional vhost web section
Add an optional field to Vhost:
#[serde(default, skip_serializing_if = "Option::is_none")]
pub web: Option<WebServerSettings>,
When absent, behavior is exactly the legacy proxy behavior.
Suggested shape:
{
"web": {
"enabled": true,
"document_root": "/var/www/example/public",
"fallback": "web",
"indexes": ["index.php", "index.html"],
"autoindex": false,
"symlinks": "within_root",
"default_mime": "application/octet-stream",
"php_profiles": [],
"named_locations": []
}
}
Suggested fallback values:
proxy— retain the main backend pool as unmatched-path fallback;web— local web root is unmatched-path fallback;not_found— no origin fallback, use the existing 404/page path.
Rules:
- if
webis absent/disabled, fallback is implicitly legacyproxy; fallback=proxyrequires at least one proxy backend;fallback=webdoes not require an HTTP backend;fallback=not_founddoes not require an HTTP backend unless a proxy route references one.
5.2 Add optional local web handling to a PathRoute
Do not change the meaning of existing fields.
Add an optional field:
#[serde(default, skip_serializing_if = "Option::is_none")]
pub web: Option<WebRouteSettings>,
Action resolution for persisted routes:
response != null -> existing local Return action
web != null -> new local Web action
otherwise -> existing Proxy action
Validation must reject ambiguous combinations.
For a web route:
responsemust be null;backend_idmust be null unless a future explicit proxy web action is added;- existing
PathRewritemust remainpreserve; internal web rewrite uses a new field/type; - proxy cache override should initially be rejected/unused for local static/FastCGI routes rather than silently changing meaning;
- route ACL and header rules remain valid and should apply.
This allows the existing location matcher to be reused for static/PHP routes without creating a second public URL matcher.
5.3 Do not repurpose existing PathRewrite
Add a separate web rewrite model, for example:
{
"web": {
"handler": "static",
"rewrites": [
{
"pattern": "^/(.*)$",
"replacement": "/index.php",
"query": "q=$1",
"flow": "last"
}
]
}
}
The existing proxy rewrite field continues to modify only the upstream proxy target.
5.4 Structured try_files
Prefer a structured model over accepting an arbitrary Nginx directive string.
Example:
{
"try_files": [
{"kind": "file", "value": "$uri"},
{"kind": "directory", "value": "$uri"},
{"kind": "named", "value": "drupal"}
]
}
Other supported terminal candidates:
{"kind": "uri", "value": "/index.php", "query": "$args"}
{"kind": "status", "value": 404}
The UI can render a familiar preview:
try_files $uri $uri/ @drupal;
without storing or executing raw Nginx syntax.
5.5 Named locations
Named locations are internal-only and should not become public URL patterns.
Suggested shape:
{
"named_locations": [
{
"id": "drupal",
"action": {
"type": "internal_redirect",
"uri": "/index.php",
"query": "q=$uri"
}
}
]
}
Rules:
- IDs use the existing safe ID rules where possible;
- named locations cannot be requested directly by a client;
- only
try_files/ internal rewrite may enter them; - loops are bounded;
- their configuration is compiled into the immutable snapshot.
6. Necessary internal routing change
A pure Web Server vhost cannot require a fake HTTP backend.
0.24.2 currently requires 1..32 backends and the compiled main backend fallback is also used to establish route ownership. 0.25.0 therefore needs a small internal routing refactor, but it must be behavior-preserving for all old configurations.
6.1 Regression-gated refactor
Introduce an internal compiled action/target concept, for example:
enum CompiledRouteAction {
Proxy(CompiledProxyAction),
Return(LocationResponse),
Static(CompiledStaticAction),
FastCgi(CompiledFastCgiAction),
}
or an equivalent representation.
This is an internal model only. It does not require rewriting old persisted JSON.
Compile old configurations exactly as follows:
PathRoute.response = Some -> Return
PathRoute.response = None and PathRoute.web = None -> Proxy
legacy vhost fallback -> Proxy
New configurations may additionally compile to Static/FastCGI/local web fallback.
6.2 Host ownership must not depend on having a proxy fallback
Frontend hostname/listener ownership already exists separately and must remain authoritative.
For an enabled vhost:
claimed frontend
-> existing custom location selection
-> configured fallback target (proxy/web/not_found)
Do not continue to a broader wildcard merely because a path did not match, preserving the existing claimed-vhost behavior.
6.3 Backend validation becomes conditional
Legacy proxy vhost:
web absent/disabled -> require 1..32 backends exactly as today
Web vhost:
0..32 backends allowed
but validation must require a backend if any configured route or fallback uses Proxy.
No HTTP backend should be required for a pure static/PHP vhost.
6.4 Legacy root normalization
PathRoute::is_legacy_main_fallback() must treat any new web action/configuration as a deliberate customized / route.
A new web route must never be removed as the old synthetic root fallback.
7. Request pipeline
The existing outer request/response pipeline is valuable and should be retained.
Desired high-level order:
accepted connection
-> current listener/TLS/frontend selection
-> current host/path normalization
-> current redirect/local-host handling
-> current host/profile/vhost ACL
-> current rate limits
-> current Basic Auth / Tinyauth
-> current location selection
-> current location ACL
-> action dispatch:
Return -> existing local return
Static -> new static handler
FastCGI -> new FastCGI handler
Proxy -> existing proxy path unchanged
-> current error-page processing
-> current global/vhost/location response header rules
-> current security headers/server headers/diagnostics
-> current compression where safe
-> H1/H2/H3 response body
7.1 Critical rule
Do not fork a second HTTP server pipeline for local web content.
Static and FastCGI responses must flow through the same outer policies as proxy responses wherever those policies make sense.
7.2 Local web response marker
Do not mark normal local website files with the existing behavior that forces placeholder/default pages to no-store and strips validators.
Add a distinct response extension/marker for local web-origin responses if needed so that:
- proxy-cache diagnostics are not incorrectly added;
ETagandLast-Modifiedremain intact;- application
Cache-Controlremains intact; - global/vhost/location response headers still apply;
- security headers still apply;
- compression may still apply when safe;
- custom error pages may still replace error responses.
8. Static file server
Create a dedicated module instead of growing proxy/mod.rs further.
Suggested files:
src/web/mod.rs
src/web/static_files.rs
src/web/path.rs
src/web/rewrite.rs
src/web/fastcgi.rs
src/web/fastcgi_protocol.rs
src/web/presets.rs # only if presets are also generated server-side
8.1 Required static features
- GET;
- HEAD;
- 405 for unsupported methods when the route is a pure static file handler;
Allow: GET, HEADwhere appropriate;- document root;
- per-location root override;
- alias support;
- directory detection;
- trailing-slash directory redirect;
- index resolution;
- MIME type detection;
- configurable MIME overrides;
- default
application/octet-stream; Content-Length;Last-Modified;ETag;If-None-Match;If-Modified-Since;304 Not Modified;- byte ranges;
206 Partial Content;416 Range Not Satisfiable;Accept-Ranges: bytes;If-Range;- streaming file bodies;
- no whole-file buffering;
- directory autoindex optional and OFF by default;
- correct HEAD metadata with no body;
- correct behavior under HTTP/1.1, HTTP/2 and HTTP/3.
8.2 Validators
Recommended ETag strategy for 0.25.0:
- metadata-based validator using stable file metadata such as size + modification time;
- do not hash the complete file on every request;
- document whether the tag is weak or strong;
- obey HTTP conditional precedence correctly (
If-None-Matchbefore date validators).
8.3 Ranges
P0:
- one satisfiable byte range;
- suffix ranges;
- open-ended ranges;
- correct 416 with
Content-Range: bytes */size; If-Range.
For syntactically valid multi-range requests, either implement multipart ranges or safely ignore the Range and return a complete 200. Do not generate malformed multipart responses.
8.4 Index handling
Example:
index index.php index.html;
If a directory resolves to index.php, never serve PHP source as a static file.
The index URI must enter the internal web dispatch path so the PHP/FastCGI handler is selected.
8.5 Autoindex
- default OFF;
- HTML escape names;
- URL encode links;
- never expose filesystem paths outside the configured root;
- do not show denied dotfiles;
- do not follow a symlink that violates the root policy;
- HEAD support;
- bounded directory entry count or streamed/bounded generation to avoid memory abuse.
9. Filesystem security
This is a release blocker for 0.25.0.
9.1 Reuse current path validation
Reuse the existing normalized routing path as the basis for local URL mapping.
Do not add a second decoder that could allow double decoding.
Continue rejecting:
- encoded
/; - encoded
\\; - encoded
%; - dot segments;
- malformed percent escapes;
- control characters;
- ambiguous separators;
- malformed UTF-8.
9.2 Root escape prevention
A requested path must never escape its configured document root/alias through:
..;- percent encoding;
- symlinks;
- rename races where feasible to prevent;
- platform separator differences.
Prefer a capability/open-beneath style implementation rather than simple string-prefix checks.
Cross-platform correctness for Linux/BSD is more important than Linux-only sendfile optimization.
9.3 Symlink policy
Suggested explicit values:
deny;within_root— recommended default;allow— advanced opt-in with clear warning.
Never make allow the default.
9.4 Sensitive files
Provide a secure default/preset policy for common sensitive paths:
.git;.svn;.hg;.env;.htaccess;.htpasswd;- editor/backup files where configured;
- application-specific config files from presets.
Do not over-block arbitrary dotfiles if the administrator explicitly opts out, but presets should be secure by default.
9.5 PHP/source disclosure prevention
PHP-like executable source extensions must not silently fall back to static serving when:
- PHP-FPM is down;
- the PHP route is invalid;
- FastCGI times out;
- the FastCGI connection fails.
Return an error (502/504 as appropriate). Never expose source code as a fallback.
Protect at least common PHP script extensions used by the configured policy (.php, and optional configured extensions such as .phtml/.phar).
10. Internal web routing
10.1 try_files
Required behavior:
try_files $uri $uri/ @drupal
and:
try_files $uri $uri/ /index.php?$args
Candidate checks should be performed relative to the effective route root/alias.
No candidate may escape the allowed filesystem root.
10.2 Internal redirect
An internal redirect may change URI/query and run web route selection again.
Required safeguards:
- hard maximum redirect/rewrite depth, e.g. 10;
- loop detection/diagnostics;
- no client-visible redirect unless explicitly configured as a 3xx response;
- re-evaluate the effective location after
last; - preserve or replace query according to explicit configuration;
- internal redirect target must pass the same path validator.
10.3 last and break
Implement explicit structured behavior:
last— update internal URI and reselect location;break— stop rewrite evaluation and continue the current location handler with the rewritten internal path.
Do not reuse the existing proxy rewrite enum for this purpose.
10.4 Safe variables
Initial variable allowlist should include only values with clear semantics:
$uri— normalized internal URI path;$request_uri— original path/query where safe for value expansion, never for filesystem joining directly;$args;$host;$scheme;$request_method;- regex captures
$1..$9for the current web rewrite rule; $document_rootfor FastCGI parameter expansion;$request_filenameas a derived safe path representation for conditions, not as an unchecked arbitrary path.
No arbitrary environment variable expansion from public requests.
10.5 Safe conditional rules
Do not implement general Nginx if scripting.
Support structured conditions needed by normal web hosting:
- file exists;
- file does not exist;
- regular file exists;
- directory exists;
- URI regex;
- request method;
- hostname if genuinely needed.
Example equivalent of:
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?q=$1 last;
}
should be representable as an explicit condition + internal rewrite, not raw script text.
11. FastCGI / PHP-FPM
Implement FastCGI as a local web origin, not as an HTTP proxy backend.
11.1 Endpoints
Support:
- Unix socket:
/run/php/php8.4-fpm.sock
- TCP:
127.0.0.1:9000
Optionally allow remote TCP FastCGI only through explicit configured endpoints. Never derive the endpoint from request data.
11.2 FastCGI protocol
Implement/test the required FastCGI responder flow:
FCGI_BEGIN_REQUEST;- role
FCGI_RESPONDER; FCGI_PARAMS;FCGI_STDIN;FCGI_STDOUT;FCGI_STDERR;FCGI_END_REQUEST;- FastCGI name/value length encoding;
- record splitting for values/bodies larger than one record;
- bounded stderr capture/logging;
- protocol error handling;
- request IDs;
- connection close/reuse state.
11.3 Connection model
- async I/O;
- bounded number of FastCGI connections per profile;
- queue timeout;
- connect timeout;
- read timeout;
- write/body idle timeout;
- backpressure;
- cancellation on downstream disconnect;
- no unlimited buffers;
- do not assume FastCGI multiplexing support;
- reuse a connection only after a clean
END_REQUESTand when configured/safe.
PHP-FPM compatibility is the primary target.
11.4 Request body
- stream POST/PUT/PATCH bodies to
FCGI_STDIN; - do not buffer normal uploads completely in memory;
- enforce a configurable maximum request size for web/PHP routes;
- handle missing/invalid Content-Length safely;
- preserve streaming behavior for HTTP/2 and HTTP/3;
- abort the FastCGI request/connection safely when the client disconnects.
11.5 CGI/FastCGI response parsing
Parse CGI-style response headers from FCGI_STDOUT:
Status;Content-Type;Content-Lengthif valid;Location;- repeated
Set-Cookie; - arbitrary safe end-to-end headers.
Then:
- remove/reject hop-by-hop/framing headers that an application must not control;
- do not trust an application-supplied transfer framing header;
- pass the body as a streaming HTTP response;
- map malformed FastCGI output to
502; - map connect failure to
502; - map timeout to
504; - map unavailable/capacity state consistently with RustProxy conventions.
11.6 PHP-FPM profiles
Suggested profile:
{
"id": "php-default",
"endpoint": {
"type": "unix",
"path": "/run/php/php8.4-fpm.sock"
},
"connect_timeout_ms": 1000,
"response_timeout_seconds": 120,
"write_timeout_seconds": 60,
"max_connections": 32,
"queue_timeout_ms": 5000,
"keep_conn": true,
"max_request_body_bytes": 134217728,
"params": {}
}
Limits are examples and must be validated against existing RustProxy resource conventions before final defaults are chosen.
12. FastCGI parameters
Provide a safe built-in default equivalent to the useful part of common fastcgi_params / fastcgi.conf setups.
Required parameters:
GATEWAY_INTERFACE;SERVER_SOFTWARE;QUERY_STRING;REQUEST_METHOD;CONTENT_TYPE;CONTENT_LENGTH;SCRIPT_FILENAME;SCRIPT_NAME;REQUEST_URI;DOCUMENT_URI;DOCUMENT_ROOT;SERVER_PROTOCOL;REQUEST_SCHEME;HTTPS;REMOTE_ADDR;REMOTE_PORT;SERVER_ADDR;SERVER_PORT;SERVER_NAME.
Also expose incoming request headers as safe CGI HTTP_* parameters after normal RustProxy header validation/sanitization.
12.1 Trust boundary
REMOTE_ADDR must come from RustProxy's already validated effective client identity, not directly from an untrusted forwarding header.
SERVER_ADDR / SERVER_PORT must come from the accepted local frontend.
SERVER_NAME comes from the normalized claimed vhost/host.
12.2 SCRIPT_FILENAME
Default PHP mapping:
$document_root$fastcgi_script_name
but calculate it structurally rather than concatenating unchecked request text.
Before opening FastCGI:
- resolve against the permitted document root;
- require an existing regular file unless explicitly configured otherwise;
- enforce symlink/root policy;
- reject traversal/ambiguous paths;
- never pass an arbitrary filesystem path supplied by a client.
12.3 Custom params
Allow per-profile and per-route overrides.
Precedence suggestion:
built-in defaults
-> PHP profile params
-> route params
Protect parameters that define RustProxy's trust boundary from unsafe browser-controlled replacement where needed.
12.4 PATH_INFO
Default OFF/safe.
Provide an explicit structured option for applications that require PATH_INFO, similar in purpose to fastcgi_split_path_info, with tests for script/path confusion.
Never enable permissive PHP path guessing by default.
Document a secure PHP-FPM/PHP recommendation such as disabling unsafe path fixing where appropriate.
13. Mapping Nginx concepts to RustProxy
| Nginx concept | RustProxy 0.25 design |
|---|---|
server_name |
existing vhost frontend.hosts |
listen |
existing named listeners |
location /x |
existing PathMatch::Prefix |
location ^~ /x |
existing PathMatch::PrefixPriority |
location = /x |
existing PathMatch::Exact |
location ~ regex |
existing PathMatch::Regex |
location ~* regex |
existing PathMatch::RegexInsensitive |
root |
vhost web root / route root override |
alias |
route web alias |
index |
vhost/route web indexes |
try_files |
structured web try_files |
rewrite ... last |
new internal web rewrite + location reselection |
rewrite ... break |
new internal web rewrite without reselection |
if (-e ...) |
structured file condition |
if (!-e ...) |
structured not-exists condition |
fastcgi_pass |
PHP/FastCGI profile endpoint |
fastcgi_param |
FastCGI profile/route params |
add_header |
existing response header rules |
return |
existing LocationResponse |
Cache-Control |
existing response header rules / preset helper |
Vary |
existing response header rules plus compression-owned values |
status_zone |
RustProxy metrics keyed by bounded vhost/route IDs, not arbitrary dynamic zones |
Do not duplicate existing header/ACL/return functionality inside the new WWW subsystem.
14. Drupal examples
14.1 Simple Drupal/front-controller behavior
Nginx-style intent:
location / {
try_files $uri $uri/ @drupal;
index index.php index.html;
}
location @drupal {
rewrite ^/(.*)$ /index.php?q=$1 last;
}
RustProxy should represent this structurally as:
Web root: /var/www/drupal
Indexes: index.php, index.html
Fallback static handler:
try file $uri
try directory $uri
otherwise -> @drupal
Named location @drupal:
internal URI -> /index.php
query -> q=<original normalized URI/capture>
reselect location
Regex location \.php$:
FastCGI -> php-default
script must exist under document root
14.2 Advanced imagecache behavior
Nginx-style intent:
location ^~ /files/imagecache/ {
add_header Cache-Control "public, max-age=604800";
if_modified_since exact;
index index.php;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?q=$1 last;
break;
}
add_header Vary Accept-Encoding;
}
RustProxy representation:
Location match:
type: prefix_priority
path: /files/imagecache/
Action:
local web/static
Response headers:
existing HeaderRules:
Cache-Control = public, max-age=604800
Vary += Accept-Encoding (with normal de-duplication/compression rules)
Index:
index.php
Condition:
if requested file does not exist
Internal rewrite:
regex: ^/(.*)$
target: /index.php
query: q=$1
flow: last
The existing proxy PathRewrite is not used for this internal rewrite.
15. WordPress preset
Generate ordinary configuration equivalent in intent to:
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_pass ...;
}
Preset requirements:
- administrator selects WordPress root;
- default indexes include
index.php,index.html; - local static fallback;
- front-controller fallback to
/index.phppreserving query args; - PHP regex route;
- PHP script existence check;
- block
.ht*; - block common secret/backup files;
- never serve PHP source statically;
- allow normal
/wp-contentstatic files; - no hidden WordPress runtime flag.
16. Drupal presets
Provide at least two clear choices:
Drupal modern
- normal static file checks;
- front controller
/index.php; - preserve normal query string;
- secure PHP route;
- common private file restrictions appropriate to the chosen document root.
Drupal legacy q=
- normal static file checks;
- front controller
/index.php?q=<path>; - preserve/append original query according to explicit generated config;
- secure PHP route.
Do not guess the site's Drupal generation silently. The selected preset should be visible before applying.
17. Laravel / Symfony presets
Laravel
- document root must point to
public/; - static file/directory check;
/index.phpfront controller;- PHP-FPM;
- deny direct access outside the public root by construction.
Symfony
- document root
public/; - static file check;
/index.phpfront controller;- PHP-FPM;
- secure source-file behavior.
The UI should warn if the administrator selects a known project root while the expected public directory exists beneath it, but never silently rewrite an administrator path without showing the result.
18. Static / SPA presets
Static website
- web fallback static;
- indexes
index.html; - no PHP;
- autoindex off;
- validators/ranges enabled;
- secure dotfile policy.
SPA
Equivalent intent:
try file $uri
otherwise internal fallback /index.html
API/static prefixes can still use existing Custom Locations or explicit web locations.
19. Nextcloud/phpMyAdmin and advanced presets
Treat these as presets, not special server code.
They may need:
- additional blocked paths;
- PATH_INFO handling;
- well-known redirects/rewrites;
- larger upload limits;
- application-specific headers.
Before shipping a preset, add fixture tests that verify the generated structured configuration. Do not ship a preset based only on an approximate Nginx snippet.
20. MIME handling
Add a maintained built-in MIME map for common web types:
- HTML;
- CSS;
- JavaScript;
- JSON;
- XML;
- SVG;
- images;
- fonts;
- audio/video;
- WASM;
- PDF;
- archives;
- text.
Rules:
- match file extension case-insensitively where appropriate;
- administrator may override/add mappings;
- unknown type ->
application/octet-stream; - never infer executable behavior from MIME type;
- PHP execution is determined only by an explicit FastCGI route/handler.
21. Cache and compression behavior
21.1 Browser cache
Use normal HTTP headers for local static content:
Cache-Control;Expiresif configured;ETag;Last-Modified;Varywhere required.
Existing route/vhost response header rules should remain the main mechanism for custom cache headers.
21.2 RustProxy object cache
For 0.25.0 P0, do not require local static files to pass through the proxy object cache. The disk file is already the local origin and the OS page cache provides the primary file cache.
Likewise, do not silently apply the existing proxy cache semantics to FastCGI unless a dedicated design is added and tested.
A future FastCGI cache can be added explicitly.
21.3 Compression
Reuse the existing response compression layer when safe.
Rules:
- do not compress a byte-range response incorrectly;
- preserve validator semantics;
- make
Vary: Accept-Encodingcorrect; - do not double-compress a FastCGI response that already has Content-Encoding;
- honor existing no-transform/private compression rules where applicable;
- HEAD remains bodyless.
Optional precompressed .br/.gz static file selection can be deferred unless implemented with complete validator/Vary tests.
22. Headers
Reuse existing HeaderRules.
Do not create another web-only header engine.
For a local web route:
- response header rules apply to static/FastCGI responses;
- request header rules should apply before FastCGI
HTTP_*parameter generation; - protected forwarding/framing headers remain protected;
- canonical client identity remains RustProxy-owned;
- FastCGI output cannot override hop-by-hop transport framing.
23. Authentication / ACL / rate limits
Local web content must not bypass current gates.
The following must continue to run before filesystem content/FastCGI application data is returned:
- host ACL;
- reusable ACL profile;
- vhost ACL;
- route ACL;
- country policy;
- vhost rate limits;
- Basic Auth;
- Tinyauth.
Do not create a direct static-file shortcut before authentication.
Authenticated responses retain current privacy protections.
24. Error handling
Reuse existing custom error pages where possible.
Expected mapping:
- missing static file -> 404;
- denied path/file policy -> 403/404 according to chosen security policy;
- unsupported static method -> 405;
- invalid Range -> 416;
- FastCGI connect/protocol failure -> 502;
- FastCGI timeout -> 504;
- FastCGI capacity/queue exhaustion -> 503;
- internal rewrite loop -> 500 with bounded diagnostic log;
- invalid internal target -> 400/500 depending on whether it originated from public input or invalid administrator configuration.
Do not leak absolute filesystem paths, socket paths or PHP-FPM stderr to public clients.
Operational logs may expose sanitized administrator-useful detail.
25. Observability
Add bounded metrics/log fields without high-cardinality public values.
25.1 Request origin/action
Expose a bounded action category:
proxy;return;static;fastcgi.
25.2 Static metrics
Suggested counters:
- static requests;
- static bytes served;
- 304 count;
- range responses;
- not found;
- denied path;
- index resolutions;
- internal redirects/rewrite loop failures.
25.3 FastCGI metrics
Suggested counters/gauges:
- requests;
- active connections;
- queued requests;
- connect errors;
- protocol errors;
- timeouts;
- response latency;
- bytes in/out.
Use bounded profile/route IDs from configuration as labels. Never use arbitrary URI, script filename or query string as a Prometheus label.
25.4 Live logs
Add useful bounded fields:
- route ID;
- action type;
- FastCGI profile ID;
- status;
- duration;
- optional relative script path, sanitized/truncated;
- internal rewrite count.
Do not log FastCGI secrets or full POST bodies.
26. Admin UI details
26.1 Main WWW card
Fields:
[ ] Enable web server
Document root: [/var/www/example/public]
Unmatched requests: [Serve from web root | Proxy | 404]
Index files: [index.php] [index.html]
Autoindex: [off]
Symlinks: [within root]
Preset: [Custom v]
Show a warning if the root is not accessible by the RustProxy service user.
26.2 PHP card
[ ] Enable PHP/FastCGI
Profile: php-default
Endpoint type: Unix socket / TCP
Socket: /run/php/php8.4-fpm.sock
or host:port: 127.0.0.1:9000
[Test connection]
Then Advanced:
- timeouts;
- max connections;
- queue timeout;
- request body limit;
- custom FastCGI params;
- PATH_INFO.
26.3 Front controller builder
Provide common choices:
Existing file -> serve it
Existing directory -> serve/index it
Otherwise -> /index.php
Query handling -> preserve
Advanced representation may show:
try_files $uri $uri/ /index.php?$args
but the saved model remains structured.
26.4 Web locations
Do not hide that URL matching is the same RustProxy location system.
A location card can show action:
- Proxy;
- Return;
- Static files;
- PHP/FastCGI.
The existing Locations tab remains the complete routing view. The WWW tab provides web-server-oriented defaults, presets and helpers.
Avoid maintaining two independent location lists.
26.5 Effective behavior preview
Extend the current location preview with:
- action: Static / FastCGI;
- effective document root/alias;
- index list;
- try_files chain;
- selected PHP profile;
- internal rewrite summary;
- script filename template;
- ACL/header composition.
27. API / OpenAPI
Update:
- vhost schema;
- route schema;
- WebServerSettings;
- WebRouteSettings;
- FastCGI profile schemas;
- try_files candidates;
- internal rewrite/condition schemas;
- named location schemas;
- status/diagnostic schemas if new metrics are returned.
Keep:
- authenticated admin API rules;
- CSRF/revision CAS behavior;
deny_unknown_fieldssemantics;- current
/configurationcompatibility behavior; - no new anonymous admin endpoint.
A connection test endpoint for FastCGI, if added, must be authenticated and bounded and must not permit an arbitrary user-supplied network destination outside the validated draft/config context.
28. Configuration validation
Validation must happen before publishing a snapshot.
Validate at least:
- document root is absolute;
- configured path length/control characters;
- alias/root compatibility;
- index filenames contain no separators/traversal;
- MIME override names/values;
- FastCGI endpoint syntax;
- Unix socket path syntax;
- timeout ranges;
- connection/queue limits;
- request body limit;
- unique PHP profile IDs;
- unique named location IDs;
- named fallback references exist;
- rewrite regex compiles within bounded regex limits;
- internal rewrite replacement length;
- try_files item count;
- rewrite/redirect depth configured within hard server maximum;
- web route and local response are mutually exclusive;
- web route and legacy proxy-only settings do not conflict;
- proxy route requires a backend pool;
fallback=proxyrequires a backend pool;- pure web vhost may have zero backends;
- PHP handler references an existing FastCGI profile;
- PHP source cannot accidentally be configured as generic static fallback without an explicit dangerous override, preferably disallow entirely.
Filesystem existence checks may be shown as UI/runtime diagnostics, but decide carefully whether a temporarily missing mount should invalidate the persisted configuration. Prefer safe runtime 503/404 diagnostics over preventing startup solely because a removable/mounted document root is momentarily absent, unless security depends on canonicalization.
29. Snapshot/runtime model
All web configuration must compile into the same immutable snapshot philosophy as the rest of RustProxy.
Request path must not query SQLite.
Compile/store:
- normalized root/alias configuration;
- compiled regexes;
- validated FastCGI endpoints;
- parsed header/param templates;
- named location lookup maps;
- MIME map overlays;
- bounded limits;
- route action enum/representation.
Keep dynamic state outside desired config:
- FastCGI connection pool state;
- FastCGI counters;
- observed socket availability;
- filesystem metadata/cache observations if any are added.
Do not persist live FastCGI connection state.
30. FastCGI profile lifecycle
On config publication:
- reuse compatible runtime pool state when profile identity and endpoint/security parameters are unchanged, if practical;
- otherwise retire the old pool gracefully;
- existing in-flight requests hold their runtime references until completion;
- new requests use the new snapshot/profile;
- no request replay to another PHP-FPM endpoint after partial body transmission.
This should follow the existing backend lease/publication philosophy.
31. System/service integration
RustProxy remains non-root.
Documentation must explain:
Static roots
The RustProxy service user needs read/search permission on the configured document tree.
RustProxy must not automatically chmod, chown or upload site content in 0.25.0.
PHP-FPM Unix socket
The service user needs permission to connect to the PHP-FPM socket.
Document typical approaches:
- configure PHP-FPM socket owner/group/mode;
- add RustProxy service user to the appropriate group where operationally acceptable.
Do not automatically alter PHP-FPM configuration.
MAC policies
Mention SELinux/AppArmor/system policy considerations where relevant, but do not weaken them automatically.
32. Preset generation rules
Presets must:
- modify only the current vhost draft;
- show what will change before/after apply;
- preserve hostname/listener/TLS/auth settings unless a preset explicitly needs a web field;
- never delete backends silently;
- never silently remove custom routes;
- warn about route conflicts;
- create deterministic route IDs;
- produce valid ordinary configuration;
- be editable immediately after generation;
- pass the same validator as handwritten configuration.
If the vhost already has routes, offer a clear conflict strategy in the UI rather than overwriting them automatically.
33. Example proposed configuration — pure WordPress
Illustrative only; final schema names may differ.
{
"id": "wordpress",
"enabled": true,
"frontend": {
"hosts": ["www.example.com"],
"listener_ids": ["https"]
},
"backends": [],
"web": {
"enabled": true,
"document_root": "/srv/www/wordpress",
"fallback": "web",
"indexes": ["index.php", "index.html"],
"autoindex": false,
"symlinks": "within_root",
"default_mime": "application/octet-stream",
"php_profiles": [
{
"id": "php-default",
"endpoint": {
"type": "unix",
"path": "/run/php/php8.4-fpm.sock"
}
}
]
},
"routes": [
{
"id": "php",
"path_prefix": "\\.php$",
"match_type": "regex",
"enabled": true,
"web": {
"handler": "fastcgi",
"fastcgi_profile": "php-default",
"require_script_file": true
}
},
{
"id": "root-web",
"path_prefix": "/",
"match_type": "prefix",
"enabled": true,
"web": {
"handler": "static",
"try_files": [
{"kind": "file", "value": "$uri"},
{"kind": "directory", "value": "$uri"},
{"kind": "uri", "value": "/index.php", "query": "$args"}
]
}
}
]
}
A final implementation may use the vhost web fallback for the root static action instead of persisting a synthetic / route. Whichever representation is chosen, do not reintroduce the old ambiguity between the vhost fallback and a user Custom Location.
34. Example proposed configuration — mixed static/PHP/proxy
Use case:
- website served locally;
/api/proxied to an application backend;.phpsent to PHP-FPM.
Conceptually:
/api/ -> existing Proxy action
*.php -> new FastCGI action
all else -> local Static web fallback
The /api/ proxy must use the same existing backend selection, health, retry/capacity, WebSocket and cache rules as 0.24.2.
Turning on WWW must not route /api/ through FastCGI or filesystem code when the existing Custom Location selected Proxy.
35. Source-file change map
Expected areas. Keep changes focused.
src/vhost.rs
- optional
webvhost settings; - optional route web settings;
- validation;
- conditional backend requirement;
- legacy synthetic-root normalization updated to recognize deliberate web route configuration.
src/config.rs
- compile web settings;
- compile route actions;
- compile local web fallback;
- keep existing match precedence;
- validate cross references;
- preserve claimed-host behavior.
src/proxy/mod.rs
Keep existing proxy branch as intact as practical.
Changes should mainly be:
- dispatch selected compiled action;
- call the new web module for Static/FastCGI;
- preserve common ACL/auth/response pipeline;
- distinguish local web responses from placeholder/error local responses;
- expose final/effective route to response policy if internal rewrites can select another route.
Do not implement filesystem/FastCGI protocol details directly in this large module.
src/web/*
New implementation modules for:
- secure path resolution;
- static files;
- conditions;
- try_files;
- internal rewrites;
- FastCGI protocol/client;
- MIME handling.
src/admin/web/vhosts.js
- WWW tab;
- web settings editor;
- PHP profile editor;
- preset generator;
- web route actions;
- effective behavior preview;
- validation messages.
src/admin/openapi.json
- schema additions only; preserve existing paths/contracts where possible.
langs/en_US.json, langs/pl_pl.json
- all new UI text goes through discovered language packs;
- no hardcoded PL/EN switch.
Documentation
Add at least:
docs/WEB_SERVER.md
docs/STATIC_FILES.md
docs/FASTCGI.md
docs/WEB_REWRITES.md
docs/WEB_PRESETS.md
Update:
README.md
ROADMAP.md
CHANGELOG.md
docs/VHOSTS.md
docs/CUSTOM_LOCATIONS.md
docs/API.md
docs/SECURITY.md
docs/TEST_REPORT.md
36. Tests — existing behavior regression gate
Before considering new WWW functionality accepted, prove old behavior is unchanged.
Keep/add tests for:
- exact route precedence;
^~priority prefix;- regex order;
- longest prefix;
- custom route -> main backend fallback;
- claimed exact host does not fall through to broader wildcard;
- old synthetic root normalization;
- deliberate customized
/remains a real route; - existing preserve/strip/replace/regex proxy rewrite behavior;
- existing query preservation;
- local
return; - backend pinning;
- balancing;
- ACL composition;
- Basic Auth;
- Tinyauth;
- cache behavior;
- header rules;
- security headers;
- compression;
- WebSockets;
- H1/H2/H3.
Add fixture tests that deserialize representative 0.24.2 JSON and verify effective compiled behavior under 0.25.0.
37. Tests — static files
Required tests:
- GET existing file;
- HEAD existing file;
- missing file 404;
- directory trailing slash redirect;
- directory index HTML;
- directory index PHP enters FastCGI rather than static source;
- autoindex disabled;
- autoindex enabled;
- MIME known extension;
- MIME unknown extension;
- Content-Length;
- Last-Modified;
- ETag;
- If-None-Match 304;
- If-Modified-Since 304;
- validator precedence;
- Range start/end;
- suffix Range;
- open-ended Range;
- invalid/unsatisfiable Range 416;
- If-Range match/miss;
- HEAD + Range semantics;
- large file streaming;
- client disconnect;
- compression with static file;
- range not incorrectly compressed;
- custom response headers;
- custom error pages;
- H1/H2/H3.
38. Tests — filesystem security
Include explicit attacks:
/../secret
/%2e%2e/secret
/%2fetc/passwd
/%5c..%5csecret
/%252e%252e/secret
//..//secret
/a;b
malformed % escape
invalid UTF-8 escape
symlink -> outside root
symlink chain -> outside root
alias boundary confusion
root prefix string collision (/srv/www vs /srv/www2)
Also test races/behavior to the extent the selected safe filesystem API allows.
PHP source must remain undisclosed under every failure case.
39. Tests — try_files and rewrites
Required:
$uriexisting file;$uri/existing directory;- fallback URI;
- named location;
- status fallback
=404equivalent; - query preserve;
- query replace;
- query append if supported;
- regex captures;
lastreselects location;breakremains in location;- maximum internal redirects;
- direct loop A -> A;
- loop A -> B -> A;
- rewritten path still passes ambiguity/path validation;
- condition file exists/not exists;
- condition directory exists;
- route ACL remains enforced after internal reselection.
40. Tests — FastCGI
Build a deterministic fake FastCGI peer for automated tests. Real PHP-FPM remains a release-host integration gate.
Test:
- Unix socket connect;
- TCP connect;
- BEGIN/PARAMS/STDIN protocol framing;
- long FastCGI param length encoding;
- record splitting;
- GET;
- HEAD;
- POST body streaming;
- large upload;
- chunked/H2/H3 request body adaptation;
- standard PHP-like response;
Statusheader;- repeated
Set-Cookie; Location;- stderr handling;
- END_REQUEST;
- malformed response headers;
- premature EOF;
- protocol status failure;
- connect refused;
- connect timeout;
- response timeout;
- queue capacity exhaustion;
- clean connection reuse;
- broken connection not reused;
- downstream cancellation;
- protected hop-by-hop headers stripped;
SCRIPT_FILENAMEcorrect;- missing script rejected before FastCGI;
- script symlink outside root rejected;
REMOTE_ADDRuses trusted effective identity;- FastCGI custom params precedence;
- PATH_INFO disabled default;
- PATH_INFO explicit mode.
41. Tests — presets/UI
For every shipped preset:
- generated JSON/schema validates;
- deterministic output;
- expected web root/fallback;
- expected routes;
- PHP handler where needed;
- safe blocked paths;
- no hidden runtime preset flag;
- applying a preset does not silently delete unrelated hostname/TLS/auth settings;
- conflict warning for existing routes;
- Custom mode round-trips generated values;
- Advanced JSON and visual editor edit the same model;
- EN/PL language packs contain every new key;
scripts/check_source.pylanguage key checks pass;- JS syntax checks pass.
42. Release-host integration tests
Before production-ready status, test with real services:
PHP-FPM
- supported distro PHP-FPM over Unix socket;
- TCP PHP-FPM;
- upload through PHP;
- slow PHP timeout;
- FPM restart while RustProxy remains running;
- socket disappears/reappears;
- connection pool recovery.
Applications
At minimum:
- WordPress install/front page/admin login/static assets/permalinks;
- Drupal front page/static assets/front-controller routing;
- Laravel or Symfony front controller;
- SPA fallback.
Transports
Run application requests over:
- HTTP/1.1;
- HTTP/2;
- HTTP/3.
No separate local-web implementation per transport.
43. Performance/resource requirements
- no whole-file static buffering;
- no whole-request PHP upload buffering;
- bounded FastCGI connections;
- bounded FastCGI queue;
- bounded stderr capture;
- bounded rewrite depth;
- bounded try_files count;
- bounded index list;
- bounded named locations;
- bounded custom params;
- bounded autoindex generation;
- no request-path SQLite access;
- no request-path external configuration/provider calls;
- cancellation-aware I/O;
- full response/request permits retained for body lifetime consistent with existing resource policy.
Cross-platform correctness first. sendfile/zero-copy may be an optimization after correct async streaming is proven.
44. Suggested hard limits
Final values should be selected consistently with existing project limits, but define explicit bounds for at least:
- max web routes per vhost;
- max try_files candidates per route;
- max internal rewrites per route;
- max internal redirect depth;
- max named locations;
- max PHP profiles;
- max FastCGI custom params;
- max param name/value length;
- max FastCGI stderr captured per request;
- max index entries;
- max MIME overrides;
- max request body per web/PHP route;
- max FastCGI connections/profile;
- max FastCGI queue waiters.
Do not create attacker-controlled unbounded vectors/maps on the request path.
45. Implementation sequence
Phase 0 — lock current behavior
- Add/confirm regression tests for current route/fallback behavior.
- Add 0.24.2 config fixtures.
- Add tests proving existing
PathRewritesemantics. - Add tests for ACL/auth/header/security order.
- Record current H1/H2/H3 behavior.
Phase 1 — additive schema and internal action model
- Add optional
Vhost.web. - Add optional
PathRoute.web. - Add new config structs with
deny_unknown_fields. - Add validation.
- Add internal compiled action/target model.
- Compile all old configs to exactly existing Proxy/Return behavior.
- Allow zero HTTP backends only when configuration has no Proxy requirement.
- Update host ownership/fallback selection without changing legacy behavior.
- Update synthetic-root normalization.
- Run full regression suite before implementing filesystem access.
Phase 2 — static file engine
- Secure URL -> filesystem path resolver.
- Root/alias.
- GET/HEAD.
- directory redirects.
- index.
- MIME.
- Content-Length.
- ETag/Last-Modified.
- conditional GET.
- Range/If-Range.
- streaming body.
- symlink policy.
- dotfile/sensitive-file policy.
- PHP source deny.
- optional autoindex.
- local web response marker/pipeline integration.
Phase 3 — web routing
- structured try_files.
- named internal locations.
- safe variables.
- file/directory conditions.
- internal rewrite engine.
- query handling.
last.break.- internal redirect limit.
- final route response-header policy handling.
- rewrite/loop diagnostics.
Phase 4 — FastCGI/PHP-FPM
- FastCGI wire protocol.
- Unix sockets.
- TCP.
- connection pool.
- timeouts/queue/cancellation.
- PARAMS generation.
- streaming STDIN.
- streaming STDOUT.
- bounded STDERR.
- CGI response header parser.
- status/error mapping.
- PHP script existence/security.
- FastCGI params.
- optional PATH_INFO.
- real PHP-FPM integration test.
Phase 5 — WWW dashboard
- new tab.
- web root editor.
- fallback editor.
- PHP profiles.
- FastCGI test UI.
- static options.
- try_files builder.
- rewrite builder.
- named locations.
- location action Static/FastCGI.
- effective behavior preview.
- route conflict detection.
- no duplicate independent location system.
Phase 6 — presets
- Static.
- SPA.
- Generic PHP.
- WordPress.
- Drupal modern.
- Drupal legacy
q=. - Joomla.
- Laravel.
- Symfony.
- Nextcloud.
- phpMyAdmin.
- fixture tests for every preset.
Phase 7 — API/observability/docs
- OpenAPI.
- metrics.
- Prometheus.
- live logs.
- status diagnostics.
- EN/PL translations.
- docs.
- README/ROADMAP/CHANGELOG.
Phase 8 — release acceptance
python3 scripts/preflight.py.python3 scripts/check_source.py.python3 scripts/release_smoke.py../dev.sh fmt../dev.sh check../dev.sh test.- JS syntax checks.
- OpenAPI/lang JSON parse.
- real PHP-FPM Unix/TCP.
- WordPress runtime.
- Drupal runtime.
- H1/H2/H3 runtime.
- security/path traversal suite.
- large file/upload streaming/resource test.
- update
docs/TEST_REPORT.mdwith what was actually executed vs blocked.
46. Explicit non-goals for 0.25.0
Unless separately accepted, do not expand scope into:
- full Nginx config parser;
.htaccessparser;- Apache config compatibility;
- arbitrary embedded scripting;
- CGI process execution;
- mod_php equivalent;
- Node/Python/Ruby process manager;
- site file upload/file manager;
- automatic CMS installer/updater;
- automatic PHP-FPM configuration changes;
- arbitrary shell commands from web config;
- arbitrary environment variable exposure;
- FastCGI cache without a separate cache design;
- reverse proxy behavior rewrite;
- new authentication stack;
- new TLS stack.
The feature is a web/static/FastCGI origin inside the existing RustProxy vhost and policy architecture.
47. Definition of Done
RustProxy 0.25.0 Web Server is complete when all of the following are true:
- an unchanged 0.24.2 proxy config behaves the same under 0.25.0;
- a vhost can run with zero HTTP backends when it is a pure web server;
- a vhost can mix local static/PHP and existing proxied locations;
- static files are streamed securely from disk;
- directory/index handling works;
- PHP source cannot leak through static fallback;
- PHP-FPM works over Unix socket and TCP;
- request/response bodies stream with bounded resources;
- FastCGI params have safe trusted values;
try_fileshandles normal front-controller applications;- internal rewrites are bounded and do not reuse/alter legacy proxy rewrite semantics;
- Drupal/WordPress presets generate editable ordinary config;
- existing ACL/Auth/Tinyauth/rate/security/header/compression policies still apply;
- existing H1/H2/H3 request pipeline is reused;
- path traversal/symlink/root escape tests pass;
- existing proxy/location/cache/WebSocket regression tests pass;
- UI/API/manual JSON all edit the same canonical model;
- release documentation clearly distinguishes verified runtime tests from static/source checks.
48. Recommended architectural summary
The lowest-risk design is:
Existing vhost/frontend/listener/auth/ACL pipeline
|
v
Existing location matcher
|
+--------+---------+-----------+
| | |
Proxy Return Web
| | |
existing code existing code +---------------------+
Static FastCGI
| |
filesystem origin PHP-FPM origin
+----------+----------+
|
v
existing response policy
headers/security/compression/etc.
The WWW tab is a configuration UX over this canonical vhost model, not a separate server process and not a second competing routing engine.
The main compatibility rule is simple:
If
webis not configured, the request must follow the same path and semantics as RustProxy 0.24.2.