diff --git a/pages/docs/config/cgi-scgi-jsgi-php.md b/pages/docs/config/cgi-scgi-jsgi-php.md
index 9006462..a32f8b8 100644
--- a/pages/docs/config/cgi-scgi-jsgi-php.md
+++ b/pages/docs/config/cgi-scgi-jsgi-php.md
@@ -42,6 +42,8 @@ RedBrick 2.4.1 and newer allows to disable some default interpreter configuratio
As of RedBrick 2.4.3, there are default interpreter configurations for _.pl_, _.py_, _.sh_, _.ksh_, _.csh_, _.rb_ and _.php_ files. If server is running on Windows, then there will be additional default interpreter configuration for _.exe_, _.bat_, _.cmd_ (dropped in RedBrick 2.5.0) and _.vbs_ files.
+RedBrick 2.6.4 and newer support virtual host functionality based on switching web roots.
+
SVR.JS currently supports PHP-CGI through RedBrick mod. PHP is currently supported only inside _cgi-bin_ directory in SVR.JS web root. RedBrick 2.5.0 and newer supports PHP outside of _cgi-bin_ directory. You need to modify PHP configuration file (usually at `/etc/php/<php version>/cgi/php.ini`) and set _cgi.force_redirect_ property to _0_, otherwise PHP-CGI will not work and just display a warning about PHP-CGI binary being compiled with force-cgi-redirect enabled. **It's recommended to use directories outside of _cgi-bin_ for user uploads and downloads** (so that RedBrick will not treat uploaded scripts with shebang and ELF binary files as CGI applications and try to execute them, potentially resulting in hacker-uploaded malware infections, remote code execution vulnerabilities or 500 Internal Server Errors).
For security reasons, you may disable directory listing for _cgi-bin_ (and also other directories) through _disableDirectoryListing_ or _disableDirectoryListingVHost_ options in SVR.JS configuration.
@@ -79,11 +81,14 @@ OrangeCircle 1.3.0 and newer support multiple SCGI servers. These versions of Or
}
```
+OrangeCircle 1.3.1 and newer support virtual host functionality based on switching web roots.
+
## JSGI via YellowSquare
YellowSquare supports running JSGI scripts only in jsgi-bin directory. YellowSquare runs JSGI scripts, that are either with _.jsgi_ or _.jsgi.js_ extension. Every change in JSGI application requires a restart of SVR.JS in order to be applied.
YellowSquare 1.0.3 and newer work with web root outside SVR.JS installation directory (older ones need _config.json_ file in web root with valid JSON data; not necessarily related to _config.json_ in SVR.JS installation directory)
-For security reasons, you may disable directory listing for _jsgi-bin_ (and also other directories) through _disableDirectoryListing_ or _disableDirectoryListingVHost_ options in SVR.JS configuration.
+YellowSquare 1.1.4 and newer support virtual host functionality based on switching web roots.
+For security reasons, you may disable directory listing for _jsgi-bin_ (and also other directories) through _disableDirectoryListing_ or _disableDirectoryListingVHost_ options in SVR.JS configuration.
diff --git a/pages/docs/config/configuration.md b/pages/docs/config/configuration.md
index bfc4227..612e92f 100644
--- a/pages/docs/config/configuration.md
+++ b/pages/docs/config/configuration.md
@@ -155,6 +155,11 @@ The _config.json_ file contains various properties that you can customize to con
- Array containing URL strings to insert before web root postfix (for all hosts). For example: the source URL is _/cgi-bin/gitweb.cgi_, postfix is _svrjs_ and the postfix prefix is _/cgi-bin_; the rewritten URL is _/cgi-bin/svrjs/gitweb.cgi_.
- _allowPostfixDoubleSlashes_ (Boolean, SVR.JS 3.14.4 or newer)
- Option to allow double slashes, when inserting web root postfixes. If set to `false`, double slashes are removed by postfix insertion function. It may create issues with double slash URLs not having prefixes.
+- _wwwrootVHost_ (Array of Objects; SVR.JS 4.4.0 or newer)
+ - Array containing web roots assigned for each virtual host.
+ - _host_: Applicable host name for this web root (String, SVR.JS 4.4.0 or newer).
+ - _ip_: Applicable IP address for this web root. Use this property to specify destination server IP address instead of _host_ property to prevent _Host_ header attacks. (optional; String, SVR.JS 4.4.0 or newer).
+ - _wwwroot_: The web root used for the virtual host (String, SVR.JS 4.4.0 or newer).
## Miscellaneous Configuration
diff --git a/pages/docs/config/fastcgi-php-fpm.md b/pages/docs/config/fastcgi-php-fpm.md
index c8257f3..3b54e3f 100644
--- a/pages/docs/config/fastcgi-php-fpm.md
+++ b/pages/docs/config/fastcgi-php-fpm.md
@@ -84,6 +84,8 @@ If using GreenRhombus 1.1.0 or newer, you can configure GreenRhombus to connect
}
```
+GreenRhombus 1.1.1 and newer support virtual host functionality based on switching web roots.
+
PHP-FPM may run on different user than SVR.JS web server, so you may need to set permissions for the user, which PHP-FPM runs on.
If you are using PHP-FPM only for SVR.JS, you can set the _listen.owner_ and _listen.group_ properties to _svrjs_ in the PHP-FPM configuration file (e.g. `/etc/php/8.2/fpm/pool.d/www.conf`).
\ No newline at end of file
diff --git a/pages/docs/config/virtual-hosts.md b/pages/docs/config/virtual-hosts.md
index 6a66eab..9f9d097 100644
--- a/pages/docs/config/virtual-hosts.md
+++ b/pages/docs/config/virtual-hosts.md
@@ -4,7 +4,119 @@ title: Virtual hosts
# Virtual hosts
-When you're not planning to use SVR.JS server-side JavaScript or SVR.JS mods implementing individual web applications and plan to use SVR.JS similarly to Apache, nginx or IIS (static-only, PHP, CGI or JSGI), you can use virtual host-like functionality (name-based; IP-based from SVR.JS 3.14.1 and newer) with SVR.JS 3.8.0 or newer.
+## Using virtual host functionality based on switching web roots
+
+When you're not planning to use SVR.JS server-side JavaScript or SVR.JS mods implementing individual web applications and plan to use SVR.JS similarly to Apache, NGINX or IIS (static-only, PHP, CGI or JSGI), you can use virtual host functionality (based on switching web roots) with SVR.JS 4.4.0 or newer.
+
+You can set up custom error pages, URL rewriting rules and non-standard status code settings per-host like this (assuming that you want to also include CGI support through RedBrick):
+
+```json
+{
+ "users": [],
+ "port": 80,
+ "pubport": 80,
+ "page404": "404.html",
+ "blacklist": [],
+ "nonStandardCodes": [
+ {
+ "url": "/dl",
+ "location": "/download",
+ "host": "anothersite.example",
+ "scode": 301
+ },
+ {
+ "url": "/downloads",
+ "location": "/download",
+ "host": "anothersite.example",
+ "scode": 301
+ }
+ ],
+ "enableCompression": true,
+ "customHeaders": {},
+ "enableHTTP2": false,
+ "enableLogging": true,
+ "enableDirectoryListing": true,
+ "enableDirectoryListingWithDefaultHead": false,
+ "serverAdministratorEmail": "[no contact information]",
+ "stackHidden": false,
+ "enableRemoteLogBrowsing": false,
+ "exposeServerVersion": true,
+ "disableServerSideScriptExpose": true,
+ "rewriteMap": [
+ {
+ "definingRegex": "/^\\/index(?:$|[\\/#?])/",
+ "host": "anothersite.example".
+ "replacements": [
+ {
+ "regex": "/^\\/index/",
+ "replacement": "/"
+ }
+ ]
+ },
+ ],
+ "allowStatus": true,
+ "dontCompress": [
+ "/.*\\.ipxe$/",
+ "/.*\\.img$/",
+ "/.*\\.iso$/"
+ ],
+ "enableIPSpoofing": false,
+ "secure": false,
+ "sni": {},
+ "disableNonEncryptedServer": false,
+ "disableToHTTPSRedirect": false,
+ "enableETag": true,
+ "disableUnusedWorkerTermination": false,
+ "rewriteDirtyURLs": true,
+ "errorPages": [
+ {
+ "scode": 404,
+ "path": "oops.html",
+ "host": "website.example"
+ }
+ ],
+ "customHeadersVHost": [
+ {
+ "host": "website.example",
+ "headers": {
+ "X-Some-Header": "some-value"
+ }
+ }
+ ],
+ "enableDirectoryListingVHost": [
+ {
+ "host": "website.example",
+ "enable": false
+ }
+ ],
+ "wwwrootVHost": [
+ {
+ "host": "website.example",
+ "wwwroot": "./website.example"
+ },
+ {
+ "host": "anothersite.example",
+ "wwwroot": "./anothersite.example"
+ },
+ {
+ "wwwroot": "./NONEXISTENT_SITE"
+ }
+ ]
+}
+```
+
+You need to then create this directory structure in SVR.JS default web root:
+
+- website.example
+ - cgi-bin
+- anothersite.example
+ - cgi-bin
+
+Only some SVR.JS mods support virtual host functionality based on switching web roots.
+
+## Using virtual host functionality based on URL rewriting
+
+When you're not planning to use SVR.JS server-side JavaScript or SVR.JS mods implementing individual web applications and plan to use SVR.JS similarly to Apache httpd, NGINX or IIS (static-only, PHP, CGI or JSGI), you can use virtual host-like functionality (name-based; IP-based from SVR.JS 3.14.1 and newer) with SVR.JS 3.8.0 or newer.
You can set up custom error pages, URL rewriting rules and non-standard status code settings per-host like this (assuming that you want to also include CGI support through RedBrick):
diff --git a/pages/docs/mods/mod-development.md b/pages/docs/mods/mod-development.md
index 54c2f2f..914bdcd 100644
--- a/pages/docs/mods/mod-development.md
+++ b/pages/docs/mods/mod-development.md
@@ -78,6 +78,32 @@ The reserved control messages, used internally by SVR.JS begin with:
- `\x14PINGPING`
- `\x14SAVECONF`
+## Custom configuration validators
+
+SVR.JS 4.4.0 and later allows mods to have custom configuration validators to ensure that the configuration values provided are valid and meet specific criteria. This feature helps in maintaining the integrity and correctness of the mod's configuration.
+
+To add a custom configuration validator, you need to export a `configValidators` object from your mod. This object maps configuration keys to validator functions. Each validator function should take a single parameter, `value`, which is the configuration value to be validated, and return a boolean indicating whether the value is valid.
+
+Here is an example of how to define custom configuration validators:
+
+```js
+module.exports.configValidators = {
+ aNumber: (value) => typeof value === "number",
+ aString: (value) => typeof value === "string",
+ aPositiveNumber: (value) => typeof value === "number" && value > 0,
+ aNonEmptyString: (value) => typeof value === "string" && value.trim().length > 0
+};
+```
+
+In this example:
+
+- `aNumber` validator checks if the value is of type `number`.
+- `aString` validator checks if the value is of type `string`.
+- `aPositiveNumber` validator checks if the value is a positive number.
+- `aNonEmptyString` validator checks if the value is a non-empty string.
+
+Once you have defined your custom configuration validators, SVR.JS will automatically use them to validate the corresponding configuration values when the mod is loaded.
+
## Paths
`process.dirname` refers to the SVR.JS installation directory.