103 KiB
title | sitemap | date | layout |
---|---|---|---|
SVR.JS documentation | false | 2023-12-21 17:10:14 | docs-page |
Welcome to the official documentation of SVR.JS!
This documentation is in the public domain.
First use
System requirements
Minimum
- Node.JS 8.4.0 or newer (SVR.JS 3.4.x and earlier), Node.JS 10.0.0 or newer (SVR.JS 3.5.x and later) / Latest version of Bun (experimental).
- OS supported by Node.JS/Bun.
Recommended
- Latest Node.JS LTS version.
- 2-core CPU or better.
- 1.5GB of RAM or more.
- One of tested platforms: Android, FreeBSD, GNU/Linux, Haiku, Oracle Solaris, Microsoft Windows.
Installation
Using SVR.JS installer (installer packages made in April 5, 2024 and later; GNU/Linux only)
The command for SVR.JS installation is available in the SVR.JS home page. First off, switch to GNU/Linux tab, then copy the command below the tab into the terminal. The command looks something like this: curl -fsSL https://downloads.svrjs.org/installer/svr.js.installer.linux.20240509.sh > /tmp/installer.sh && sudo bash /tmp/installer.sh
. After starting the installer, you will be prompted to select the type of SVR.JS installation. After selecting the type, SVR.JS installer will install Node.JS, SVR.JS and create SVR.JS service. During installation, you may be prompted for the installation of dependencies. Once the installation is done, the server is started at http://localhost.
File structure will look like this:
- /usr/lib/svrjs - SVR.JS installation directory
- /var/log/svrjs - SVR.JS logs
- /var/www/svrjs - SVR.JS web root
- /etc/svrjs-config.json - SVR.JS configuration file (SVR.JS config.json)
SVR.JS installer will also install these commands:
- svrjs-loghighlight - SVR.JS log highlighter
- svrjs-logviewer - SVR.JS log viewer
- svrpasswd - SVR.JS user management tool
- svrjs-updater - SVR.JS updater
Using SVR.JS installer (installer packages made before April 5, 2024; GNU/Linux only)
SVR.JS now has a brand new installer for GNU/Linux. First, download SVR.JS installer, then unpack your SVR.JS installer zip archive. After unpacking the installer, download SVR.JS zip archive (not installer), copy it to the installer directory and rename it to "svrjs.zip". Then run SVR.JS installer using sudo bash installer.sh
. After starting the installer, you will be prompted to select the type of OS (type of GNU/Linux distribution). After selecting the type, SVR.JS installer will install Node.JS, SVR.JS and create SVR.JS service. During installation, you may be prompted for the installation of dependencies. Once the installation is done, restart your server OS or type systemctl start svrjs
or /etc/init.d/svrjs start
to start SVR.JS and get a web server on http://localhost.
File structure will look like this:
- /usr/lib/svrjs - SVR.JS installation directory
- /var/log/svrjs - SVR.JS logs
- /var/www/svrjs - SVR.JS web root
- /etc/svrjs-config.json - SVR.JS configuration file (SVR.JS config.json)
SVR.JS installer will also install these commands:
- svrjs-loghighlight - SVR.JS log highlighter
- svrjs-logviewer - SVR.JS log viewer
- svrpasswd - SVR.JS user management tool
Using create-svrjs-server tool
To install SVR.JS using create-svrjs-server, first install the utility using npm install -g svrjs
. Then create a directory, which will contain SVR.JS. Change your working directory to a new one, and run one of those commands:
create-svrjs-server lts
- Latest SVR.JS LTS versioncreate-svrjs-server latest
- Latest SVR.JS versioncreate-svrjs-server 3.6.1
- SVR.JS 3.6.1 (replace 3.6.1 with your desired version)
After downloading and installing SVR.JS to your working directory, run node svr.js
for SVR.JS 3.x or node svr_new.js
for earlier versions or bun run svr.js
if you're using Bun instead of Node.JS.
You will then see the message similar to this:
Decompressing modules...
Deleting SVR.JS stub...
Decompressing SVR.JS...
Restart SVR.JS to get server interface.
After running this command again, you'll get a web server on http://localhost.
Using Docker
To install SVR.JS via Docker, first pull the image using docker pull svrjs/svrjs
command, or docker pull svrjs/svrjs:lts
command, if you wish to install LTS version of SVR.JS. Then create and start the Docker container using docker run --name mysvrjs -d -p 80:80 --restart=always svrjs/svrjs
command (replace mysvrjs
with desired Docker container name). The file structure is the same, as it would be installed via SVR.JS installer. Once the installation is done, the server is started at http://localhost.
Manual installation
To install SVR.JS manually, first unpack your SVR.JS zip archive you downloaded from SVR.JS download page. Then change your working directory to one containing SVR.JS script stub, and run node svr.js
for SVR.JS 3.x or node svr_new.js
for earlier versions or bun run svr.js
if you're using Bun instead of Node.JS.
You will then see the message similar to this:
Decompressing modules...
Deleting SVR.JS stub...
Decompressing SVR.JS...
Restart SVR.JS to get server interface.
After running this command again, you'll get a web server on http://localhost, which looks like this:
After installation
When you visit localhost
, the page will look like this:
If you see this page, then SVR.JS installation is successful. You can now replace default server pages (index.html, tests.html, licenses, serverSideScript.js) with custom ones, and remove default mods! If you don't see this page, then there was a problem when installing SVR.JS.
Features
Static file handling
- Static file serving (even above 2GB)
- Directory listing serving
- Protection against path traversal
- Content-Range support (for non-HTML static files; also for HTML files from SVR.JS 3.15.1)
- Serving from web root different than SVR.JS installation directory
Security
- HTTPS support
- HTTP/2 support
- Built-in block list
- Protection against HTTP authentication brute force attacks (from SVR.JS 3.4.8; enabled by default)
- Ability to hide server version
- OCSP stapling support (from SVR.JS 3.4.9)
Configuration and customization
- Configurability via config.json file
- Expandability via server-side JavaScript and mods
- Ability to serve non-standard error pages
- URL rewriting engine
- Event driven architecture powered by Node.JS, along with clustering.
Compression and content delivery
- Brotli, gzip and Deflate HTTP compression (Brotli supported since SVR.JS 3.4.11)
- SNI (Server Name Indication) support
- ETag support (from SVR.JS 3.6.1)
- Reverse proxy functionality (requires reverse-proxy-mod SVR.JS mod)
- Forward proxy functionality (requires forward-proxy-mod SVR.JS mod)
Authentication and access control
- HTTP basic authentication
Gateway interfaces
- CGI (Common Gateway Interface) support (requires RedBrick mod)
- SCGI (Simple Common Gateway Interface) support (requires OrangeCircle mod)
- JSGI (JavaScript Gateway Interface) support (requires YellowSquare mod)
- PHP support (PHP-CGI with RedBrick mod or PHP-FPM with GreenRhombus mod)
Additional functionality
- Logging
- Ability to display IP addresses, from which originally request was made (from reverse proxies; via X-Forwarded-For)
SVR.JS files
- svr.js - main SVR.JS script
- config.json - SVR.JS configuration file
- serverSideScript.js - server-side JavaScript
- mods - directory, from which SVR.JS loads mods
- log - directory, to which SVR.JS logs
- temp - temporary directory for SVR.JS
SVR.JS utilities
SVR.JS 3.0.0 and later comes with several utilities:
- logviewer.js - SVR.JS log viewing tool
- loghighlight.js - SVR.JS log highlighting tool
- svrpasswd.js - SVR.JS user management tool
SVR.JS commands
SVR.JS comes with a console interface that provides several built-in commands for managing the server and interacting with it.
Available commands:
- close - Closes the server. This command will gracefully shut down the server, closing all connections and resources.
- open - Opens the server. This command allows you to start the server if it was previously closed.
- help - Displays the list of available commands. Use this command to get a quick overview of all the commands supported by the server console.
- mods - Displays the list of mods. SVR.JS supports modularity. This command will show you the currently installed mods.
- stop - Stops the server process. This command will terminate the SVR.JS server entirely.
- clear - Clears the current page of the terminal. This command helps to clean up the terminal interface.
- block <blocked> - Adds an IP address or a domain to the server's block list. Blocked clients will be denied access to the server.
- unblock <blocked> - Removes an IP address or a domain from the server's block list. Unblocked clients can access the server normally.
- restart - Restarts SVR.JS workers. This command will restart the server's worker processes, allowing for a fresh start of worker instances. (SVR.JS 3.0.0 or newer)
These commands provide an easy and convenient way to manage and control the SVR.JS server directly from the console.
Updating SVR.JS
Using SVR.JS updater (included in SVR.JS installer package; GNU/Linux only)
If you installed SVR.JS using installer packages in April 5, 2024 and later, you can just run sudo svrjs-updater
command to update SVR.JS to latest version. Once the update is done, restart your server OS or type systemctl start svrjs
or /etc/init.d/svrjs start
to restart SVR.JS.
For older installer packages, SVR.JS can be updated using SVR.JS updater by changing working directory to one containing SVR.JS updater, and running sudo bash updater.sh
(make sure svrjs.zip file contains new version of SVR.JS). Once the update is done, restart your server OS or type systemctl start svrjs
or /etc/init.d/svrjs start
to restart SVR.JS.
Using create-svrjs-server tool
SVR.JS can be updated using create-svrjs-server tool by changing working directory to one containing SVR.JS, and running one of those commands:
create-svrjs-server lts
- Latest SVR.JS LTS versioncreate-svrjs-server latest
- Latest SVR.JS versioncreate-svrjs-server 3.6.1
- SVR.JS 3.6.1 (replace 3.6.1 with your desired version)
Then you can run node svr.js
or bun run svr.js
to extract new version of SVR.JS and new Node.JS modules.
Manual updating
SVR.JS can be updated manually by extracting svr.js, modules.compressed and svr.compressed files from archive containing new version of SVR.JS to directory, to which older version of SVR.JS is installed (if you installed SVR.JS using SVR.JS installer, it is /usr/lib/svrjs). Then you can run node svr.js
or bun run svr.js
to extract new version of SVR.JS and new Node.JS modules.
Common problems
- Problem: Access denied. or Permission denied. You may not have sufficient privileges to access the requested address.
Solution: Run SVR.JS with elevated privileges. Check config.json. If you have installed SVR.JS with SVR.JS installer, grant Node.JS permissions usingsetcap 'cap_net_bind_service=+ep' /usr/bin/node
. - Problem: Address in use by another process. or Address is already in use by another process.
Solution: Try to stop process using the same port as SVR.JS, and restart SVR.JS. Check config.json - Problem: JSON Parse error.
Solution: Check config.json and correct JSON syntax errors. If it fails, delete config.json. SVR.JS will then create new config.json - Problem: SVR.JS worker just crashed!!!
Solution: Check your SVR.JS configuration, mods and server-side JavaScript. If crash is related to SVR.JS itself, you can report it at bugreports[at]svrjs[dot]org, or ask on SVR.JS bug reports board. - Problem: There was a problem while loading a "<mod name>" mod.
Solution: Try deleting temp directory. If it still won't work, report the problem to mod developer, or ask on SVR.JS mod problems board. - Problem: There was a problem while loading server side JavaScript.
Solution: Try deleting temp directory. If it still won't work, check your serverSideScript.js file, or ask on Problems with server-side JavaScript board. - Problem: There was a problem while saving logs! Logs will not be kept in log file.
Solution: Check your log directory.
Bun support
SVR.JS is currently partially compatible with Bun JavaScript runtime. In the benchmark shown below, SVR.JS on Bun 1.1 has around 2.8 times more requests per second and over 5 times lower maximum latency than SVR.JS on Node.JS 18.19.1 LTS.
However, SVR.JS on Bun currently has these limitations:
- Proxy requests with CONNECT method are not supported.
- WebSocket requests are not supported (via req.socket API).
- There is just one worker process (Bun 1.0 and later; due to cluster module not being implemented in Bun; SVR.JS shims the cluster module, but ports aren't shared in Bun 1.0 and later).
- PBKDF2 function blocks the event loop, which may cause denial of service.
- HTTP/2 is not supported (because Bun didn't implement HTTP/2 server in http2 module yet)
Configuration
SVR.JS can be configured by modifying config.json file.
config.json properties
The config.json file contains various properties that you can customize to configure SVR.JS according to your specific requirements. Below are the available properties:
General Configuration
- users (Array of Objects, SVR.JS 3.0.0 or newer)
- Users list for HTTP authentication. Use svrpasswd tool to add, modify or delete users.
- name: User name for HTTP authentication (String)
- pass: Salted hash of the password (default SHA256 with appended salt, String)
- salt: Salt used to generate the SHA256 hash (String)
- pbkdf2: Flag used to determine, if hash is PBKDF2 (Boolean, SVR.JS 3.7.0 or newer)
- scrypt: Flag used to determine, if hash is scrypt (Boolean, SVR.JS 3.7.0 or newer)
- Users list for HTTP authentication. Use svrpasswd tool to add, modify or delete users.
- port (Number or String, required)
- HTTP port for SVR.JS to listen on. For SVR.JS 3.6.0 and later, it can also be a Unix socket or Windows named pipe. For SVR.JS 3.9.0 and later, this can also be an IP address along with a port like "192.168.0.2:80" or like "[fdad:8948:1053::2]:80"
- pubport (Number, required)
- Public HTTP port for SVR.JS to display. It is also used in HTTP to HTTPS redirect.
- sport (Number or String)
- HTTPS port for SVR.JS to listen on. For SVR.JS 3.6.0 and later, it can also be a Unix socket or Windows named pipe. For SVR.JS 3.9.0 and later, this can also be an IP address along with a port like "192.168.0.2:80" or like "[fdad:8948:1053::2]:80"
- spubport (Number)
- Public HTTPS port for SVR.JS to display. It is also used in HTTP to HTTPS redirect.
SSL Configuration
- secure (Boolean, SVR.JS 3.0.0 or newer)
- Option to enable HTTPS.
- cert (String, required for HTTPS)
- Path to the SSL certificate file. Path is relative to SVR.JS installation directory, unless absolute path is specified.
- key (String, required for HTTPS)
- Path to the RSA/ECDSA private key file. Path is relative to SVR.JS installation directory, unless absolute path is specified.
- sni (Object, SVR.JS 3.0.0 or newer)
- SNI certificate paths for multiple domain names.
- {domain_name}: Object with properties cert and key (path to SSL certificate and private key).
- SNI certificate paths for multiple domain names.
- enableOCSPStapling (Boolean, SVR.JS 3.4.9 or newer)
- Option to enable OCSP stapling.
- useClientCertificate (Boolean, SVR.JS 3.14.0 or newer)
- Option to require client to provide its certificate.
- rejectUnauthorizedClientCertificates (Boolean, SVR.JS 3.14.0 or newer)
- Option to disable verification of client certificates.
- cipherSuite (String, SVR.JS 3.14.0 or newer)
- Specification of cipher suites, replacing the default. For more information, see Node.JS documentation.
- ecdhCurve (String, SVR.JS 3.14.0 or newer)
- Specification of ECDH curves, for example
P-521:P-384:P-256
. Set the parameter toauto
to select the curve automatically. You can useopenssl ecparam -list_curves
command to obtain available ECDH curves.
- Specification of ECDH curves, for example
- signatureAlgorithms (String, SVR.JS 3.14.0 or newer)
- Colon-seperated list for signature algorithms supported by the server. The list may contain digest algorithms (e.g.
SHA256
,MD5
), public key algorithms (e.g.RSA-PSS
,ECDSA
), combinations of both (e.g.RSA+SHA384
) or TLS v1.3 scheme names (e.g.rsa_pss_pss_sha512
). For more information, see OpenSSL man pages.
- Colon-seperated list for signature algorithms supported by the server. The list may contain digest algorithms (e.g.
- tlsMinVersion (String, SVR.JS 3.14.0 or newer)
- Minimum TLS version, it can be
TLSv1.3
,TLSv1.2
,TLSv1.1
, orTLSv1
. It is not recommended to set it less than TLSv1.2, unless it's required for interoperability. This is because of security vulnerabilities of TLS v1.1 and TLS v1.
- Minimum TLS version, it can be
- tlsMaxVersion (String, SVR.JS 3.14.0 or newer)
- Maximum TLS version, it can be
TLSv1.3
,TLSv1.2
,TLSv1.1
, orTLSv1
.
- Maximum TLS version, it can be
Domain and Redirect Configuration
- domain (String)
- Domain for SVR.JS to display. (In SVR.JS 2.x, it was domian)
- wwwredirect (Boolean)
- Option to enable redirects to domain name that begins with "www.". You need to first set domain property in order for this option to have effect. This property didn't work in SVR.JS versions from 3.3.0 to 3.14.4
Error Pages and Logging Configuration
- page404 (String)
- Path to a custom 404 error page (after pages defined in errorPages property).
- errorPages (Array; SVR.JS 3.8.0 or newer)
- Custom error pages configuration.
- scode: HTTP status code specification for error page (Number, SVR.JS 3.8.0 or newer).
- path: Path for error page (String, SVR.JS 3.8.0 or newer).
- host: Applicable host name for this error page (optional; String, SVR.JS 3.8.0 or newer).
- ip: Applicable IP address for this error page. Use this property to specify destination server IP address instead of host property to prevent Host header attacks. (optional; String, SVR.JS 3.14.1 or newer).
- Custom error pages configuration.
- serverAdministratorEmail (String, SVR.JS 3.0.0 or newer)
- Server administrator e-mail address to be displayed in default 5xx error pages.
- enableLogging (Boolean)
- Option to enable saving logs to a log file.
HTTP Configuration
- enableCompression (Boolean, SVR.JS 3.0.0 or newer)
- Option to enable HTTP compression.
- enableHTTP2 (Boolean)
- Option to enable HTTP/2.
- enableDirectoryListing (Boolean)
- Option to enable directory listing. If disabled, it returns a 403 error page.
- enableDirectoryListingWithDefaultHead (Boolean)
- Option to enable default header and footer on directory listing.
- nonStandardCodes (Array of Objects)
- Non-standard status codes configuration:
- scode: Non-standard status code to apply. (Number)
- url: URL to which this status code applies (after URL rewriting; String).
- regex: Regex string (e.g.
"/^\\/index\\.php(?:$|[\\/?#])/"
) for matching the source URL (after URL rewriting) this status code applies to (with or without the query string). (Regex String, SVR.JS 3.0.0 or newer) - location: URL to which it is redirected on 301 and 302 status codes. (String)
- realm: HTTP authentication realm on 401 status code. (String, SVR.JS 3.0.0 or newer)
- disableBruteProtection: Option to disable brute force protection on 401 status code. (Boolean, SVR.JS 3.4.8 or newer)
- host: Applicable host name for this status code. (optional; String, SVR.JS 3.8.0 or newer)
- ip: Applicable IP address for this status code. Use this property to specify destination server IP address instead of host property to prevent Host header attacks. (optional; String, SVR.JS 3.14.1 or newer)
- userList: Allowed users for HTTP authentication. (optional; Array of Strings, SVR.JS 3.8.0 or newer)
- Non-standard status codes configuration:
- dontCompress (Array of Regex Strings, SVR.JS 3.0.0 or newer)
- URLs for which HTTP compression will be disabled.
- enableIPSpoofing (Boolean, SVR.JS 3.0.0 or newer)
- Option to enable identifiying client's originating IP address through the X-Forwarded-For header (for use in websites hidden behind a reverse proxy, not recommeded if you're not using SVR.JS behind a reverse proxy, since hackers can spoof client IP address via this header).
- enableETag (Boolean, SVR.JS 3.6.1 or newer)
- Option to enable ETags.
- customHeaders (Object, SVR.JS 3.0.0 or newer)
- Custom HTTP headers (configured as a JavaScript object) with a {path} template representing the request path (after URL rewriting).
- http2Settings (Object, SVR.JS 3.14.0 or newer)
- HTTP/2 protocol settings object. See Node.JS documentation for more information.
- headerTableSize: Maximum number of bytes used for header compression. Minimum value is 0. Maximum value is 232-1. Default is 4096 (Number, SVR.JS 3.14.0 or newer).
- enablePush: Option to enable HTTP/2 Push Streams. It is enabled by default (Boolean, SVR.JS 3.14.0 or newer).
- initialWindowSize: Sender's initial window size in bytes for stream-level flow control. Minimum value is 0. Maximum value is 232-1. Default is 65535 (Number, SVR.JS 3.14.0 or newer).
- maxFrameSize: Largest frame payload size in bytes. Minimum value is 16384. Maximum value is 224-1. Default is 16384 (Number, SVR.JS 3.14.0 or newer).
- maxConcurrentStreams: Maximum number of concurrent streams allowed on HTTP/2 session. Minimum value is 0. Maximum value is 232-1. Default is 232-1 (Number, SVR.JS 3.14.0 or newer).
- maxHeaderListSize: Maximum size (uncompressed octets) of acceptable header list. Minimum value is 0. Maximum value is 232-1. Default is 65535 (Number, SVR.JS 3.14.0 or newer).
- maxHeaderSize: Alias for maxHeaderListSize (Number, SVR.JS 3.14.0 or newer).
- enableConnectProtocol: Option to enable the "Extended Connect Protocol" defined by RFC 8441 (Number, SVR.JS 3.14.0 or newer).
- customSettings: Additional settings not implemented yet in Node.JS and its underlying libraries. Object key defines the numeric value of the settings type (as defined in the "HTTP/2 SETTINGS" registry established by RFC 7540). Object values define actual numeric value of the settings. Settings types should be greater than 6 and less than 216-1. Values should be in range from 0 to 232-1. Currently you can specify up to 10 custom settings (Object, SVR.JS 3.14.0 or newer).
- HTTP/2 protocol settings object. See Node.JS documentation for more information.
Security Configuration
- blacklist (Array of Strings)
- Block list of IP addresses and CIDR ranges.
- disableServerSideScriptExpose (Boolean, SVR.JS 3.0.0 or newer)
- Option to disable exposing SVR.JS script, server-side JavaScript, SVR.JS mods, and Node.JS modules. It's strongly recommended to set this property to true if you're using SVR.JS server-side JavaScript. If you want to additionally prevent fingerprinting SVR.JS by accessing /serverSideScript.js, you can add URL rewrite rule, that defines rewriting of /serverSideScript.js to a non-existent page.
- enableRemoteLogBrowsing (Boolean, SVR.JS 3.0.0 or newer)
- Option to enable browsing server logs from an HTTP client. Applicable only when you're not using custom web root. It's not recommended to enable this, because it provides valuable information for attackerss, unless you're protecting log folder with HTTP authentication.
- exposeServerVersion (Boolean)
- Option to expose the server version via Server header. If it is disabled, the header will have "SVR.JS" value.
- rewriteDirtyURLs (Boolean, SVR.JS 3.7.0 or newer)
- Option to rewrite "dirty" URLs (those filtered by path sanitizer) instead of redirecting them.
- exposeModsInErrorPages (Boolean, SVR.JS 3.4.29, 3.9.1 or newer)
- Option to expose SVR.JS mod information through default error pages (for example in SVR.JS RedBrick/2.4.2 on forum.svrjs.org signature). Mod information is never exposed through Server header (just SVR.JS information).
Virtual Host Configuration
- enableDirectoryListingVHost (Array of Objects; SVR.JS 3.8.0 or newer)
- Array containing options to enable directory listings for specific virtual hosts.
- host: Applicable host name for this rule (String, SVR.JS 3.8.0 or newer).
- ip: Applicable IP address for this rule. Use this property to specify destination server IP address instead of host property to prevent Host header attacks. (optional; String, SVR.JS 3.14.1 or newer).
- enabled: Has the same effect as enableDirectoryListing (Boolean, SVR.JS 3.8.0 or newer).
- Array containing options to enable directory listings for specific virtual hosts.
- customHeadersVHost (Array of Objects; SVR.JS 3.8.0 or newer)
- Array containing custom headers for specific virtual hosts.
- host: Applicable host name for this rule (String, SVR.JS 3.8.0 or newer).
- ip: Applicable IP address for this rule. Use this property to specify destination server IP address instead of host property to prevent Host header attacks. (optional; String, SVR.JS 3.14.1 or newer).
- headers: Has the same effect as customHeaders property (Object, SVR.JS 3.8.0 or newer).
- Array containing custom headers for specific virtual hosts.
- wwwrootPostfixesVHost (Array of Objects; SVR.JS 3.14.0 or newer)
- Array containing web root postfixes assigned for each virtual host. For example: the source URL is /page.html and postfix is svrjs; the rewritten URL is /svrjs/page.html. URL rewriting (with rules defined in the rewriteMap property) will be processed after assigning web root postfixes.
- host: Applicable host name for this prefix (String, SVR.JS 3.14.0 or newer).
- ip: Applicable IP address for this prefix. Use this property to specify destination server IP address instead of host property to prevent Host header attacks. (optional; String, SVR.JS 3.14.1 or newer).
- postfix: Postfix inserted before the request URL (String, SVR.JS 3.14.0 or newer).
- skipRegex: Regex string (e.g.
"/^\\/index\\.php(?:$|[\\/?#])/"
) for matching request URLs to skip (optional; Regex String, SVR.JS 3.14.0 or newer).
- Array containing web root postfixes assigned for each virtual host. For example: the source URL is /page.html and postfix is svrjs; the rewritten URL is /svrjs/page.html. URL rewriting (with rules defined in the rewriteMap property) will be processed after assigning web root postfixes.
- wwwrootPostfixPrefixesVHost (Array of Strings; SVR.JS 3.14.0 or newer)
- 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.
- Option to allow double slashes, when inserting web root postfixes. If set to
Miscellaneous Configuration
- rewriteMap (Array of Objects, SVR.JS 3.0.0 or newer)
- Map for URL rewriting engine. Entries of the array are URL rewrite rules.
- definingRegex: Regex string (e.g.
"/^\\/index\\.php(?:$|[\\/?#])/"
) for matching the source URL it applies to (Regex String, SVR.JS 3.0.0 or newer). - host: Applicable host name for this URL rewriting rule (optional; String, SVR.JS 3.8.0 or newer).
- ip: Applicable IP address for this URL rewriting rule. Use this property to specify destination server IP address instead of host property to prevent Host header attacks. (optional; String, SVR.JS 3.14.1 or newer).
- append: String to append after the end of URL (optional; String, SVR.JS 3.0.0 or newer).
- isNotDirectory: Option to disable rewrite rule, when directory defined by the path exists (optional; Boolean, SVR.JS 3.13.0 or newer).
- isNotFile: Option to disable rewrite rule, when file defined by the path exists (optional; Boolean, SVR.JS 3.13.0 or newer).
- allowDoubleSlashes: Option to allow double slashes in the URL. If set to
false
, then URL rewriter removes double slashes. You may use\\/{1,2}
instead of\\/
in URL rewriting regular expressions (optional; Boolean, SVR.JS 3.14.4 or newer). - replacements: Regex string (e.g.
"/^\\/index\\.php(?:$|[\\/?#])/"
) replacements (Array of Objects, SVR.JS 3.0.0 or newer).- regex: Regex string (e.g.
"/^\\/index\\.php(?:$|[\\/?#])/"
) for matching the source URL this replacement applies to (Regex String, SVR.JS 3.0.0 or newer). - replacement: Replacement string (you can use for example "$1" for first capturing group; String, SVR.JS 3.0.0 or newer).
- regex: Regex string (e.g.
- definingRegex: Regex string (e.g.
- Map for URL rewriting engine. Entries of the array are URL rewrite rules.
- disableNonEncryptedServer (Boolean, SVR.JS 3.0.0 or newer)
- Option to disable the HTTP server if the HTTPS server is running.
- disableToHTTPSRedirect (Boolean, SVR.JS 3.0.0 or newer)
- Option to disable redirects from the HTTP server to the HTTPS server.
- allowStatus (Boolean, SVR.JS 3.0.0 or newer)
- Option to enable /svrjsstatus.svr page for monitoring server status (by default it's enabled).
- wwwroot (String, SVR.JS 3.0.0 or newer)
- Path to the root directory from which SVR.JS serves files and loads its server-side JavaScript. Defaults to the directory on which SVR.JS resides.
- disableUnusedWorkerTermination (Boolean, SVR.JS 3.7.0 or newer)
- Option to disable termination of unused SVR.JS workers.
- useWebRootServerSideScript (Boolean, SVR.JS 3.9.0 or newer)
- Option to use server-side JavaScript in web root. If it is set to false, the server-side JavaScript is loaded from SVR.JS installation directory.
- disableTrailingSlashRedirects (Boolean, SVR.JS 3.12.0 or newer)
- Option to disable redirects from URLs referencing to directories (but without a trailing slash) to URL with a trailing slash. For forwards proxy applications and SVR.JS 3.14.9 and earlier, it needs to be true, or else the server will just do redirect loops.
- environmentVariables (Object, SVR.JS 3.12.0 or newer)
- Envrionment variables. These can be used for CGI web applications and server-side JavaScript.
- allowDoubleSlashes (Boolean, SVR.JS 3.14.4 or newer)
- Option to allow double slashes in the URL. If set to
false
, double slashes are removed by URL sanitizer. Double slashes at the beginning of path (e.g. in //config.json) are always removed. Doesn't affect URL rewriting, in that case please configure the allowDoubleSlashes property in the URL rewriting rule. It may allow some configuration file leaks, if web root is in the SVR.JS installation directory.
- Option to allow double slashes in the URL. If set to
- optOutOfStatisticsServer (Boolean, SVR.JS 3.15.6 or newer)
- Option to opt out of sending data to the statistics server. You can use this option to increase the privacy of SVR.JS.
Deprecated and Removed Properties
The following properties are deprecated or removed in newer versions of SVR.JS, and modifying them might not have any effect on the server:
- timestamp (Number, DON'T CHANGE)
- Timestamp of server starting. (This property should not be modified.)
- version (String, removed in SVR.JS 3.4.0, DON'T CHANGE)
- SVR.JS version (This property is no longer used and should not be modified.)
Example Configuration
Here's an example config.json file illustrating some of the available properties:
{
"port": 8080,
"pubport": 80,
"sport": 8443,
"spubport": 443,
"domain": "example.com",
"wwwroot": "/var/www/html",
"wwwredirect": true,
"page404": "custom_404.html",
"enableLogging": true,
"enableDirectoryListing": true,
"enableCompression": true,
"enableHTTP2": true,
"enableETag": true,
"secure": true,
"cert": "path/to/certificate.crt",
"key": "path/to/private.key",
"exposeServerVersion": false,
"exposeModsInErrorPages": false,
"disableServerSideScriptExpose": true,
"enableIPSpoofing": true,
"allowStatus": false,
"useWebRootServerSideScript": false,
"rewriteMap": [
{
"definingRegex": "/^\\/serverSideScript\\.js(?:$|[#?])/",
"replacements": [
{
"regex": "/^\\/serverSideScript\\.js($|[#?])/",
"replacement": "/NONEXISTENT_PAGE$1"
}
]
},
{
"definingRegex": "/^\\/old-url$/",
"replacements": [
{
"regex": "/^\\/old-url$/",
"replacement": "/new-url"
}
]
}
],
"customHeaders": {
"X-Frame-Options": "DENY",
"X-Content-Type-Options": "nosniff"
}
}
CLI options
- -h, -?, /h, /? or --help - displays help
- --clean - cleans up files created by SVR.JS
- --reset - resets SVR.JS to default settings (WARNING: DANGEROUS)
- --secure - runs HTTPS server
- --disable-mods - disables mods (safe mode)
- --single-threaded - runs single-threaded
- -v or --version - displays server version
Page customization
You can easily customize the appearance of pages served by SVR.JS by adding custom head and foot sections. These sections can be linked to every .html file served by SVR.JS.
To customize the head, create a head.html or .head (SVR.JS 3.0.0 or newer) file in the web root directory. For the foot, create a foot.html or .foot (SVR.JS 3.0.0 or newer) file in the web root directory. Both custom head and foot sections will also be linked to directory listings if the enableDirectoryListingWithDefaultHead property in config.json is set to true.
For individual directory listings, you can add custom head and foot sections as well. Create a HEAD.html or .dirhead (SVR.JS 3.0.0 or newer) file for the head section, and a FOOT.html or .dirfoot (SVR.JS 3.0.0 or newer) file for the foot section in the specific directory you want to customize. You can also add a description of the directory (in HTML format) by creating a .maindesc file in the respective directory. You can even apply CSS styles to directory listing table (using #directoryListing
CSS selector and custom directory listing head and foot).
You can add index page to web root or directories in web root with one of those file names: index.html, index.htm and index.xhtml.
From SVR.JS 3.5.0, you can change directory listing icons by replacing the icons in the .dirimages directory located in the web root. If an icon is not present in the .dirimages directory in the web root, SVR.JS will fall back to using icons in the .dirimages directory in the same directory as the SVR.JS script.
Custom error pages
You can configure SVR.JS to serve custom error pages by adding .<errorcode> (SVR.JS 3.0.0 or newer) or <errorcode>.html pages. For the 404 error, you can specify it by changing the page404 property in config.json. From SVR.JS 3.8.0 onwards, you can use errorPages property in config.json to specify path to each custom error page.
When designing custom error pages, you can make use of the following placeholders or templates:
- {errorMessage} - Displays the error code along with its short description.
- {errorDesc} - Displays a longer description of the server error.
- {stack} - Displays the error stack, which is equivalent to the Error.stack property in JavaScript.
- {path} - Shows the path of the page that caused the error.
- {server} - Displays the server version string along with the hostname. For example, "SVR.JS/3.9.6 (Linux; Node.JS/v12.22.12) on 127.0.0.1:8080" or simply "SVR.JS on svrjs.org".
- {contact} - Displays the contact information of the server administrator, which can be set using the serverAdministratorEmail property in config.json.
User management
You can manage users for HTTP authentication in SVR.JS by using svrpasswd.js tool (SVR.JS 3.0.0 or newer). Usage is node svrpasswd.js [-h] [--help] [-?] [/h] [/?] [-x] [-a|--add|-d|--delete] <username>
. Command-line options:
- -h, -?, /h, /? or --help - displays help
- -a or --add - adds an user
- -d or --delete - deletes an user
- -x - forces password hashing algorithm change
In SVR.JS 3.7.0 and newer, you can choose between 3 password hashing algorithms:
- Salted SHA256 (1 iteration) - fastest and uses least memory, but less secure
- PBKDF2 (PBKDF2-HMAC-SHA512, 36250 iterations) - more secure and uses less memory, but slower
- scrypt (N=214, r=8, p=1) - faster and more secure, but uses more memory
HTTP authentication
You can add HTTP basic authentication by including a 401 code (with scode property set to 401) entry in the nonStandardCodes property of config.json. To enable HTTP basic authentication, you need to specify the URL you want to restrict in the url or regex property of the entry. Additionally, you can set the authentication realm in the realm property. If the realm is not specified, the default realm is "SVR.JS HTTP Basic Authorization". The encoding used for authentication will always be UTF-8.
By default, SVR.JS enables brute force protection for HTTP authentication, so you don't need to worry about potential brute force attacks against the authentication mechanism.
From SVR.JS 3.8.0 onwards, you can specify a list of allowed users in the userList property.
Redirects
Setting up HTTP redirects is simple with SVR.JS. You can add a 301 or 302 code (with scode property set to 301 or 302) entry to the nonStandardCodes property in config.json. The entry should specify the source URL for the redirect in the url or regular expression string for the redirect in regex property (for example "/\\/blog($|[#?\\/].*)/"
), and the destination URL in the location property (for regular expressions, you can use for example "$1" for contents of first capturing group). Destination location can be relative to current site (for example /blogs) or a full URL (for example https://blog.example.com).
Please be cautious when setting up redirects to avoid redirect loops, as they can cause unintended behavior and potentially impact the performance of your server.
From SVR.JS 3.8.0 onwards, you can specify a hostname for which this redirect applies in host property. If you want to move your website to new address, you can add redirect to new website and specify host property to be host name of the old website (for example oldsite.example), location property to be a location of new website with "$1" appended (for example "https://newsite.example$1") and regex property to be "/(.*)/"
(regular expression, which matches everything to capturing group).
URL rewriting
You can set up URL rewriting by adding entries to rewriteMap property in config.json file. See "config.json properties" section for URL rewrite rules syntax.
Log viewing
To make log viewing easier, SVR.JS 3.x and later included it's log viewer utility under logviewer.js. SVR.JS log viewer is interactive.
You can also manually view logs, and highlight them using SVR.JS log highlighter utility under loghighlight.js (SVR.JS 3.0.0 or newer). Usage: <some process> | node loghighlight.js [-h] [--help] [-?] [/h] [/?]
.
SVR.JS stores it's logs in log directory. Server logs look like this:
[2023-07-04T18:50:54.610Z] SERVER MESSAGE [Request Id: c0ffd0]: Somebody connected to port 80... [2023-07-04T18:50:54.611Z] SERVER REQUEST MESSAGE [Request Id: c0ffd0]: Client ::ffff:127.0.0.1:33670 wants content in localhost/leak.svr [2023-07-04T18:50:54.611Z] SERVER REQUEST MESSAGE [Request Id: c0ffd0]: Client uses Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0 [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: There was an error while processing the request! [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: Stack: [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: RangeError [ERR_INVALID_OPT_VALUE]: The value "4294967296" is invalid for option "size" [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at Function.allocUnsafe (buffer.js:290:3) [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at /home/ubuntu/svr.js.3.3.3/temp/serverSideScript.js:70:18 [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at /home/ubuntu/svr.js.3.3.3/temp/modloader/primitiveanalytics.tar.gz/index.js:28:23 [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at modExecute (/home/ubuntu/svr.js.3.3.3/svr.js:2981:9) [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at Server.reqhandler (/home/ubuntu/svr.js.3.3.3/svr.js:3741:11) [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at Server.emit (events.js:198:13) [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at parserOnIncoming (_http_server.js:691:12) [2023-07-04T18:50:54.625Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: at HTTPParser.parserOnHeadersComplete (_http_common.js:111:17) [2023-07-04T18:50:54.626Z] SERVER RESPONSE ERROR MESSAGE [Request Id: c0ffd0]: Server responded with 500 code. [2023-07-04T18:50:54.630Z] SERVER MESSAGE [Request Id: c0ffd0]: Client disconnected. [2023-07-04T18:50:54.699Z] SERVER MESSAGE [Request Id: 1be453]: Somebody connected to port 80... [2023-07-04T18:50:54.699Z] SERVER REQUEST MESSAGE [Request Id: 1be453]: Client ::ffff:127.0.0.1:33670 wants content in localhost/favicon.ico [2023-07-04T18:50:54.700Z] SERVER REQUEST MESSAGE [Request Id: 1be453]: Client uses Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:99.0) Gecko/20100101 Firefox/99.0 [2023-07-04T18:50:54.709Z] SERVER MESSAGE [Request Id: 1be453]: Client disconnected. [2023-07-04T18:50:54.710Z] SERVER RESPONSE MESSAGE [Request Id: 1be453]: Server responded with 200 code. [2023-07-04T18:50:54.712Z] SERVER RESPONSE MESSAGE [Request Id: 1be453]: Client successfully recieved content.
First on the line is timestamp. Second is message type, optionally with request ID. Last is message contents.
Environment variables
SVR.JS 3.12.0 and newer
You can configure environment variables by configuring environmentVariables property in config.json.
Older SVR.JS versions
SVR.JS seamlessly passes through externally set environment variables to mods and server-side JavaScript, allowing you to customize and control your application's behavior based on these variables.
If you have a start-up script or use the command line to run SVR.JS, you can easily set environment variables before launching the server. Here's an example of how you can do it in a bash script:
export NODE_ENV=production
export OPENAI_API_KEY=redacted
node svr.js
In this example, we're setting two environment variables, NODE_ENV
and OPENAI_API_KEY
, before running the node svr.js
command. These environment variables will be accessible within your mods and server-side JavaScript, allowing you to utilize them to configure and adapt your application as needed.
If you have installed SVR.JS using SVR.JS installer then you may modify /etc/init.d/svrjs script (do_start method) like this:
do_start()
{
if [ ! -f "$lockfile" ] ; then
echo -n $"Starting $servicename: "
runuser -l "$user" -c "export GIT_HTTP_EXPORT_ALL=1; export GIT_PROJECT_ROOT=/var/lib/git; $nodejs $server > /dev/null &" && echo_success || echo_failure
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch "$lockfile"
else
echo "$servicename is locked."
RETVAL=1
fi
}
If you have used SVR.JS installer on GNU/Linux distribution that uses systemd, then you may add Environment directives in Service section in systemd service file (/etc/systemd/system/svrjs.service) like this:
[Unit]
Description=SVR.JS web server
After=network.target
[Service]
Type=simple
User=svrjs
ExecStart=/usr/bin/env node /usr/lib/svrjs/svr.js
Environment=GIT_HTTP_EXPORT_ALL=1
Environment=GIT_PROJECT_ROOT=/var/lib/git
Restart=on-failure
[Install]
WantedBy=multi-user.target
Using environment variables can be a powerful way to manage different configurations for development, staging, and production environments, configure your CGI web applications, or to securely store sensitive information like API keys and passwords.
Remember that when you set environment variables externally, they will be available to all instances of SVR.JS running on your system. Exercise caution when using sensitive information as environment variables, and ensure that they are properly secured and protected.
By leveraging environment variables, you can enhance the flexibility and security of your SVR.JS application and streamline your deployment process.
CGI/SCGI/JSGI/PHP
In order to use CGI with SVR.JS, you need to install RedBrick mod. For SCGI you need to install OrangeCircle, while for JSGI you need to install YellowSquare mod. Download these mods.
CGI and PHP via RedBrick
RedBrick supports running CGI programs and PHP files (RedBrick 2.3.0 and newer) in cgi-bin directory. RedBrick 2.5.0 and newer support running CGI programs and PHP files outside cgi-bin directory. You can configure file extensions outside of cgi-bin directory handled by RedBrick in redbrick-scriptexts.json file in SVR.JS installation directory like this:
[
".php",
".cgi"
]
RedBrick custom interpreters (from RedBrick 2.3.2; in earlier versions it is broken) can be configured in redbrick-interpreters.json file in SVR.JS install directory like this:
{
".pl": ["perl"],
".py": ["python"],
".sh": ["bash"],
".pyw": ["python"],
".rb": ["ruby"],
".php": ["php-cgi"]
}
RedBrick 2.3.0 and newer support PHP-CGI, while RedBrick 2.3.1 and newer support URL rewriting. RedBrick 2.3.6 and newer work with Windows (older ones always threw an 500 error while trying to execute CGI scripts on Windows). RedBrick 2.4.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)
RedBrick 2.4.1 and newer allows to disable some default interpreter configuration using "null" like this:
{
".pl": null,
".py": null,
".rb": null,
".exe": null
}
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.
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.
SCGI via OrangeCircle
OrangeCircle can be configured in orangecircle-config.json file in SVR.JS install directory like this:
{
"path": "/scgi",
"host": "localhost",
"port": 4000
}
OrangeCircle 1.0.7 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)
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.
FastCGI/PHP-FPM
In order to use FastCGI with SVR.JS, you need to install GreenRhombus mod. Download the mod.
GreenRhombus notes
GreenRhombus' path and FastCGI server address can be configured in greenrhombus-config.json file in the SVR.JS install directory.
Example configuration (with FastCGI server listening with port):
{
"path": "/fastcgi",
"host": "localhost",
"port": 7000
}
Example configuration (with FastCGI server listening on socket):
{
"path": "/fastcgi",
"socketPath": "/run/fastcgi.sock"
}
You can configure file extensions outside of path specified in greenrhombus-config.json file handled by GreenRhombus in greenrhombus-scriptexts.json file in SVR.JS installation directory like this:
[
".php"
]
PHP-FPM
GreenRhombus supports running PHP files through PHP-FPM. If you want to use GreenRhombus only for PHP-FPM, configure greenrhombus-config.json like this (in this case we're using socket in /run/php/php8.2-fpm.sock; you can check it in PHP-FPM configuration file, e.g. /etc/php/8.2/fpm/pool.d/www_.conf_; configure it without path property):
{
"socketPath": "/run/php/php8.2-fpm.sock"
}
And configure greenrhombus-scriptexts.json like this:
[
".php"
]
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_).
Forward proxy notes
In order to use SVR.JS as a forward proxy, you need to install forward-proxy-mod SVR.JS mod. Download this mod.
If you are using forward-proxy-mod, then local IP addresses and localhost are also accessible from the proxy. You may block these using a firewall, if you don't want these to be accessible from the proxy
Reverse proxy configuration
In order to use SVR.JS as a reverse proxy, you need to install reverse-proxy-mod SVR.JS mod. Download this mod.
Configuration file of reverse-proxy-mod is reverse-proxy-config.json inside SVR.JS installation directory. Keys of configuration object are domain names (or paths from reverse-proxy-mod 1.1.1), for which it's settings apply. Values are object with those properties:
- hostname - Hostname of origin server.
- port - Port of origin server.
- secureHostname - Hostname of origin server (access via HTTPS).
- securePort - Port of origin server (access via HTTPS).
reverse-proxy-mod 1.1.0 and newer support HTTP upgrades (including WebSocket).
If you're using per-host URL rewrite rules and running multiple sites on one SVR.JS instance (instead of proxying them all to specific web servers; assuming that you're using SVR.JS 3.8.0 or newer; shared hosting), use paths referring to URL rewrite destinations instead of domain names. However if you're planning to use VPSes (virtualized servers) or run different web server instances and use SVR.JS with reverse-proxy-mod as a reverse proxy for them, use domain names instead.
If you're using SVR.JS just as a reverse proxy (for VPSes or other web server instances, and not serving websites from proxy itself), set disableServerSideScriptExpose to false, set web root to outside SVR.JS installation directory, empty out rewriteMap, nonStandardCodes, enableDirectoryListingVHost, customHeadersVHost, wwwrootPostfixesVHost, wwwrootPostfixPrefixesVHost to []
, empty out customHeaders to {}
, set disableTrailingSlashRedirects to true, set allowDoubleSlashes to true, and set disableToHTTPSRedirect to true, in order to avoid interference involving SVR.JS web server (use this configuration when proxy itself doesn't use SVR.JS server-side JavaScript not including SVR.JS mods).
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.
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):
{
"users": [],
"port": 80,
"pubport": 80,
"page404": "404.html",
"blacklist": [],
"nonStandardCodes": [
{
"url": "/anothersite.example/dl",
"location": "/download",
"host": "anothersite.example",
"scode": 301
},
{
"url": "/anothersite.example/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": "/^(?!\\/(?:\\.dirimages|cgi-bin)(?:$|[\\/#?]))/",
"host": "website.example",
"replacements": [
{
"regex": "/(.*)/",
"replacement": "/website.example$1"
}
]
},
{
"definingRegex": "/^\\/cgi-bin(?:$|[\\/#?])/",
"host": "website.example",
"replacements": [
{
"regex": "/^\\/cgi-bin($|[\\/#?].*)/",
"replacement": "/cgi-bin/website.example$1"
}
]
},
{
"definingRegex": "/^(?!\\/(?:\\.dirimages|cgi-bin)(?:$|[\\/#?])|\\/index(?:$|[\\/#?]))/",
"host": "anothersite.example",
"replacements": [
{
"regex": "/(.*)/",
"replacement": "/anothersite.example$1"
}
]
},
{
"definingRegex": "/^\\/index(?:$|[\\/#?])/",
"host": "anothersite.example".
"replacements": [
{
"regex": "/^\\/index/",
"replacement": "/anothersite.example/"
}
]
},
{
"definingRegex": "/^\\/cgi-bin(?:$|[\\/#?])/",
"host": "anothersite.example",
"replacements": [
{
"regex": "/^\\/cgi-bin($|[\\/#?].*)/",
"replacement": "/cgi-bin/anothersite.example$1"
}
]
},
{
"definingRegex": "/^\\/(?:cgi-bin\\/)?(?:website\\.example|anothersite\\.example)(?:$|[\\/#?])/",
"replacements": [
{
"regex": "/(.*)/",
"replacement": "/NONEXISTENT_PAGE"
}
]
}
],
"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
}
]
}
If you're using SVR.JS 3.14.0 or newer, you can use this configuration:
{
"users": [],
"port": 80,
"pubport": 80,
"page404": "404.html",
"blacklist": [],
"nonStandardCodes": [
{
"url": "/anothersite.example/dl",
"location": "/download",
"host": "anothersite.example",
"scode": 301
},
{
"url": "/anothersite.example/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": "/^\\/anothersite.example\\/index(?:$|[\\/#?])/",
"host": "anothersite.example".
"replacements": [
{
"regex": "/^\\/anothersite.example\\/index/",
"replacement": "/anothersite.example/"
}
]
},
],
"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
}
],
"wwwrootPostfixesVHost": [
{
"host": "website.example",
"postfix": "website.example",
"skipRegex": "/^\\/.dirimages(?:$|[\\/#?]))/"
},
{
"host": "anothersite.example",
"postfix": "anothersite.example",
"skipRegex": "/^\\/.dirimages(?:$|[\\/#?]))/"
}
{
"postfix": "NONEXISTENT_SITE"
}
],
"wwwrootPostfixPrefixesVHost": [
"/cgi-bin"
]
}
You need to then create this directory structure in SVR.JS web root:
- cgi-bin
- website.example
- anothersite.example
- website.example
- anothersite.example
If you want to still use SVR.JS server-side JavaScript (not including SVR.JS mods implementing specific web applications) and virtual hosts simultaneously, path checks need to correspond to rewritten URLs (those processed by URL rewriting engine).
For some SVR.JS mods, path settings may correspond to URLs processed by URL rewriting engine.
It is not recommended to use global custom head and foot (head.html, foot.html, .head, .foot) with this setup, because they will apply to all virtual hosts (doesn't include custom heads and feet for directory listings [.dirhead, .dirfoot], which apply to only one directory).
Client-initiated secure renegotiation
Client-initiated secure renegotiation may pose DoS risks. However, Node.JS (JS runtime on which SVR.JS is running on) has built-in protection against DoS attacks caused by client-initiated secure renegotiation. Such attacks can be detected by looking for ERR_TLS_SESSION_ATTACK errors in server log.
Mods
Mods in SVR.JS are custom modules that can extend the server's functionality. Using mods, you can extend SVR.JS functionality to suit your specific requirements and customize the server's behavior to handle different types of requests.
Installing mods
To install mod to SVR.JS, copy the mod to mods directory inside SVR.JS installation directory. SVR.JS searches this directory for mods, loads and executes them in alphabetical order (by mod file name). If you want have mods to be executed in specific order, add numeric prefix to mod file name, for example "01-redbrick.cgi.2.3.3.tar.gz" and "00-easywaf.integration.1.1.2.tar.gz".
Mod format
SVR.JS mods are JavaScript files, they work in SVR.JS 4.x and newer
Older SVR.JS mods are tar archives with gzip compression, they work in SVR.JS 2.x and newer.
SVR.JS 1.x used custom svrmodpack archives with gzip compression (they worked up to SVR.JS 3.13.0), but this format is deprecated for new mods, and may be no longer supported in future versions of SVR.JS, since svrmodpack is not maintained anymore. All current SVR.JS mods are now in tar.gz format. SVR.JS 3.13.0 dropped support for svrmodpack.
Mod loading order
Startup
- Search for mods
- For each mod (sorted alphabetically by mod file name):
- .js mods
- Initialize mod, and add mod along with mod info to list
- .tar.gz mods
- Prepare temporary directory for extracted mod contents
- Extract mod contents
- Initialize mod, and add mod along with mod info to list
- .js mods
- Load server-side JavaScript:
- Create mod file from server-side JavaScript
- Initialize "mod", and add "mod" to list
Execution (on each server request)
- Initialize SVR.JS variables
- Invoke mods and server-side JavaScript (mods sorted alphabetically by mod file name)
- Load SVR.JS main callback (if it's not affected by mods and server-side JavaScript)
Mod files (.tar.gz mods)
- index.js - main script for mod
- mod.info - information about mod
- other files necessary for the mod
Mod development (.js mods)
This section provides a comprehensive guide on developing .js
mods for SVR.JS. Mods allow you to extend the functionality of SVR.JS by writing custom JavaScript code.
Mod callback
The main export of the mod is a callback function that handles HTTP requests. This function takes the following parameters:
req
- the request object.res
- the response object.logFacilities
- logging facilities provided by SVR.JS.config
- the configuration object.next
- a function to pass control to the next request handler.
You should implement a proxy URL check in the callback, if you're going to use proxy
callback (or set proxySafe
in the exports to true
) and main callback at once, or else your SVR.JS mod may be vulnerable to access control bypass attacks (SVR.JS doesn't enforce URL rewriting, custom headers and non-standard codes for proxy requests to avoid interference of its access controls with proxy mods).
Commands
Mods can also export commands that can be invoked from the SVR.JS console. The commands
object maps command names to functions that handle the command logic.
Each command takes the following parameters:
args
- the arguments for the commandlog
- the logging function for the commandpassCommand
- a function to pass control to the next command handler.
Proxy handling
Mods can handle proxy requests by exporting a proxy
function. This function takes the following parameters:
req
- the request object.socket
- the socket object.head
- the head object.logFacilities
- logging facilities provided by SVR.JS.config
- the configuration object.next
- a function to pass control to the next proxy handler.
Required in order for the main callback to be invoked for request URLs beginning with "http://" or with "https://" (proxy through GET or POST method, non-proxy requests have request URLs beginning with "/").
You can also set proxySafe
in the exports to true
, in order to have the same effect described above.
IPC listener
Mods can communicate with the main process using IPC (Inter-Process Communication). The process.messageEventListeners
array allows you to add listeners for messages received by the main process.
You can add the wrapper for the listener for messages received by main process, which takes these parameters:
worker
- worker who sent the messageserverconsole
- logging facilities provided by SVR.JS.
The wrapper returns a function, which takes the message
parameter, which means the message sent by the worker.
Control messages received by main process begin with 0x12 control character. Control messages sent by main process begin with 0x14 control character.
The reserved control messages, used internally by SVR.JS begin with:
\x12AUTHQ
\x12AUTHR
\x12AUTHW
\x12CLOSE
\x12END
\x12ERRCRASH
\x12ERRLIST
\x12KILLOK
\x12KILLTERMMSG
\x12LISTEN
\x12PINGOK
\x12SAVEERR
\x12SAVEGOOD
\x14AUTHA
\x14AUTHD
\x14KILLPING
\x14KILLREQ
\x14PINGPING
\x14SAVECONF
Paths
process.dirname
refers to the SVR.JS installation directory.
Current working directory (process.cwd()
) is SVR.JS web root.
Get started
To get started with the development of the mod, clone the Git repository for the SVR.JS mod starter:
git clone https://git.svrjs.org/svrjs/svrjs-mod-starter.git
Further instructions can be found in the README
file in the SVR.JS mod starter repository.
Example mod
Below is an example of index.js
code for a simple mod from SVR.JS mod starter that handles a /test.svr
endpoint and a /ping.svr
endpoint:
const cluster = require("./utils/clusterBunShim.js"); // Cluster shim for Bun
const { add } = require("./utils/helper.js"); // Require the addition module
const modInfo = require("../modInfo.json"); // SVR.JS mod information
// Exported SVR.JS mod callback
module.exports = (req, res, logFacilities, config, next) => {
if (req.parsedURL.pathname == "/test.svr") {
res.writeHead(200, "OK", {
"Content-Type": "text/plain"
});
res.end("2 + 2 = " + add(2,2));
} else if (req.parsedURL.pathname == "/ping.svr") {
if (!cluster.isWorker) {
// Invoke 500 Internal Server Error status code, if the process is not a worker
res.error(500, new Error("SVR.JS is running single-threaded, so this request is not supported"));
return;
}
// Ping OK message listener
const pingOKListener = (message) => {
if (message == "\x14MODPINGOK") {
process.removeListener("message", pingOKListener);
res.writeHead(200, "OK", {
"Content-Type": "text/plain"
});
res.end("OK");
}
};
// Listen to Ping OK messages
process.on("message", pingOKListener);
// Send Ping message
process.send("\x12MODPING");
} else {
next(); // Invoke other request handlers
}
};
// Exported command
module.exports.commands = {
somecmd: (args, log, passCommand) => {
log("Arguments: " + args.toString()); // Print arguments
passCommand(args, log) // Invoke other command handlers
}
};
// IPC listener for main process
// Control messages received by main process begin with 0x12 control character
// Control messages sent by main process begin with 0x14 control character
process.messageEventListeners.push((worker, serverconsole) => {
return (message) => {
if (message == "\x12MODPING") {
// Ping back
worker.send("\x14MODPINGOK");
}
}
});
module.exports.modInfo = modInfo;
The modInfo.json
file would look like this:
{
"name": "Example mod",
"version": "0.0.0"
}
Mod development (.tar.gz mods)
Mods in SVR.JS have two methods:
- callback - Invoked on non-CONNECT requests (includes proxy requests using GET or POST methods). Parameters (must be in this particular order, argument names given to match SVR.JS API documentation):
- req
- res
- serverconsole
- responseEnd
- href
- ext
- uobject
- search
- defaultpage
- users
- page404
- head
- foot
- fd
- elseCallback
- configJSON
- callServerError
- getCustomHeaders
- origHref
- redirect
- parsePostData
- authUser
This method is required (if it is not present, SVR.JS will simply return 500 Internal Server Error on all requests with error message in error stack similar to "TypeError: modO.callback is not a function").
- proxyCallback - Invoked on CONNECT requests (used for proxying). Parameters (must be in this particular order, argument names given to match SVR.JS API documentation):
- req
- socket
- head
- configJSON
- serverconsole
- elseCallback
Required in order for function returned from callback method to be invoked for request URLs beginning with "http://" or with "https://" (proxy through GET or POST method, non-proxy requests have request URLs beginning with "/"). You should implement a proxy URL check in callback method, if you're going to use proxyCallback and callback methods at once, or else your SVR.JS mod may be vulnerable to access control bypass attacks (SVR.JS doesn't enforce URL rewriting, custom headers and non-standard codes for proxy requests to avoid interference of its access controls with proxy mods).
These methods are defined inside Mod.prototype object. Both methods return a function, which will be executed in SVR.JS.
__dirname
and . in require()
function both refer to directory, to which mod contents are extracted.
The reference to file in the SVR.JS installation directory is __dirname + "/../../../filename"
(replace filename
with your desired file name).
Current working directory (process.cwd()
) is SVR.JS web root.
A typical index.js file for a mod may look like this:
//Requires go here
function Mod() {}
Mod.prototype.callback = function callback(req, res, serverconsole, responseEnd, href, ext, uobject, search, defaultpage, users, page404, head, foot, fd, elseCallback, configJSON, callServerError, getCustomHeaders, origHref, redirect, parsePostData) {
return function () {
//Mod contents go here
if (href == "/hello.svr") {
serverconsole.resmessage("Sent Hello World message!");
res.writeHead(200, "OK", {
"Content-Type": "text/plain"
});
res.end("Hello World!");
} else {
elseCallback();
}
}
}
//OPTIONAL: proxyCallback method
//Uncomment code below, if you want to use proxyCallback method.
//But then you'll need to implement proxy request URL check for callback method.
/*
Mod.prototype.proxyCallback = function proxyCallback(req, socket, head, configJSON, serverconsole, elseCallback) {
return function () {
//Just pass elseCallback
elseCallback();
}
}
*/
module.exports = Mod; //SVR.JS mod exports
The mod.info file (in JSON format) contains metadata about the mod, such as its name and version:
{
"name": "The Example Mod",
"version": "0.1.0"
}
Server-side JavaScript
Another way to expand SVR.JS functionality is through server-side JavaScript located in serverSideScript.js file inside SVR.JS web root (or locaten in SVR.JS installation directory if you're running SVR.JS 3.9.0 or newer, and you have set useWebRootServerSideScript property to false). Server-side JavaScript allows you to create various web applications using JavaScript, Node.JS and SVR.JS API.
Predefined objects
When working with server-side JavaScript in SVR.JS, you have access to several predefined objects that can greatly enhance your scripting capabilities. These objects are available for use without requiring any additional imports or installations.
- readline: The readline library for reading input streams.
- os: The os library for accessing operating system-related information.
- http: The http library for handling HTTP functionality.
- url: The url library for parsing and formatting URLs.
- fs: The fs library for interacting with the file system.
- path: The path library for working with file and directory paths.
- hexstrbase64: The hexstrbase64 library for converting hexadecimal strings to base64 format.
- crypto: The crypto library for cryptographic functionality, such as generating hashes and handling encryption.
- https: The https library, an extension of the http library for handling secure HTTPS connections.
- stream: The stream library for working with streams of data.
- customvar1, customvar2, customvar3, customvar4: Custom variables meant to be reused in multiple requests. These variables are available starting from SVR.JS version 3.0.0.
Additionally, there is an option to control the automatic execution of the elseCallback function. By default, automatic execution is enabled. You can use the disableEndElseCallbackExecute option to disable this behavior if needed.
By leveraging these predefined objects, you can streamline your server-side JavaScript code and build powerful applications using SVR.JS.
Predefined methods
See methods in SVR.JS API in non-proxy section
Additionally SVR.JS server-side JavaScript has filterHeaders(headers)
method, that filters out invalid request headers.
SVR.JS 3.8.0 and newer have additionally two methods:
checkHref(destHref)
- checks if request path name matches the destHref.checkHostname(hostname)
- checks if host name defined in the request matches the hostname parameter.
SSJS development
__dirname
and . in require()
function both refer to temp directory in SVR.JS.
Current working directory (process.cwd()
) is SVR.JS web root.
If you want to divide server-side JavaScript into several files, you can do one of those:
require(process.cwd() + "/someOtherScript.js")
for script located in the web root (it's recommended to set up 403 Forbidden or 404 Not Found non-standard code in SVR.JS configuration to prevent source code leaks).require("../someOtherScript.js")
for script located in SVR.JS installation directory.require("/usr/lib/webappfiles/someOtherScript.js")
for script located in /usr/lib/webappfiles.
Example code:
disableEndElseCallbackExecute = true; //Without "var", else it will not work!!!
if (href == "/hello.svr") {
serverconsole.resmessage("Sent Hello World message!");
res.writeHead(200, "OK", {
"Content-Type": "text/plain"
});
res.end("Hello World!");
} else {
elseCallback();
}
Migration to SVR.JS
If you have previously built your web application using the Node.JS http library, Express framework, or Koa framework, you can easily migrate that code to SVR.JS server-side JavaScript.
From Node.JS http library
For applications built with the Node.JS http library, you can simply copy the contents of the request event listener to the SVR.JS server-side JavaScript. However, make sure to consider the disableEndElseCallbackExecute option to ensure proper execution flow.
disableEndElseCallbackExecute = true; //Without "var", else it will not work!!!
// Node.JS http library request event listener code goes here.
if(req.url == "/" && req.method == "GET") {
res.writeHead(200, "OK", {
"Content-Type": "text/plain"
});
res.end("Hello World!");
return;
}
elseCallback(); // Optionally, invoke main SVR.JS callback.
From Express Framework
If your application is built using the Express framework, you can easily migrate it to SVR.JS. You can mix Express methods with SVR.JS methods for more flexibility.
disableEndElseCallbackExecute = true; //Without "var", else it will not work!!!
var express = require("express");
// Other requires go here.
var app = express(); // Initialize express app
// Express application code goes here!
app.get("/", function (req, res) {
res.send("Hello World!");
});
app.use(elseCallback); // Optionally, if you want the main SVR.JS callback.
app(req, res); // Invoke Express handler
From Koa Framework
Migrating from the Koa framework to SVR.JS is also straightforward. Here's an example of how you can do it:
disableEndElseCallbackExecute = true; //Without "var", else it will not work!!!
var koa = require("koa");
// Other requires go here.
var app = new koa(); // Initialize Koa app
// Koa application code goes here!
app.use(function (ctx, next) {
if (ctx.method != "GET" || ctx.path != "/") {
next(); // Koa router could be used...
} else {
ctx.body = "Hello World!";
}
});
// Optionally, if you want the main SVR.JS callback (not recommended by Koa, as it passes Node.JS req and res objects).
app.use(function (ctx) {
ctx.respond = false;
elseCallback(ctx.req, ctx.res);
});
(app.callback())(req, res); // Invoke Koa handler
By migrating your web application to SVR.JS, you can take advantage of its features and performance enhancements, while still preserving your existing codebase.
SVR.JS API (.js mods)
SVR.JS has its API for .js mods that expands its functionality. SVR.JS API extends vanilla Node.JS HTTP API.
Error handling
When a JavaScript error is thrown outside of event callbacks, SVR.JS will return a 500 error to the client. Inside event callbacks, SVR.JS will simply crash.
Incorrect Error Handling:
//XXX WARNING!!! IT WILL CRASH THE SVR.JS!!!
//It also contains path traversal vulnerability!
module.exports = (req, res, logFacilities, config, next) => {
let headers = config.getCustomHeaders();
headers["Content-Type"] = "text/html; charset=utf8";
if (req.parsedURL.pathname == "/page.svr") {
fs.readFile(".template", (err, data) => {
if (err) throw err; //EVIL!!!
let id = req.parsedURL.query.id;
if (!id) id = "index";
if (fs.existsSync("pages/" + id + ".html")) {
fs.readFile("pages/" + id + ".html", (err2, data2) => {
if (err2) throw err2; //EVIL TWO!!!
res.writeHead(200, "OK", headers);
res.end(data.toString().replace("{websiteContents}", data2.toString()));
});
} else {
res.error(404);
}
});
} else if (href == "/") {
res.redirect("/page.svr");
} else {
next();
}
};
module.exports.modInfo = {
name: "Custom server-side JavaScript",
version: "0.0.0"
};
Instead, you should handle errors gracefully using res.error
function:
Correct Error Handling:
//Much better!
module.exports = (req, res, logFacilities, config, next) => {
let headers = config.getCustomHeaders();
headers["Content-Type"] = "text/html; charset=utf8";
if (req.parsedURL.pathname == "/page.svr") {
fs.readFile(".template", (err, data) => {
if (err) {
res.error(500, err);
return;
}
let id = req.parsedURL.query.id;
if (!id) id = "index";
id = id.replace(/\\/g,"/").replace(/(?:\/|^)\.\.(?=(\/|$))/g,"$1").replace(/\/+/g,"/"); //Poor mans path sanitiation
if (fs.existsSync("pages/" + id + ".html")) {
fs.readFile("pages/" + id + ".html", (err2, data2) => {
if (err2) {
res.error(500, err2);
return;
}
res.writeHead(200, "OK", headers);
res.end(data.toString().replace("{websiteContents}", data2.toString()));
});
} else {
res.error(404);
}
});
} else if (href == "/") {
res.redirect("/page.svr");
} else {
next();
}
};
module.exports.modInfo = {
name: "Custom server-side JavaScript",
version: "0.0.0"
};
By using res.error
, you can handle errors effectively and provide appropriate error responses to the client, preventing SVR.JS from crashing due to unhandled exceptions.
Main callback API (module.exports
)
Added in SVR.JS 4.0.0
This API includes proxy requests, which don't use CONNECT method. It's possible to determine, if the request comes from the proxy with req.isProxy
property.
SVR.JS applies mods for request URLs beginning with "http://" or with "https://" (proxy through GET or POST method, non-proxy requests have request URLs beginning with "/") only if module.exports.proxy method is present or if module.exports.proxySafe property is set to true
.
req
Added in SVR.JS 4.0.0
req object is almost same, as req object in Node.JS
req.socket.realRemoteAddress
Added in SVR.JS 4.0.0
A property containing IP address, from which request originally went from, if request is sent through reverse proxy.
You can specify generic request IP variable using const reqip = req.socket.realRemoteAddress ? req.socket.realRemoteAddress : req.socket.remoteAddress
req.socket.realRemotePort
Added in SVR.JS 4.0.0
A property containing port number, from which request originally went from, if request is sent through reverse proxy. (for X-Forwarded-For header, it will be null)
You can specify generic request IP variable using const reqip = req.socket.realRemotePort ? req.socket.realRemotePort : req.socket.remotePort
req.socket.originalRemoteAddress
Added in SVR.JS 4.0.0
A property containing IP address, from which proxy request came from. If the request isn't a proxy request, it will be undefined
.
req.socket.originalRemotePort
Added in SVR.JS 4.0.0
A property containing port number, from which proxy request came from. If the request isn't a proxy request, it will be undefined
.
req.url
Added in SVR.JS 4.0.0
A property containing request URL after all processing (URL rewriting too).
req.parsedURL
Added in SVR.JS 4.0.0
A property containing parsed request URL created by a custom URL parser (compatible with legacy URL parser: url.parse()
)
req.originalParsedURL
Added in SVR.JS 4.0.0
A property containing parsed request URL (before URL rewriting) created by new URL()
constructor (WHATWG URL parser)
req.isProxy
Added in SVR.JS 4.0.0
A property that determines if request is a proxy request or not.
req.authUser
Added in SVR.JS 4.0.0
The name of authenticated HTTP user. If the user wasn't authenticated, the property would be null.
res
Added in SVR.JS 4.0.0
res object is almost same, as res object in Node.JS
res.socket.realRemoteAddress
Added in SVR.JS 4.0.0
A property containing IP address, from which request originally went from, if request is sent through reverse proxy.
You can specify generic request IP variable using const reqip = req.socket.realRemoteAddress ? req.socket.realRemoteAddress : req.socket.remoteAddress
res.socket.realRemotePort
Added in SVR.JS 4.0.0
A property containing port number, from which request originally went from, if request is sent through reverse proxy. (for X-Forwarded-For header, it will be null)
You can specify generic request IP variable using const reqip = req.socket.realRemotePort ? req.socket.realRemotePort : req.socket.remotePort
res.socket.originalRemoteAddress
Added in SVR.JS 4.0.0
A property containing IP address, from which proxy request came from. If the request isn't a proxy request, it will be undefined
.
res.socket.originalRemotePort
Added in SVR.JS 4.0.0
A property containing port number, from which proxy request came from. If the request isn't a proxy request, it will be undefined
.
res.writeHead(statusCode[, statusMessage][, headers])
Added in SVR.JS 4.0.0
Parameters:
- statusCode - the response status code (String)
- statusMessage - the response status message (optional; String)
- headers - the response headers (optional; Object)
Returns: res property.
The difference between res.writeHead in Node.JS, and in SVR.JS is that in SVR.JS it writes into server log, doesn't invoke a warning about unused status code string, and if called multiple times will emit a warning, instead of throwing an error, which could crash SVR.JS.
res.setHeader(name, value)
Added in SVR.JS 4.0.0
Parameters:
- name - the response header name (String)
- value - the response header value (optional; String or Array)
The difference between res.setHeader in Node.JS, and in SVR.JS is that in SVR.JS it doesn't invoke a warning about HTTP/1.x headers being not allowed in HTTP/2.
Custom headers defined in config.json are set by default.
res.head
Added in SVR.JS 4.0.0
HTML head read from either .head or head.html file.
res.foot
Added in SVR.JS 4.0.0
HTML foot read from either .foot or foot.html file.
res.responseEnd(body)
Added in SVR.JS 4.0.0
Parameters:
- body - message you want to send before ending response (String or Buffer)
Sends response message (along with custom head and foot) specified by body parameter.
res.error(errorCode[, extName][, stack][, ch])
Added in SVR.JS 4.0.0
Parameters:
- errorCode - HTTP error code (Number)
- extName - extension name, which caused an error (optional; String)
- stack - error stack (optional; String or Error)
- ch - custom HTTP headers for error (optional; Object)
Invokes HTTP error code. If it's unavailable, invokes 501 error code.
res.redirect(dest[, isTemporary][, keepMethod][, headers])
Added in SVR.JS 4.0.0
Parameters:
- dest - destination of redirect (String)
- isTemporary - if true, then redirect with 302 code. Else redirect with 301 code. When keepMethod parameter is set to true, then redirect with 307 code, when isTemporary is true or with 308 code otherwise. (optional; Boolean)
- keepMethod - if true, then redirect with either 307 or 308 code. Else redirect with etiher 301 or 302 code. (optional; Boolean; SVR.JS 3.13.0 or later)
- headers - custom HTTP headers for redirect (optional; Object)
Redirects HTTP client to specific destination.
logFacilities
Added in SVR.JS 4.0.0
The log facilities for SVR.JS.
logFacilities.climessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends CLI message to server console.
logFacilities.reqmessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends request message to server console.
logFacilities.resmessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends response message to server console.
logFacilities.errmessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends response error message to server console.
logFacilities.locerrmessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends local error message to server console.
logFacilities.locwarnmessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends local warning message to server console.
logFacilities.locmessage(message)
Added in SVR.JS 4.0.0
Parameters:
- message - message you want to send to server console (String)
Sends local message to server console.
config
Added in SVR.JS 4.0.0
This object contains properties from config.json file.
config.getCustomHeaders()
Added in SVR.JS 4.0.0
Returns: Object property contains custom headers.
This methods retrieves custom headers from config.json file. Returned object additionally includes Server header.
config.generateServerString()
Added in SVR.JS 4.0.0
Returns: The generated server string.
This methods generated the string which is used to identify a web server (the same string as in the "Server" header).
next()
Added in SVR.JS 4.0.0
Invokes next SVR.JS mod callback, SVR.JS server-side JavaScript callback or main SVR.JS callback.
Proxy callback API (module.exports.proxy
)
Added in SVR.JS 4.0.0
req
Added in SVR.JS 4.0.0
req object is the same, as req object in Node.JS
socket
Added in SVR.JS 4.0.0
socket object is the same, as socket object in Node.JS
head
Added in SVR.JS 4.0.0
head object is the same, as head object in Node.JS
logFacilities
Added in SVR.JS 4.0.0
See logFacilties in main callback API
config
Added in SVR.JS 4.0.0
See config in main callback API
next()
Added in SVR.JS 4.0.0
See next in main callback API
Global variables (for use in callback APIs)
process.versions.svrjs
Added in SVR.JS 4.0.0
A property containing SVR.JS version.
process.serverConfiguration
Added in SVR.JS 4.0.0
A property containing SVR.JS configuration from config.json file.
process.dirname
Added in SVR.JS 4.0.0
A property containg the SVR.JS installation directory.
process.filename
Added in SVR.JS 4.0.0
A property containg the path to the SVR.JS script.
process.err4xxcounter
Added in SVR.JS 4.0.0
A property containg the count of 4xx HTTP errors.
process.err5xxcounter
Added in SVR.JS 4.0.0
A property containg the count of 5xx HTTP errors.
process.reqcounter
Added in SVR.JS 4.0.0
A property containg the count of HTTP requests.
process.malformedcounter
Added in SVR.JS 4.0.0
A property containg the count of malformed HTTP requests.
SVR.JS API (.tar.gz mods and server-side JavaScript)
SVR.JS has its API for both .tar.gz mods and server-side JavaScript that expands its functionality. SVR.JS API extends vanilla Node.JS HTTP API.
Error handling
When a JavaScript error is thrown outside of event callbacks, SVR.JS will return a 500 error to the client. Inside event callbacks, SVR.JS will simply crash.
Incorrect Error Handling:
//XXX WARNING!!! IT WILL CRASH THE SVR.JS!!!
//It also contains path traversal vulnerability!
disableEndElseCallbackExecute = true; //Without "var", else it will not work!!!
var headers = getCustomHeaders();
headers["Content-Type"] = "text/html; charset=utf8";
if(href == "/page.svr") {
fs.readFile(".template", function(err, data) {
if(err) throw err; //EVIL!!!
var id = uobject.query.id;
if(!id) id = "index";
if(fs.existsSync("pages/" + id + ".html")) {
fs.readFile("pages/" + id + ".html", function(err2, data2) {
if(err2) throw err2; //EVIL TWO!!!
res.writeHead(200,"OK", headers);
res.end(data.toString().replace("{websiteContents}",data2.toString()));
});
} else {
callServerError(404);
}
});
} else if(href == "/") {
redirect("/page.svr");
} else {
elseCallback();
}
Instead, you should handle errors gracefully using callServerError function:
Correct Error Handling:
//Much better!
disableEndElseCallbackExecute = true; //Without "var", else it will not work!!!
var headers = getCustomHeaders();
headers["Content-Type"] = "text/html; charset=utf8";
if(href == "/page.svr") {
if(fs.existsSync(".template")) {
fs.readFile(".template", function(err, data) {
if(err) {
callServerError(500,err);
return;
}
var id = uobject.query.id;
if(!id) id = "index";
id = id.replace(/\\/g,"/").replace(/(?:\/|^)\.\.(?=(\/|$))/g,"$1").replace(/\/+/g,"/"); //Poor mans path sanitiation
if(fs.existsSync("pages/" + id + ".html")) {
fs.readFile("pages/" + id + ".html", function(err2, data2) {
if(err2) {
callServerError(500,err2);
return;
}
res.writeHead(200,"OK", headers);
res.end(data.toString().replace("{websiteContents}",data2.toString()));
});
} else {
callServerError(404);
}
});
} else {
callServerError(500, new Error("Server is misconfigured - .template file missing"));
}
} else if(href == "/") {
redirect("/page.svr");
} else {
elseCallback();
}
By using callServerError
, you can handle errors effectively and provide appropriate error responses to the client, preventing SVR.JS from crashing due to unhandled exceptions.
Non-proxy API
This API is exposed both to mods and server-side JavaScript. This API also includes proxy requests, which don't use CONNECT method. It's possible to determine, if the request comes from the proxy, by checking if req.url begins with "http://" or with "https://" (unlike non-proxy requests, for which req.url begins with "/") like this:
var isProxy = (req.url && req.url.match(/^https?:\/\//));
SVR.JS applies mods for request URLs beginning with "http://" or with "https://" (proxy through GET or POST method, non-proxy requests have request URLs beginning with "/") only if Mod.prototype.proxyCallback method is present (not possible with SVR.JS server-side JavaScript).
req
req object is almost same, as req object in Node.JS
Differences:
- req.socket.realRemoteAddress and req.socket.realRemotePort will contain IP address, from which request originally went from, if request is sent through reverse proxy (for X-Forwarded-For header, req.socket.realRemotePort will be null). You can specify generic request IP variable using
var reqip = req.socket.realRemoteAddress ? req.socket.realRemoteAddress : req.socket.remoteAddress
(from SVR.JS 3.4.4) - req.socket.originalRemoteAddress and req.socket.originalRemotePort will contain IP address, from which proxy request came from.
- req.url refers to request URL after all processing (URL rewriting too)
res
res object is almost same, as res object in Node.JS
Differences:
- res.socket.realRemoteAddress and res.socket.realRemotePort will contain IP address, from which request originally went from, if request is sent through reverse proxy. (for X-Forwarded-For header, req.socket.realRemotePort will be null; from SVR.JS 3.4.4)
- res.socket.originalRemoteAddress and res.socket.originalRemotePort will contain IP address, from which proxy request came from.
- res.writeHead writes into server log.
- res.writeHead doesn't invoke a warning about unused status code string.
- res.setHeader doesn't invoke a warning about HTTP/1.x headers being not allowed in HTTP/2.
- res.writeHead called multiple times will emit a warning, instead of throwing an error, which could crash SVR.JS.
- Custom headers defined in config.json are set by default.
serverconsole.climessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends CLI message to server console.
serverconsole.reqmessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends request message to server console.
serverconsole.resmessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends response message to server console.
serverconsole.errmessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends response error message to server console.
serverconsole.locerrmessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends local error message to server console.
serverconsole.locwarnmessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends local warning message to server console.
serverconsole.locmessage(message)
Parameters:
- message - message you want to send to server console (String)
Sends local message to server console.
responseEnd(body)
Parameters:
- body - message you want to send before ending response (String or Buffer)
Sends response message (along with custom head and foot) specified by body parameter.
href
Path name of resource defined in the request. Alias for uobject.pathname.
ext
Extension of resource defined in the request.
uobject
Parsed Url object created by url.parse() method (includes parsed query string).
SVR.JS 3.3.1 and newer include hostname of the server (3.3.1 to 3.14.x use wrapper over WHATWG URL API; 3.15.0 and newer use custom URL parser), older versions don't.
search
Query string of URL. Alias for uobject.search
defaultpage
WARNING! DEPRECATED IN SVR.JS 3.X OR NEWER
In SVR.JS 2.x it was alias for configJSON.defaultpage. In SVR.JS 3.x for backward compability it's always "index.html".
users
WARNING! DEPRECATED
Alias for configJSON.users
page404
Alias for configJSON.page404
head
HTML head read from either .head or head.html file.
foot
HTML foot read from either .foot or foot.html file.
fd
WARNING! This property has currently no use and it's reserved for new SVR.JS functions. Currently this property is an empty string.
elseCallback()
Invokes next SVR.JS mod callback, SVR.JS server-side JavaScript callback or main SVR.JS callback.
configJSON
Added in SVR.JS 3.0.0
Parsed object of config.json file.
SVR.JS 3.4.0 and newer has version property, that corresponds to server version, and productName property, which always is "SVR.JS".
callServerError(errorCode[, extName][, stack][, ch])
Added in SVR.JS 3.0.0
Parameters:
- errorCode - HTTP error code (Number)
- extName - extension name, which caused an error (optional; String)
- stack - error stack (optional; String or Error)
- ch - custom HTTP headers for error (optional; Object)
Invokes HTTP error code. If it's unavailable, invokes 501 error code.
getCustomHeaders()
Added in SVR.JS 3.0.0
Returns: Object property contains custom headers.
This methods retrieves custom headers from config.json file. Returned object additionally includes Server header.
origHref
Added in SVR.JS 3.0.0
Original path name before URL rewriting.
redirect(dest[, isTemporary][, keepMethod][, headers])
Added in SVR.JS 3.0.0
Parameters:
- dest - destination of redirect (String)
- isTemporary - if true, then redirect with 302 code. Else redirect with 301 code. When keepMethod parameter is set to true, then redirect with 307 code, when isTemporary is true or with 308 code otherwise. (optional; Boolean)
- keepMethod - if true, then redirect with either 307 or 308 code. Else redirect with etiher 301 or 302 code. (optional; Boolean; SVR.JS 3.13.0 or later)
- headers - custom HTTP headers for redirect (optional; Object)
Redirects HTTP client to specific destination.
parsePostData([options], callback)
Added in SVR.JS 3.0.0
Parameters:
- options - options to be passed to formidable (optional; Object)
- callback - callback to execute after parsing URL. (Function)
- err - error, which occurred in POST data parsing. If not occured, it's null (Error or null)
- fields - POST fields (Object)
- files - Files sent (Object)
A wrapper over formidable library, which is used for parsing request bodies of POST requests.
authUser
Added in SVR.JS 3.14.2
The name of authenticated HTTP user. If the user wasn't authenticated, the property would be null.
If you want to check if the request is authenticated in SVR.JS versions older than 3.14.2, you can use function shown below, that checks for an applicable 401 non-standard code in the server configuration:
function checkIfThereIsA401Rule() {
var actually401 = false;
function createRegex(regex) {
var regexObj = regex.split("/");
if (regexObj.length == 0) throw new Error("Invalid regex!");
var modifiers = regexObj.pop();
regexObj.shift();
var searchString = regexObj.join("/");
return new RegExp(searchString, modifiers);
}
if(configJSON.nonStandardCodes) {
configJSON.nonStandardCodes.every(function (nonscode) {
if (nonscode.scode == 401) {
if (nonscode.regex && (req.url.match(createRegex(nonscode.regex)) || href.match(createRegex(nonscode.regex)))) {
actually401 = true;
return true;
} else if (nonscode.url && (nonStandardCodes[i].url == href || (os.platform() == "win32" && nonStandardCodes[i].url.toLowerCase() == href.toLowerCase()))) {
actually401 = true;
return true;
}
}
return false;
});
}
return actually401;
}
Proxy API
Added in SVR.JS 3.4.21, 3.7.0
This API is exposed only to mods. It is invoked, when client connects with the server using CONNECT method.
This API was present from SVR.JS 3.0.0, however SVR.JS version older than 3.4.21 or 3.7.0 had a bug, which involves calling non-proxy callback, instead of proxy one. A workaround involves calling proxy callback over non-proxy one, when request uses CONNECT method (insert at beginning of non-proxy callback):
if(!res.writeHead) {
Mod.prototype.proxyCallback(req, res, serverconsole, responseEnd, href, ext)();
return;
}
req
Added in SVR.JS 3.4.21, 3.7.0
req object is the same, as req object in Node.JS
socket
Added in SVR.JS 3.4.21, 3.7.0
socket object is the same, as socket object in Node.JS
head
Added in SVR.JS 3.4.21, 3.7.0
head object is the same, as head object in Node.JS
configJSON
Added in SVR.JS 3.4.21, 3.7.0
See configJSON in non-proxy API
serverconsole
Added in SVR.JS 3.4.21, 3.7.0
See serverconsole in non-proxy API
elseCallback()
Added in SVR.JS 3.4.21, 3.7.0
See elseCallback in non-proxy API