Complete Config · HTTP + HTTPS
Set only what should change.
Run HTTP, HTTPS-only, or both transports from one instance. Known nested objects merge with isolated defaults, and values are validated before listeners open.
Using configuration
Pass an object or use Config directly.
const {Server}=require('node-http-server');
const server=new Server({
host:'127.0.0.1',
port:8080,
root:'./public',
server:{
noCache:false,
allowDotfiles:false,
compression:true,
maxRequestBodyBytes:1048576
}
});
server.deploy();| API | Behavior |
|---|---|
new Server(values?) | Creates an instance with an isolated Config. |
server.deploy(values?) | Merges supplied values before deployment. |
new Config(values?) | Creates isolated configuration without deploying. |
config.merge(values) | Safely merges and returns the same Config instance. |
Config.defaults | Returns a fresh copy of all defaults. |
Config.mimeTypes | Returns a fresh built-in MIME map. |
const Config=require('node-http-server/config');
const mimeTypes=require('node-http-server/mime-types');import Config from 'node-http-server/config';
import mimeTypes from 'node-http-server/mime-types';Network, roots, and top-level state
Separate binding from Host routing.
| Key | Default | Purpose | Playground |
|---|---|---|---|
host | '127.0.0.1' | Address passed to listen(). | Location and host routing |
port | 8080 | HTTP port; 0 requests an ephemeral port. | Location and host routing |
root | process.cwd() | Default static root. | Location and host routing |
domain | '0.0.0.0' | Legacy primary Host check; host controls the bind address. | Location and host routing |
domains | {} | Additional hostname-to-root mappings. | Additional domains JSON |
verbose | false | Sanitized operational console output. | HTTP behavior |
server | table below | Static HTTP behavior and Node timeouts. | HTTP behavior + Timeouts |
https | empty values | Certificate paths and secure listener mode. | HTTPS |
contentType | built-in map | MIME additions/overrides, or false. | File types and restrictions |
restrictedType | {} | Truthy extension keys return 403. | File types and restrictions |
errors | built-in map | Error headers and status bodies. | Logging and errors |
log | false | NDJSON destination or logging off. | Logging and errors |
logBody | false | Include UTF-8 body in request records. | Logging and errors |
logFunction | built in | Custom request-record writer. | Module-only function stub |
host versus domain: host chooses the network interface. domain and domains choose accepted HTTP/1 Host or HTTP/2 :authority values and static roots. A mismatch returns 421.deploy() builds an O(1) table for domain, domains, and their canonical roots. Live root/domain assignments and domain-map changes invalidate it; the next request rebuilds the table with the current values.domain:'0.0.0.0' or domain:'*' selects the primary root before domains is consulted. Set a nonwildcard primary domain when using the map.new Server({
root:'./www/default',
domain:'example.test',
domains:{
'docs.example.test':'./www/docs',
'app.example.test':'./www/app'
}
}).deploy();Static server behavior
The server object.
| Key | Default | Purpose |
|---|---|---|
index | 'index.html' | File used for directory requests. There is no directory listing when it is absent. |
noCache | true | Sends no-cache/no-store/must-revalidate directives. false omits them; set cache lifetime headers through a hook or proxy. |
allowDotfiles | false | Only literal true allows dot-prefixed path segments. The default returns 403 before lookup or SPA fallback. |
compression | false | Negotiates Brotli/gzip for accepted compressible static responses through Node's built-in node:zlib; runtime dependencies stay at zero. Ranges and manual serve() responses retain their selected encoding. |
compressionThreshold | 1024 | Minimum uncompressed bytes before compression is considered. |
brotliQuality | 4 | Brotli quality from 0 through 11 for automatically compressed static responses through node:zlib. |
spaFallback | false | true uses index; a string chooses another root-relative file. |
timeout | 30000 | HTTP/1 socket or HTTP/2 session inactivity timeout in milliseconds. |
requestTimeout | 300000 | HTTP/1 whole-request timeout in milliseconds. |
headersTimeout | 60000 | HTTP/1 request-header timeout in milliseconds. |
keepAliveTimeout | 5000 | HTTP/1 keep-alive timeout in milliseconds. |
maxRequestBodyBytes | false | Maximum request bytes; false/0 is unlimited. |
404, for an extensionless path whose request accepts HTML or */*. Missing assets and non-HTML requests remain 404.allowDotfiles:true exposes every dot-prefixed segment in the selected root, including /.git, /.env, and /.well-known. Use a dedicated audited root.Limits and timeouts
Every disable value is explicit.
| Setting | false | 0 | Unit |
|---|---|---|---|
server.timeout | Disabled | Disabled | milliseconds |
server.requestTimeout | Disabled | Disabled | milliseconds |
server.headersTimeout | Disabled | Disabled | milliseconds |
server.keepAliveTimeout | Disabled | Disabled | milliseconds |
server.maxRequestBodyBytes | Unlimited | Unlimited | bytes |
contentType | Automatic map removed | Invalid map value | — |
null: false, null, and numeric 0 disable timeouts and the body cap through the module API. The CLI accepts false/off/0, not null.requestTimeout, headersTimeout, and keepAliveTimeout apply to HTTP/1 connections, including HTTPS fallback connections. They do not impose HTTP/2 stream deadlines. timeout controls HTTP/2 session inactivity.
File types and restrictions
Serve, reject, or use the binary fallback.
| Configuration | Result |
|---|---|
| No entry for extension | application/octet-stream. |
contentType:{md:'text/markdown; charset=utf-8'} | Adds or overrides that extension. |
contentType:{secret:false} | Filenames ending in .secret return 415 after path policy checks. |
contentType:false | Removes automatic mapping; served files use application/octet-stream. |
restrictedType:{key:true} | Filenames ending in .key return 403 after path policy checks. |
new Server({
contentType:{
md:'text/markdown; charset=utf-8',
secret:false
},
restrictedType:{
key:true,
pem:true
}
});Extension keys omit the leading dot. The built-in map is available through Config.mimeTypes or the node-http-server/mime-types package subpath. If an object is merged after contentType:false, the built-in defaults are restored first and then overlaid.
Error responses
Override headers or individual bodies.
| Key | Default / shape | Use |
|---|---|---|
errors.headers | Content-Type: text/plain; charset=utf-8, X-Content-Type-Options: nosniff | Headers applied to built-in error responses. |
errors[400] | '400 Bad Request' | Malformed request. |
errors[403|404|405] | Status text | Denied, missing, or unsupported method. |
errors[413|415|416|421|500] | Status text | Limit/type/range/Host/internal failures. |
new Server({
errors:{
headers:{'Content-Type':'application/json'},
404:'{"error":"not found"}'
}
});Logging
Append NDJSON or provide a writer.
| Key | Default | Behavior |
|---|---|---|
log | false | File path enables one JSON record per request line. |
logBody | false | Adds the UTF-8 request body when deliberately enabled. |
logFunction | built-in append writer | Receives the record with this bound to Config; may return a Promise. |
The built-in writer adds a timestamp without mutating its input and redacts common credential headers. Serialization/filesystem errors are captured. Protect log destinations and treat any stored request body as sensitive.
new Server({
log:true,
logFunction(data){
return sendRecordSomewhere(data);
}
});Native Node HTTP/2 over HTTPS
Supply key and certificate paths together.
Configured HTTPS defaults to HTTP/2 through node:http2.createSecureServer() with allowHTTP1:true. TLS negotiates HTTP/2 or HTTP/1.1 on the same port before requests begin. Plain HTTP remains HTTP/1.1. Node.js 22.12 or newer remains the runtime requirement, with zero runtime dependencies.
| Key | Default | Purpose |
|---|---|---|
https.ca | '' | Optional CA certificate path. |
https.privateKey | '' | Private-key path. |
https.certificate | '' | Certificate path. |
https.passphrase | false | Optional private-key passphrase. |
https.port | 443 | HTTPS port. |
https.only | false | Skip HTTP when HTTPS is configured. |
https.http2 | true | HTTP/2 with HTTP/1.1 negotiation; false selects the original node:https listener. |
const server=new Server({
host:'127.0.0.1',
https:{
privateKey:'/path/to/private.key',
certificate:'/path/to/certificate.pem',
port:8443,
only:true
}
});
server.deploy();server.secureServer is a Node Http2SecureServer by default. Set https.http2:false when the application requires the original https.Server type or HTTP/1-specific native APIs. https.only controls the separate plain HTTP listener, not the negotiated HTTP version. See the hook contract for HTTP/2 request/response compatibility.
Validation and merging
Invalid configuration fails before serving.
| Check | Failure |
|---|---|
| Non-plain Config object | TypeError. |
| Non-plain nested map | TypeError naming the key. |
__proto__, constructor, or prototype | Rejected as unsafe. |
| Port outside the integer range 0–65535 | Deployment throws. |
| Host empty | Deployment throws. |
| Invalid root/domain root (missing or non-directory) | Deployment throws. |
| Negative timeout/limit/threshold | Deployment throws. |
server.brotliQuality outside integer range 0–11 | Deployment throws. |
| Only one of HTTPS key/certificate set | Deployment throws. |
https.only:true without key/certificate | Deployment throws. |
Merge precedence is defaults, then constructor values, then later deploy()/merge() overlays. Known nested records shallow-overlay and omitted earlier values persist. Instances, Config.defaults, Config.mimeTypes, and user maps maintain independent mutable nested state. Unknown safe top-level keys remain application-owned metadata.