Develop, test, and deploy your secure static or dynamic personal web site with zero configuration.


Copy and paste the following command into your terminal. Before you pipe any script into your computer, always view the source code (Linux and macOS, Windows) and make sure you understand what it does.

Linux (x64 and Raspberry Pi)

wget -qO- | bash


curl -s | bash

Windows 10

iex(iwr -UseBasicParsing


site update


site uninstall


As a development server

You can use Site.js as a local development server with locally-trusted TLS certificates (no certificate warnings) on Linux, macOS, and Windows.

To start serving the current folder at https://localhost:


As a proxy server

Say you’re running Hugo locally at its default location (http://localhost:1313) and you want to test it via TLS:

site :1313

Now you can view it at https://localhost and even your live reload will work as Site.js in proxy mode also proxies WebSockets.

As a local development server with live sync of changes to your production server


Any changes in your current folder will be synced via rsync over ssh to You can customise all of those details by providing a fully-formed rsync remote connection string for the --sync-to option.

The sync feature is not available on Windows as a viable free and open rsync implementation does not exist for that platform.

As a testing server

To give others access to your server without running as a deployment server (daemon):

site @hostname

Similarly, can also test with proxy servers. For example, if you want to test your Hugo site from your phone, you can expose the local port at your hostname:

site :1313 @hostname

Then use, for example, ngrok (Pro+) to point a custom domain name to your temporary staging server. Make sure you set your hostname file (e.g., in /etc/hostname or via hostnamectl set-hostname <hostname> or the equivalent for your platform) to match your domain name. The first time you hit your server via your hostname it will take a little longer to load as your Let’s Encrypt certificates are being automatically provisioned by ACME TLS.

Note that on Windows, your full computer name is used as your hostname and you must put quotation marks around @hostname and @localhost, which you do not need to do on other platforms.

As a production server

site enable

The production server feature requires Linux with systemd. We use Site.js in production at Small Technology Foundation on Ubuntu 18.04 LTS.

Once your server is running, it will survive crashes and server restarts and you can use the following commands:

Dynamic sites

Easily add dynamic functionality to your static site or create a fully-dynamic site. Get started with PHP-like simplicity in JavaScript using simple DotJS (.js) files:

mkdir -p count/.dynamic
echo 'i=0; module.exports=(_, r)=>{r.end(`${++i}`)}' > count/.dynamic/index.js
site count

Hit https://localhost and refresh to see the counter update.

Congratulations, you just made your first fully-dynamic and secure DotJS site! (Seriously.)

Here’s a slightly more verbose version of index.js that’s easier to understand:

let counter = 0

module.exports = (request, response) => {
    .end(`<h1>You’ve visited ${++counter} time${counter > 1 ? 's': ''}.</h1>`)

If this reminds you of a route in Express, it’s because that’s exactly what it is.

The only difference is that you don’t have to write any other code or worry about anything else including installing Node.js, provisioning TLS certificates, ensuring your site automatically restarts on reboots, etc.

In addition to static routes and dynamic HTTPS routes, you can also specify WebSocket (WSS) routes in DotJS. You can also mix them as you please.

For example, to create a very basic chat app:

mkdir -p basic-chat/.dynamic/.wss
cat << EOF > basic-chat/.dynamic/.wss/chat.js
module.exports = function (client, request) { = this.setRoom(request)
  client.on('message', message => this.broadcast(client, message))
site basic-chat

To test it, open up two web browser windows and enter the following into the web developer (JavaScript) console on both of them:

socket = new WebSocket('wss://localhost/chat')
socket.onmessage = message => console.log(

The broadcast method, by default, has rudimentary client filtering and only sends a message to clients other than the one that originally sent the message and only to clients connected to the same route (or “room”). For a fully-documented version of the above example, see the source code for the Basic Chat example.

To run that example with a basic web interface, do the following and then visit https://localhost

git clone
cd app
site examples/wss-basic-chat

The WebSocket functionality is from our fork of express-ws (which in turn uses ws). Both of those links have more usage details.

For full details, see the Dynamic Sites documentation and view the examples.

Use as a module

npm i @small-tech/site.js

You can use Site.js as a module in your Node.js projects. See the API documentation for details.

Learn more

site help

See the docs for full details, like using custom error pages and cascading archives and the 404→302 technique for an evergreen web.

Site.js in production

The following sites run on Site.js:


Made with love by Small Technology Foundation (previously,

We are a tiny not-for-profit based in Ireland that makes tools for people like you – not for startups, enterprises, or governments – and is funded by people like you. If you like our work and want to help us exist, please fund us.

Site.js is Small Technology and the foundations of Tincan.