Navigate

Earthstar

Replica Server framework

Table of contents

Overview

A replica server is an always-online peer which you can use to synchronise your Earthstar shares with far away friends. They're undiscoverable and only synchronise with peers who already know your shares' addresses.

Being regular servers on the internet, they can be extended to provide other services too!

The replica servers module offers a selection of pre-configured replica servers, as well as a framework for constructing your own using a variety of extensions. You can even create your own extensions!

Installation

For Deno:

import { ReplicaServer } from "https://deno.land/x/earthstar_replica_server/mod.ts";

For NPM:

npm install @earthstar-project/replica-server
import { ReplicaServer } from "@earthstar-project/replica-server";

Preconfigured servers

This module exports a few preconfigured servers you can deploy right away.

Here's an example of starting one of these on Deno:

import { Nimble } from "https://deno.land/xxxxxxxxx/mod.ts";

const server = new NimbleServer();
// That's it. Your replica server is running.

If none of these configurations meets your needs, we've done our best to make it as straightforward to configure it to your liking using extensions.

Extensions

It's possible to configure your own replica server using extensions.

Here's a replica server pre-populated with known shares and websocket sync.

import * as Earthstar from "https://deno.land/x/earthstar/mod.ts";
import {
	ExtensionKnownShares,
	ExtensionSyncWebsocket,
	ReplicaServer,
} from "https://deno.land/xxxxxxx/mod.ts";

const server = new ReplicaServer([
	new ExtensionKnownShares({
		knownSharesPath: "known_shares.json"
		onCreateReplica: (shareAddress) => {
			return new Earthstar.Replica(
				shareAddress,
				Earthstar.FormatValidatorEs4,
				new Earthstar.ReplicaDriverMemory(shareAddress),
			);
		},
	}),
	new ExtensionSyncWebsocket(),
]);

The order in which you specify extensions matters, as some extensions may do something which another extension depends upon, e.g. ExtensionKnownShares sets up replicas which ExtensionServeContent will serve content from.

Equally, requests will fall through extensions, returning on the first match. So sync extensions like ExtensionSyncHttp should come before ExtensionServeContent, so that requests to sync aren't swallowed.

ExtensionKnownShares

This extension configures which shares your replica server knows about and sync. Earthstar peers can only sync shares they both know about beforehand, protecting your replica server from syncing untrusted data with strangers. The known share list is pulled from a JSON file on disk, and you can specify how the extension should create corresponding replicas for the shares.

ExtensionSyncWebsocket

Makes it possible for Earthstar peers to sync with your replica server using a Websocket connection.

ExtensionSyncHttp

Makes it possible for Earthstar peers to sync with your replica server over HTTP.

ExtensionSyncClassic

Makes it possible for pre-v7 Earthstar peers to sync with your replica server over HTTP. Handy if you want to migrate data stored in older clients / pubs.

ExtensionServeContent

Turn your replica server into a wiki, website, image gallery, or anything a web server could do! This extension will translate requests to the server to documents of a share of your choice, so a request for https://my.server/posts/page.html will make this extension fetch /page.html from a replica, and serve it back in the response! It'll do the same with markdown, text, images, and more.

Developing extensions

Extensions can be very simple or complex. ExtensionKnownShares is less than 50 lines of code.

Your extension needs to implement the interface IReplicaServerExtension, which has two methods:

You can use your extension's constructor as a place for configuring the extension before it's registered.

Here's a simple extension which would display a message showing the number of shares when a user would make a request to /share-count:

class ShareCounterExtension implements IReplicaServerExtension {
	private greeting: string;
	private peer: Earthstar.Peer;

	constructor(greeting: string) {
		// Set the user's greeting to a private variable.
		this.greeting = greeting;
	}

	register(peer: Earthstar.Peer) {
		// Set the replica server's peer to a private variable.
		this.peer = peer;

		// We could also do other stuff here, like start a new process in the background.
	}

	request(req: Request) {
		const url = new URL(req.url);

		// Check if the request is for `/share-count`
		if (url.pathname === "/share-count") {
			const shareCount = this.peer.replicas.length;

			// Serve up the greeting along with the number of shares on the replica server.
			return new Response(
				`${this.greeting}. This replica server is serving ${shareCount} shares!`,
			);
		}

		// Or pass the request on to the next extension.
		return Promise.resolve<null>;
	}
}

Deploying

Replica servers are ordinary web servers which you can run on your own devices and VPSes like any other web server.

That said, we've created a few template projects for deploying to popular hosting services.