loopernet is the Routed-mode Network control-plane service. It hosts exactly one Network, stores membership + lease + audit state in a local SQLite file, receives centralized GitHub webhooks, and fans wakeup events out to connected Nodes.
Today, deploy loopernet as a single active instance per Network.
- One
loopernethosts one Network. - Do not run multiple active
loopernetreplicas for the same Network. - Do not share one SQLite file across multiple
loopernetcontainers.
Why:
- the Coordinator lease lives in the
loopernetdatabase; - membership state lives in the same database;
- webhook/event fanout is currently in-process, not backed by shared pub/sub.
Different environments may each run their own loopernet instance, for example one for staging and one for production.
Release workflow publishes the container image to GHCR:
docker pull ghcr.io/nexu-io/loopernet:v0.x.yStable releases also publish latest.
loopernet reads configuration from environment variables.
Required:
LOOPERNET_DB_PATHβ path to the SQLite database fileLOOPERNET_ADMIN_TOKENβ bearer token used by Nodes and admin operations
Optional:
LOOPERNET_LISTEN_ADDRβ listen address, default127.0.0.1:8089LOOPERNET_NETWORK_IDβ fixed Network identifier; if omitted,loopernetcreates one and persists it in the DBLOOPERNET_PROTOCOL_VERSIONβ defaults to the current protocol versionLOOPERNET_MIN_DAEMON_VERSIONβ optional minimumlooperdversion gateLOOPERNET_ADVERTISE_URLβ optional externally reachable base URL to surface to clients
loopernet needs persistent local storage for its SQLite database.
Minimum requirement:
- mount a writable volume at
/var/lib/loopernet - keep
LOOPERNET_DB_PATH=/var/lib/loopernet/loopernet.sqlite
If the volume is lost, GitHub work-intent state remains authoritative, but loopernet loses:
- membership state
- lease state
- webhook/audit history
- persisted Network identity if you did not pin
LOOPERNET_NETWORK_ID
Recovery is then:
- redeploy
loopernet - restore or recreate the DB volume
- re-onboard repos if webhook secrets were lost
- re-join Nodes
By default the container listens on port 8089.
Expose it behind a stable HTTPS endpoint if Nodes or GitHub webhooks reach it over the network. A reverse proxy or load balancer in front of a single loopernet instance is fine.
docker run -d \
--name loopernet \
-p 8089:8089 \
-e LOOPERNET_LISTEN_ADDR=0.0.0.0:8089 \
-e LOOPERNET_DB_PATH=/var/lib/loopernet/loopernet.sqlite \
-e LOOPERNET_ADMIN_TOKEN="replace-me" \
-e LOOPERNET_MIN_DAEMON_VERSION="0.2.0" \
-v loopernet-data:/var/lib/loopernet \
ghcr.io/nexu-io/loopernet:v0.x.yThe repository also includes ready-to-edit deploy assets at ../deploy/loopernet/ including docker-compose.yml.
services:
loopernet:
image: ghcr.io/nexu-io/loopernet:v0.x.y
restart: unless-stopped
ports:
- "8089:8089"
environment:
LOOPERNET_LISTEN_ADDR: 0.0.0.0:8089
LOOPERNET_DB_PATH: /var/lib/loopernet/loopernet.sqlite
LOOPERNET_ADMIN_TOKEN: replace-me
LOOPERNET_MIN_DAEMON_VERSION: 0.2.0
volumes:
- loopernet-data:/var/lib/loopernet
volumes:
loopernet-data:After loopernet is up:
- choose a stable public URL for
loopernet - join each Node with
looper network join <url> --key ... --name <node> - disable unsupported routed Planner/Fixer auto-discovery before opting projects into
network.mode=routed - onboard repos so GitHub webhooks point to
loopernet - confirm
looper network status --verboseshows membership, identity, lease, and webhook health
Current recommendation is single-instance, restartable, persistent-volume-backed deployment.
This is not yet an HA multi-replica service. Running multiple active replicas for one Network risks split-brain or partial-brain behavior because webhook/event delivery and coordination are not backed by shared distributed state.