Mothership
A control plane for a fleet of edges. The mothership is a PocketOne app that records which edges exist and which instances run where. Each edge follows it, serves its own instances and forwards requests for the rest to the edge that runs them.
One operator, no users: owners and accounts are the tenants extension (planned), which extends the mothership through its collections and the mirror's extensions. Each layer is optional: an edge runs without a mothership, and a mothership without tenants.
Install · Configure · Use · Integrations · Example
Install
The edge side (the mirror package) is built into pocketone. It turns on when pocketone.yaml names a provider
and has a mothership section (below); pocketone serve then takes its instances and the other edges from the
mothership.
The mothership side has no switch yet. In the Go code of the PocketOne app that will be the mothership, create its collections once the app has bootstrapped:
if err := mothership.EnsureCollections(app); err != nil {
return err
}
The module is github.com/pockethost/pocketone/ext/multisite-mothership. In your own edge build, mirror.FromSection(log)
returns the mirror for the config (nil without a mothership section); use it as the host's instance source and the
router's edge source, as examples/pocketone/multi.go does.
Configure
On each edge, add a mothership section next to the provider. Logins come from the private .env:
provider: docker # or pocker
mothership:
url: http://10.88.0.10:8090
email: $MOTHERSHIP_EMAIL
password: $MOTHERSHIP_PASSWORD
self: lax-1 # this edge's edge_id (or edges.self)
internal_url: http://10.88.0.5:8080
region: lax
apex: example.com # <name>.example.com routes to each instance
url and self are required. The edge logs in as a superuser of the mothership.
On the mothership, there's nothing to configure beyond creating the collections.
pocketone.yaml reference
mothership:
A community mothership to mirror instances and edges from: url, login, this edge's id, internal URL, region, apex.
| Key | Type | Default | Description |
|---|---|---|---|
url |
string | The mothership's URL. Required. | |
email |
string | Superuser email this edge logs in with; use a $VAR from the .env. | |
password |
string | Superuser password; use a $VAR from the .env. | |
self |
string | This edge's edge_id, such as lax-1. Default: the edges section's self. Required. | |
internal_url |
string | Where other edges reach this one. Set: the edge registers itself when the mothership has no record for it. | |
region |
string | Region recorded when the edge registers itself. | |
apex |
string | Makes |
|
heartbeat |
duration | How often this edge marks itself online. Default 15s; negative: never. | |
resync |
duration | How often everything is reloaded, in case a change was missed. Default 10m. |
Use
You manage the fleet in the mothership's dashboard, in two collections only superusers can read or write:
edges:edge_id(such aslax-1),internal_url,region,status(online,draining,offline) andlast_seen. An edge withinternal_urlset registers itself when it has no record, marks itself online every 15 s, and offline when it shuts down.instances:name(<name>.<apex>routes to it),hosts(extra hostnames),edge(where it runs),power(off answers 409 "instance is powered off"),suspension(non-empty answers 403 with that message),dev,version,secrets,encryption_key,access,limits,plugins(extension settings; the field keeps its old name) andstatus.
Changes reach the edges within moments over PocketBase's realtime stream; there's no polling. To move an instance,
change its edge: the old edge drops its full record and forwards to the new one until the new edge has it. An
instance with no edge isn't served anywhere.
Integrations
Works with
| Extension | How they fit |
|---|---|
| Multisite | The mirror is the host's instance source: which instances exist and which this edge runs. |
| Edge | The mirror is also an edge source: where the other edges are, so requests for their instances are forwarded. It combines with a fixed edges list. |
| Docker and Pocker | Run the instances this edge owns, with the version, secrets, limits and extension settings from each record. |
| Tenants (planned) | Adds owners and accounts through mirror extensions. |
Building on Mothership
- Your own fields and collections.
EnsureCollectionsleaves fields an extension added alone, so an extension can add its own fields and collections to the mothership. - Mirror extensions. Pass a
mirror.Extensiontomirror.FromSectionormirror.Config.Extensions.Views()adds filtered subscriptions (such asownersfiltered toinstances_via_owner.edge ?= {edge}),Instance()adjusts each instance as it's built (block a suspended owner's instances, add an owner's trusted IPs), andChanged()names the instances a change in its views affects. - Go API.
mirror.New(mirror.Config{...})builds a mirror without the config file.Get(view, id)andRecords(view)read any view;SelfRecord()is this edge's record id.
Example
There's no example/main.go yet. The stock binary's multi-instance mode,
examples/pocketone/multi.go, follows a mothership when the config has the
section.
How it works
Each edge subscribes to filtered views, so it only receives what concerns it:
| View | Collection | Filter / fields | Why |
|---|---|---|---|
edges |
edges | all | forwarding, and health from heartbeats |
routes |
instances | fields id,name,hosts,edge,updated |
the routing table: any edge may get any visitor |
local |
instances | edge = <this edge> |
full records (secrets, limits, plugins) for instances this edge runs |
An instance moving away shows up in routes and its full record is dropped; one moving here arrives in local. The
stream reconnects and reloads on its own, and reloads everything every 10 minutes in case anything was missed.
Filters cut what each edge downloads and keeps (most edges run a few of thousands of instances). They are not a security boundary while edges log in as superusers.
Status
Early. Built: the edges and instances collections (EnsureCollections) and the edge side (mirror). Not yet:
the mothership's own endpoints (placement, moves) and instance status reports.
License
MIT
Questions and comments
Comments are a GitHub Discussions thread; sign in with GitHub to post.