Running Network Infrastructure

This howto will walk you through downloading, configuring, and running a containerized setup that provides a bootstrap and signal/relay server for a Holochain application. This server is necessary to help peers discover each other and establish a direct peer-to-peer WebRTC connection, and it also provides a message relay service as a fallback in case a direct connection can’t be established.

The kitsune2 bootstrap server provides:

Any user-friendly hApp will need these services in order to operate.

Public server

The Holochain Foundation provides a public bootstrap server at https://dev-test-bootstrap2.holochain.org/ that you’re welcome to use for testing. It’s not appropriate for production hApps, though, because it’s low-bandwidth and has no uptime guarantees.

Requirements

Create a Docker compose file

Create a docker-compose.yaml file in an appropriate place in your server’s filesystem, then open it for editing. Here we’ll be storing the file in /opt/kitsune2-bootstrap and editing it in Vim:

sudo mkdir -p /opt/kitsune2-bootstrap
sudo touch /opt/kitsune2-bootstrap/docker-compose.yaml
sudo chown $(whoami) /opt/kitsune2-bootstrap/docker-compose.yaml
vim /opt/kitsune2-bootstrap/docker-compose.yaml

Copy this code into the file, edit the locations of your TLS certificate and key files, and save it.

services:
  bootstrap:
    image: ghcr.io/holochain/kitsune2_bootstrap_srv:v0.2.11
    command:
      - kitsune2-bootstrap-srv
      - --production
      - --listen
      - "[::]:443"
      # Replace these with actual paths to your cert and key files,
      # relative to the local volume mount point you specify further down.
      - --tls-cert
      - /etc/letsencrypt/live/bootstrap.example.org/fullchain.pem
      - --tls-key
      - /etc/letsencrypt/live/bootstrap.example.org/privkey.pem
    environment:
      - RUST_LOG=info
    ports:
      - "443:443"
    volumes:
        # Replace this with the path to the TLS certificate files on the host
        # and your desired mount point inside the container, in this format:
        # <host path>:<mount point>
      - /etc/letsencrypt/:/etc/letsencrypt/:ro
    restart: unless-stopped

Tuning the bootstrap server's performance

You can pass various parameters to kitsune2-bootstrap-srv to tune the relay performance. The sbd_server crate documentation shows the data structure; the tuning parameters are limit_clients onward. To pass them as arguments to the Docker container, prefix them with sbd and convert them to hyphen-case, like this:

# ...
    command:
      - kitsune2-bootstrap-srv
      - --sbd-limit-clients
      - 50
# ...

Run the container

Test the configuration:

docker compose up

You should see a lot of log messages, ending with this line:

bootstrap-1  | #kitsune2_bootstrap_srv#listening#[::]:443#

If you see this, you know your server is running and should be able to respond to requests from Holochain conductors. You can now run the container in detached/daemon mode:

docker compose up --detach

Running a production server

At this point your bootstrap server is ready for testing, but it probably isn’t ready for production use. Operating a production server is outside of the scope of this documentation, and will require thinking about things like securing the server, denial-of-service protection, handling container or server failures, monitoring, logging, etc. Here are things to know about the bootstrap server:

  • Even though the server keeps its own state, this state is ephemeral and can safely be disposed of (e.g., in case of a server crash and failover to another instance) with only temporary disruptions to service as peers re-announce themselves to the new server. This disruption will mostly be felt by newcomers and peers using the relay fallback.
  • The state can’t be shared among instances of the bootstrap server for load-sharing.
  • One instance can be used as a bootstrap server while another can be used as a signal/relay server to spread the load; the only configuration necessary is to specify different URLs in your conductor configuration (see the next section).
  • The Docker compose file above configures the server as an open relay without authentication; we’re working on making it easier to build authentication appropriate for your hApp.
  • You’ll need to size your server instance for your expected peak level of usage — it may be helpful to simulate this using a multi-conductor Tryorama test or real humans. Depending on your server specs and bandwidth, the server binary can theoretically scale to support thousands of concurrent peers, with a couple hundred using relayed connections.
  • The server hasn’t been tested extensively with Holochain in high-load or failure scenarios.

Configure your hApp to use your bootstrap server

Testing

To use your server in testing, and to test that the server is running and accessible, open your project’s package.json file and edit the following lines.

Use a network seed during testing

