🐑 Commons Host

Documentation

@commonshost/server

Host Options

Example:

module.exports = {
  hosts: [{
    domain: 'example.net',
    root: './build/site',
    fallback: { 200: './app.html' },
    directories: { trailingSlash: 'never' },
    accessControl: { allowOrigin: '*' },
    headers: [{ fields: { 'X-Frame-Options': 'deny' } }],
    manifest: [{ get: '/app.html', push: '/app.css' }]
  }]
}

Table of Contents

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.

Multiple sites on the same server can each have their own configuration.

Examples:

module.exports = {
  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.

module.exports = {
  hosts: [{
    root: './website'
  }]
}

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.

If no directory is auto-detected, the current working directory is used. A warning message is logged to indicate this fallback behaviour.

hosts[].fallback

Default: {} (no fallback)

An object mapping HTTP status code to file paths. The file path is served as response body. No HTTP redirect is used. Typically used for client-side routing or fancy 404 error pages.

Fallbacks are supported for:

Example for client-side routing (e.g. SPA or PWA):

module.exports = {
  hosts: [{
    fallback: { 200: './app.html' }
  }]
}

Example for "Not Found" error pages:

module.exports = {
  hosts: [{
    fallback: { 404: './page-not-found.html' }
  }]
}

hosts[].fallback.extensions

Default: ['', 'html']

An array of file extensions for which to allow the 200 fallback. This prevents client-side apps from serving a fallback page on broken resource links. The extension is parsed from the request URL path. The empty extension '' must be explicitly included to allow fallback on a path without file extension. Fallbacks on paths with a trailing slash are always allowed. An empty array allows any path, regardless of extension, to have the 200 fallback.

Example for client-side routing of all paths:

module.exports = {
  hosts: [{
    fallback: {
      200: './app.html',
      extensions: []
    }
  }]
}

Example for client-side routing of specific file types:

module.exports = {
  hosts: [{
    fallback: {
      200: './app.html',
      extensions: ['md', 'html', 'htm', 'php']
    }
  }]
}

hosts[].directories

Behaviour of directory paths in clean URLs.

hosts[].directories.resolve

Default: true

If true, URL paths are normalised by resolving their //, .., and . segments. A 308 permanent redirect response is generated to the resolved path.

If false, no server-side normalisation is performed, which may be useful for client-side routing.

hosts[].directories.trailingSlash

Default: 'always'

Enforces a consistent ending character for directory paths.

The value is a string that can be:

hosts[].accessControl

Settings related to Cross-Origin Resource Sharing (CORS). The server responds to OPTIONS method requests with the appropriate response headers to allow (or deny) third-party access.

hosts[].accessControl.allowOrigin

Default: '*'

If specified, sets this value as the Access-Control-Allow-Origin header on every response.

hosts[].headers[]

Sets custom HTTP response headers. The headers array contains header objects. Each header object has the fields and uri properties.

module.exports = {
  hosts: [{
    headers: [
      {
        fields: {
          'Content-Security-Policy': "default-src 'self'",
          'Feature-Policy': "payment 'none'",
          'Strict-Transport-Security': 'max-age=31536000',
          'Referrer-Policy': 'strict-origin-when-cross-origin',
          'X-Frame-Options': 'SAMEORIGIN',
          'X-XSS-Protection': '1; mode=block',
          'X-Content-Type-Options': 'nosniff'
        }
      },
      {
        uri: '/service-worker.js',
        fields: {
          'Service-Worker-Allowed': '/'
        }
      },
      {
        uri: '/scripts/{filename}.{hash}.js',
        fields: {
          'Cache-Control': 'public, max-age=31536000, immutable'
        }
      },
      {
        fields: {
          'Set-Cookie': ['foo=bar', 'bar=baz']
        }
      }
    ]
  }]
}

hosts[].headers[].fields

fields is a required object whose property names and values are the HTTP headers to set on the response.

Property names must be valid HTTP header field names. Only case-insensitive alphanumeric characters (A through Z, and 0 through 9) and hyphens (- dash) are allowed.

Example Validity
Referrer-Policy Allowed
:status Not Allowed

Values may contain named template segments in braces. The values are substituted using matches from the uri template.

Values may also be arrays of strings to set multiple headers with the same name.

hosts[].headers[].uri

uri is an optional string as a URI Template. The header fields are applied only if the request pathname matches the route.

If no uri property is set, the fields headers are applied to all responses.

hosts[].manifest

The manifest property declares which files or URLs need to be pushed as dependencies for any request. Using HTTP/2 Server Push (PUSH_PROMISE frames) can eliminate round trips between browser and server and speed up resource loading.

The manifest property type can be:

Example: Inline manifest

module.exports = {
  hosts: [{
    manifest: [
      // Example:
      {
        // When serving the homepage,
        get: '**/*.html',
        // push all CSS and JS files.
        push: ['**/*.css', '**/*.js']
      }
    ]
  }]
}

Example: External manifest file

Using an external file is useful when using a build tool that traces dependencies to automatically generate the manifest.

This example shows a static website in the ./dist directory. The first section runs the @commonshost/manifest command line interface (CLI) tool to trace all HTML/JS/CSS files for dependencies. The automatically generated manifest is stored as ./manifest. The second section shows a reference to this external manifest.

$ npx @commonshost/manifest generate ./dist ./manifest.json
module.exports = {
  hosts: [{
    manifest: './manifest.json'
  }]
}

hosts[].redirects[]

Create redirects from gone pages to new pages.

Custom redirects help preserve inbound links and maintain search engine rankings & optimisation (SEO). As a website's content changes, pages are often moved around. Redirects are used to avoid leaving broken links from external sites to your old pages.

Tip: Use a fallback page (See: hosts[].fallback) to capture inbound links to no-longer-existing pages. With proper analytics reporting you can build a list of the most frequently visited broken links, and redirect them somewhere more useful.

Examples:

module.exports = {
  hosts: [{
    redirects: [
      // Old page to new page
      { from: '/old/page', to: '/new/page' },

      // Old page to a different website
      { from: '/somewhere', to: 'https://new.example.net/other/site' },

      // Override the HTTP status code to use a temporary redirect
      { from: '/promotion', to: '/summer-special', status: 307 },

      // Use URI Template pattern matching to preserve variables
      { from: '/shop{?sort,product}',
        to: '/store/item{/product}{?sort}' }
    ]
  }]
}

hosts[].redirects[].from

from is a required string as a URI Template.

Only paths on the current site can be matched.

hosts[].redirects[].to

to is a required string as a URI Template.

This path may be relative to the current origin (a.k.a. domain name) or an absolute URL pointing to a different origin.

hosts[].redirects[].status

status is an optional integer from 300 through 399.

The default status code is 308 which means Permanent Redirect. Use 307 to generate a Temporary Redirect.

See the IANA list of assigned HTTP status codes: https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml