@http2/server πΈ
Static HTTP/2 webserver for single page apps and progressive web apps.- HTTP/2, HTTP/1.1, and HTTP/1.0
- Content encoding for Brotli and Gzip compression
- Server Push Manifests & Cache Digest
- Scalable, multi-processor clustering
- Auto-generate HTTPS certificate for localhost development
- Fallback for client side routing
- HTTP to HTTPS redirect
- CORS
- Immutable caching of revved files
Installation
npm i -g @http2/server
CLI
http2server <command> [options]
--version
, -v
Display the current version number.--help [command]
, -h [command]
List global or command-specific options.Command: start
Start the server as a long running process that spawns workers.Aliases:
run
, up
, launch
$PORT
The environment variable PORT
sets the network port for incoming HTTPS connections. This overrides https.port
in the configuration file.The unencrypted HTTP port, used for redirects, is derived by setting the last three digits set to
080
. E.g. HTTPS 8443
-> HTTP 8080
, HTTPS 443
-> HTTP 80
.--options [file]
Configuration file path. Defaults to: ./http2(|server|live)(.conf(ig)).js(on)
If no configuration file is found, the default configuration is. See the Configuration section for details.
--watch
/--no-watch
Defaults to false
, which is the same as specifying the --no-watch
option.The server maintains an in-memory index of all files. Compared to dynamic filesystem scanning, this dramatically improves performance when pushing many small files. However if files and directories are added, moved, or deleted, the index becomes incorrect. Pass the
--watch
option to monitor filesystem changes and automatically rebuild the index. This has some performance cost, depending on operating system specific support, so watching is disabled by default. Watching is typically only used in development mode, not production.Command: stop
Shuts down the server by sending it the SIGINT
signal.Aliases:
halt
, exit
, quit
, kill
, down
, end
Command: reload
Gracefully restart workers with a new configuration by sending the server the SIGHUP
signal.Aliases:
restart
, refresh
, renew
, update
, cycle
, load
Command: test
Loads and validates a server configuration.Aliases:
verify
, validate
, check
, configtest
, lint
--config [file]
Identical to the same option of the start
command.Signals
If the server is started from the command line, it can be controlled by sending process signals.SIGINT
Graceful shutdown of all workers and the master process.SIGHUP
Gracefully restart all workers with reloaded configurations.JavaScript API
Constructor
const {Master} = require('http2/server')
const server = new Master(configuration)
The
configuration
argument contains:options
: The server configuration object.generateCertificate
: Defaults tofalse
. Iftrue
, a self-signed, trusted certificate forDNS:localhost
is created on startup in casehttps.key
andhttps.cert
are missing.serveDefaultSite
: Defaults totrue
. Creates a fallback host configuration using default settings if nohosts
are explicitly configured. This is a convenience feature for CLI usage so that no configuration is needed by default.cwd
: Defaults to the current working directory (./
). File and directory paths in the configuration are relative to this path.
Starting
await server.listen()
Loads the configuration and spawns worker processes to listen for incoming connections. Also starts a redirecting server from HTTP to HTTPS.
Stopping
await server.close()
Shuts down the workers and redirecting server gracefully.
Reloading
await server.reload()
Starts new workers to gracefully replace the old ones without downtime. Reloads the configuration.
Run-Time Updates
await server.message(message)
Invalidates cached information about files, certificates, and configuration on a per-domain level. Used to update at run-time without the performance cost of a full reload. See Messaging for details.
Messaging API
Messages are used to notify the workers of changes without reloading them. This is more efficient than spawning workers.Messages can be sent programmatically, using the
.message(...)
method. Messages are also sent by the CLI (i.e. reload
, watch
, stop
commands) and the edge agent which receives them from the core api service.All messages require at least the
type
, domain
, and root
properties.type
identifies what kind of information is described. The supported types are defined below.domain
is the host name of the site to which this message applies.root
is the path of base directory containing the site's files.
Additionally, the
configuration
field contains a valid configuration document. Only the host options matching the domain
are applied, others are ignored.For example:
{
type: 'site-deploy',
domain: 'example.net',
root: '/var/www/html',
configuration: [{
domain: 'example.net',
fallback: {200: '/index.html'}
}]
}
Type: site-deploy
isNewDomain
Set totrue
if this domain name was not previously served. Otherwisefalse
. Not currently used.hasNewFiles
Set totrue
if any files are changed, added, or removed. Otherwisefalse
.hasNewConfiguration
Set to true if any option in the site configuration is modified.
{
type: 'site-deploy',
domain: 'example.net',
isNewDomain, // boolean
hasNewFiles, // boolean
hasNewConfiguration // boolean
}
Type: site-delete
A site has been removed. Clear any cached information for the domain.{
type: 'site-delete',
domain: 'example.net'
}
Type: configuration-update
New configuration options are used for the domain.{
type: 'configuration-update',
domain: 'example.net'
}
Type: file-delete
One or more files have been removed. Clear their cached information.{
type: 'file-delete',
domain: 'example.net',
files: [
{path: 'foo/bar.lol'},
{path: 'abc/def/ghi.jkl'},
{path: '123.xyz'}
]
}
Type: file-update
One or more files have been changed. Reset or reload their cached information.{
type: 'file-update',
domain: 'example.net',
files: [
{path: 'foo/bar.lol'},
{path: 'abc/def/ghi.jkl'},
{path: '123.xyz'}
]
}
Type: certificate-issue
A new certificate for the domain is available. Clear any previously cached certificate.{
type: 'certificate-issue',
domain: 'example.net'
}
Type: certificate-revoke
The previous certificate for the domain is no longer in use. Clear any cached information.{
type: 'certificate-revoke',
domain: 'example.net'
}
Configuration
See@http2/configuration
for the JSON Schema, validation, and normalisation tools.There are three layers in the configuration:
- Server Options: applies globally to all sites on the server
- **HTTP/2 Server Push Manifest**: also applies to a single domain, but defined as a separate specification
Server Options
signature
Default: true
Boolean value that adds the
Server:
header to all HTTP responses if true
, and omits that header if false
.The value of the header identifies the versions of the server, Node.js, nghttp2, and the operating system.
Often disabled for reasons of paranoia or placebo performance tuning.
acme
Settings related to the Automated Certificate Management Environment (ACME) protocol, i.e. support for the LetsEncrypt certificate authority. This affects all requests, across all hosted domains, where the pathname starts with /.well-known/acme-challenge/
. There are many ways to implement ACME support. These settings offer flexibility in issuing certificates and serving the correct certificate for each host.When a certificate is requested for a domain using the ACME HTTP challenge, the certificate authority (i.e. LetsEncrypt's Boulder server) resolves the given DNS hostname and makes an HTTP request. The webserver needs to respond with values only known by the entity that requested the certificate. In a simple case of one webserver this can be handled by serving a local directory through
acme.webroot
. But when DNS records point to multiple edge servers, it is necessary to relay or deflect the challenge request, via acme.proxy
or acme.redirect
respectively, to the certificate requesting entity.Any domains that do not have a certificate, as per
acme.key
and acme.cert
lookups, are served using the fallback certificate in https.key
and https.cert
.acme.proxy
Default: ''
If a valid URI is specified, the server proxies all ACME challenge requests to this upstream server.
Proxying requires the server to do more work than a redirect, but it is transparent to the CA. This allows use of ports other than
80
and 443
, to which Boulder is restricted.This string is prepended to the challenge request's URL path, so omit any trailing shash to avoid duplication. Both HTTP and HTTPS can be used, depending on the scheme (
http:
vs https:
).Example:
{
acme: {
proxy: 'https://vault.example.net:8443'
}
}
acme.redirect
Default: ''
If a valid URI is specified, the server redirects, through a
301 Permanent Redirect
response, all ACME challenge requests to this upstream server.Redirecting is light on the edge server, but requires a second connection from Boulder to the specified server, possibly adding some latency. Not that Boulder, the LetsEncrypt server, is currently restricted to ports
80
and 443
. Redirecting to any other ports is not supported, and should be handled through acme.proxy
.This string is prepended to the challenge request's URL path, so omit any trailing shash to avoid duplication. Both HTTP and HTTPS can be used, depending on the scheme, i.e.
http:
or https:
respectively.Example:
{
acme: {
redirect: 'https://vault.example.net:8443'
}
}
acme.webroot
Default: ''
If a valid path is specified, the server responds to challenges by mapping to static files in this directory. This is intended to work with the
webroot
option of many ACME clients, where files are generated during the challenge-response process.{
acme: {
webroot: '/var/www/html'
}
}
acme.store
Default: ''
Directory where keys and certificates are stored.
Example:
{
acme: {
webroot: '/etc/ssl'
}
}
acme.key
Default: '$store/$domain/key.pem'
Path to the domain-specific key file.
May contain substitution variables
$store
and $domain
.Example:
{
acme: {
key: '$store/sites/$domain/crypto/key.pem'
}
}
acme.cert
Default: '$store/$domain/cert.pem'
Path to the domain-specific certificate file.
May contain substitution variables
$store
and $domain
.Example:
{
acme: {
cert: '$store/sites/$domain/crypto/cert.pem'
}
}
log
Settings for the Pino-based logger.log.level
Default: 'info'
Minimum threshold for log messages to be recorded. One of
fatal
, error
, warn
, info
, debug
, trace
; or silent
to disable logging.http
An object containing settings for the automatic redirection of HTTP to HTTPS. This is necessary since HTTP/2 is only supported by browsers when using a TLS connection (TLS).http.redirect
Default: true
If
true
, an HTTP server listens to redirect requests to HTTPS.If
false
, no HTTP server is started. This also means ACME is disabled, since it is served over HTTP as well.http.from
Default: 8080
The port number where the HTTP server accepts connections.
http.to
Default: 8443
The port number of the HTTPS URLs to which HTTP traffic is redirected.
Redirects use the
308 Permanent Redirect
status code.https
Settings for the fallback TLS context that is used if no files match acme.key
and acme.cert
.Useful when serving subdomains using a wildcard certificate.
If no fallback exists on launch, a self-signed certificate and key pair is generated using tls-keygen. The certificate is attempted to be added to to the operating system trusted store, which may require user confirmation and entry of their password. This is only done in CLI mode, or if the
generateCertificate
API argument is true
; otherwise the server simply fails to launch.See the corresponding options of tls.createSecureContext.
https.key
Default: '~/.http2server/key.pem'
A string of the path to a PEM file containing the secret key.
https.cert
Default: '~/.http2server/cert.pem'
A string of the path to a PEM file containing the public certificate.
https.ca
Default: []
An array of strings containing the path to all files in the certificate chain.
https.port
Default: 8443
The TCP/IP port number for incoming TLS connections.
The standard HTTPS port is
443
for both HTTP/1.1 and HTTP/2. However, on Unix (Linux/MacOS), root permissions are required to listen on port numbers from 1 to 1024. The default value is outside this restricted range.workers
The server runs one master process that controls one or more worker processes. The workers process incoming requests and generate responses. Communication between the master and workers uses Node.js cluster module message passing.workers.count
Default: 'max_physical_cpu_cores'
The desired number of worker processes to spawn at launch. Must be a number or a mathematical expression that evaluates to a number.
Examples:
Single worker process:
workers: {
count: 1
}
Invalid: must spawn at least 1 worker.
workers: {
count: 0
}
One worker per CPU core:
workers: {
count: 'max_physical_cpu_cores'
}
Half as many workers as CPU cores:
workers: {
count: 'max_physical_cpu_cores / 2'
}
Leave one core for other processes:
workers: {
count: 'max_physical_cpu_cores - 1'
}
hosts
Default: []
An array of objects containing host options configurations.
Host Options
hosts[].domain
Default: ''
or 'localhost'
(only for the default site, see serveDefaultSite)The DNS hostname of the site. May be specified as an Internationalized Domain Name (IDN) containing non-ASCII characters.
Examples:
{
hosts: [
{ domain: 'example.net' },
{ domain: 'xn--yfro4i67o.example.net' },
{ domain: 'π¦.example.net' }
]
}
hosts[].root
The path to the base directory containing static files to serve.If no root is specified, the server tries to auto-detect static site generator or packaging tool output directories. For example:
./dist
, ./public
, ./_site
, and many more.hosts[].fallback
Default: {}
(no fallback)An object mapping HTTP status code to file paths.
Fallbacks are supported for:
200
to serve a missing file as a success response. Typically used for client side routing.404
to serve a missing file as an error response. Typically used for client side routing.
Example:
{
fallback: {
200: './index.html'
}
}
hosts[].cacheControl
Sets the HTTP caching headers.hosts[].cacheControl.immutable
Default: []
An array of path globs for immutable files.
Special named patterns can be used as shorthand. These are:
hex
β Matches hexadecimal hash revved files. Example:layout-d41d8cd98f.css
emoji
β Matches emoji revved files. Example:app.β½οΈ.js
By default, all non-immutable responses have the header:
cache-control: public, max-age=1, must-revalidate
File paths that match the patterns set by the
cacheControl.immutable
option are considered to never, ever change their contents. To tell browsers never to revalidate these resources, they are served with the header:cache-control: public, max-age=31536000, immutable
Examples:
{
cacheControl: {
immutable: [
'/library/v1.2.3/**/*.js'
]
}
}
hosts[].directories
Behaviour of directory paths.hosts[].directories.trailingSlash
Default: 'always'
Enforces a consistent clean URL for directory paths.
The value is a string that can be:
'always'
to use HTTP redirects to append a/
at the end of the directory name.'never'
to use HTTP redirects to strip any/
at the end of the directory name.
hosts[].accessControl
Settings related to CORS.hosts[].accessControl.allowOrigin
Default: '*'
If specified, sets this value as the
access-control-allow-origin
header on every response.hosts[].serviceWorker
Settings related to service workers.hosts[].serviceWorker.allowed
Default: '/'
If specified, sets this value as the
service-worker-allowed
header on every response.hosts[].strictTransportSecurity
Settings related to HTTP Strict Transport Security.hosts[].strictTransportSecurity.maxAge
Default: 5184000
(60 days)Sets this value as the
strict-transport-security
header on every response.hosts[].manifest
The manifest declares which files or URLs need to be pushed as dependencies for any request.See the HTTP/2 Server Push Manifest specification for details and examples.
Example: Push all CSS and JS files when serving the homepage.
{
hosts: [
domain: 'localhost',
root: './dist',
manifest: [
{
get: '**/*.html',
push: ['**/*.css', '**/*.js']
}
]
]
}
Tutorials
Server Push with Cache Digests
Page load time is a largely function of latency (round trip time Γ delays) and aggregate volume (number Γ size of assets).Latency is minimised by using HTTP/2 Server Push to deliver any necessary assets to the browser alongside the HTML. When the browser parses the HTML it does not need to make a round trip request to fetch styles, scripts, and other assets. They are already in its cache or actively being pushed by the server as quickly as network conditions allow.
Volume is reduced by using strong compression (HPACK, Brotli, etc), and by avoiding sending redundant data.
If all assets were pushed every time, a large amount of bandwidth would be wasted. HTTP/1 asset concatenation makes a tradeoff between reducing round trips (good) and re-transferring invalidated, large files (bad). For example having to re-tranfer an entire spritesheet or JavaScript bundle because of one little change.
The HTTP/1 approach was to use file signatures (Etags) and timestamps to invalidate cached responses. This requires many expensive round trips where the browser checks with the server if any files have been modified.
Cache Digests to the rescue! Using a clever technique, called Golomb-Rice Coded Bloom Filters, a compressed list of cached responses is sent by the browser to the server. Now the server can avoid pushing assets that are fresh in the browser's cache.
With Server Push and Cache Digests the best practice is to have many small files that can be cached and updated atomically, instead of large, concatenated blobs.
Browsers do not yet support cache digests natively so Service Workers and the Cache API are used to implement them. A cookie-based fallback is available for browsers that lack Service Worker support.
HTTPS Certificate
While the HTTP/2 specification allows unencrypted connections, web browsers strictly enforce HTTPS.If no certificate and key are provided, one pair will be auto-generated. The generated certificate is only valid for
localhost
. It is stored in ~/.http2server
. As a user convenience, the certificate is added as trusted to the operating system so browsers will accept the certificate. A password dialog may appear to confirm. This is currently only supported on macOS and Linux.In production use Let's Encrypt or any other trusted, signed certificate.
Intermediate certificates are stapled to the OCSP response to speed up the TLS handshake.
See Also
- http2.live β Static site hosting and CDN based on this server.
- Unbundle β Build tool for front-end JavaScript applications, designed for HTTP/2 Server Push and Cache Digests.