If you use the same server for production and testing, you might end up writing test data to a production DHT. The example below adds a network seed for test runs so that test data ends up in its own DHT.

 ...
   "scripts": {
-    "start": "AGENTS=${AGENTS:-3} BOOTSTRAP_PORT=$(get-port) npm run network",
+    "start": "AGENTS=${AGENTS:-3} npm run network",
     "network": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:happ\" \"hc playground\"",
     "test": "npm run build:zomes && hc app pack workdir --recursive && npm run test --workspace tests",
     // Replace the hApp bundle name and URLs with your actual values.
-    "launch:happ": "hc-spin -n $AGENTS --ui-port $UI_PORT workdir/my_app.happ",
+    // Use bootstrap server
+    "launch:happ": "hc-spin -n $AGENTS --ui-port $UI_PORT --bootstrap-url \"https://bootstrap.example.org\" --signaling-url \"wss://bootstrap.example.org\" --network-seed \"bootstrap-testing-network-only\" workdir/my_app.happ",
     // If you use the Tauri-based launcher, you can also make the following
     // edits.
-    "start:tauri": "AGENTS=${AGENTS:-2} BOOTSTRAP_PORT=$(get-port) npm run network:tauri",
+    "start:tauri": "AGENTS=${AGENTS:-2} npm run network:tauri",
     "network:tauri": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:tauri\" \"hc playground\"",
-    "launch:tauri": "concurrently \"kitsune2-bootstrap-srv --listen \"127.0.0.1:$BOOTSTRAP_PORT\"\" \"echo pass | RUST_LOG=warn hc launch --piped -n $AGENTS workdir/my_forum_app.happ --ui-port $UI_PORT network --bootstrap http://127.0.0.1:\"$BOOTSTRAP_PORT\" webrtc ws://127.0.0.1:\"$BOOTSTRAP_PORT\"\"",
+    "launch:tauri": "echo pass | RUST_LOG=warn hc launch --piped -n $AGENTS workdir/my_forum_app.happ --ui-port $UI_PORT --network-seed \"bootstrap-testing-network-only\" network --bootstrap \"https://bootstrap.example.org\" webrtc \"wss://bootstrap.example.org\"",
     "package": "npm run build:happ && npm run package --workspace ui && hc web-app pack workdir --recursive",
     "build:happ": "npm run build:zomes && hc app pack workdir --recursive",
     "build:zomes": "cargo build --release --target wasm32-unknown-unknown"
   },
 ...
...
  "scripts": {
    "start": "AGENTS=${AGENTS:-3} npm run network",
    "network": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:happ\" \"hc playground\"",
    "test": "npm run build:zomes && hc app pack workdir --recursive && npm run test --workspace tests",
    // Replace the hApp bundle name and URLs with your actual values.
    // Use bootstrap server
    "launch:happ": "hc-spin -n $AGENTS --ui-port $UI_PORT --bootstrap-url \"https://bootstrap.example.org\" --signaling-url \"wss://bootstrap.example.org\" --network-seed \"bootstrap-testing-network-only\" workdir/my_app.happ",
    // If you use the Tauri-based launcher, you can also make the following
    // edits.
    "start:tauri": "AGENTS=${AGENTS:-2} npm run network:tauri",
    "network:tauri": "hc sandbox clean && npm run build:happ && UI_PORT=$(get-port) concurrently \"npm run start --workspace ui\" \"npm run launch:tauri\" \"hc playground\"",
    "launch:tauri": "echo pass | RUST_LOG=warn hc launch --piped -n $AGENTS workdir/my_forum_app.happ --ui-port $UI_PORT --network-seed \"bootstrap-testing-network-only\" network --bootstrap \"https://bootstrap.example.org\" webrtc \"wss://bootstrap.example.org\"",
    "package": "npm run build:happ && npm run package --workspace ui && hc web-app pack workdir --recursive",
    "build:happ": "npm run build:zomes && hc app pack workdir --recursive",
    "build:zomes": "cargo build --release --target wasm32-unknown-unknown"
  },
...

Production

If you’re using Kangaroo to build an Electron-based app, open up your project’s kangaroo.config.ts file, then edit the following lines:

 import { defineConfig } from './src/main/defineConfig';
 export default defineConfig({
   // ...
   // Use your actual domain name here.
-  bootstrapUrl: 'https://dev-test-bootstrap2.holochain.org/',
+  bootstrapUrl: 'https://bootstrap.example.org/',
-  signalUrl: 'wss://dev-test-bootstrap2.holochain.org/',
+  signalUrl: 'wss://bootstrap.example.org/',
   iceUrls: ['stun:stun.l.google.com:19302','stun:stun.cloudflare.com:3478'],
   // ...
 });
import { defineConfig } from './src/main/defineConfig';
export default defineConfig({
  // ...
  // Use your actual domain name here.
  bootstrapUrl: 'https://bootstrap.example.org/',
  signalUrl: 'wss://bootstrap.example.org/',
  iceUrls: ['stun:stun.l.google.com:19302','stun:stun.cloudflare.com:3478'],
  // ...
});

Hardening your server against unintended use

We’ve shown how to configure the server without authentication. In a production scenario, you’ll likely want to authenticate incoming connections to the server because:

  • Unauthorized requests to the bootstrap endpoint could leak details about what devices are running what hApps, and
  • Unauthorized requests to the signal/relay endpoint allow users of other hApps to freeload on your server’s bandwidth.

We plan to discuss authentication options in the future.

It looks like you are using Internet Explorer. While the basic content is available, this is no longer a supported browser by the manufacturer, and no attention is being given to having IE work well here.