Skip to content

About

One all-in-one storage backend you can drop into anything: your own apps, screenshot tools, pastebin-style pastes, Nostr clients, Reddit posts, forum embeds—anything that needs durable, anonymous file hosting. One Originless to rule them all and keep you anonymous.

Topics

Resources

Stars

86 stars

Watchers

1 watching

Forks

Repository files navigation

Originless

A single-container backend for real-time web apps.
Signed, persistent events with live updates, content-addressed file uploads, and optional multi-node federation — no database server, message broker, or account system to run.

CI Container image Go version Latest release

Originless is a small Go HTTP service with an embedded Kubo IPFS node, packaged in one image. You get a self-hosted backend you can start with a single command:

  • Signed events — immutable, Ed25519-verified JSON documents with TTL expiry, persisted in SQLite and never served after expiry
  • Live updates — Server-Sent Events, no WebSocket server required; reconnecting clients resume from their last event ID
  • IPFS uploads — files and folders addressed by CID, no pinning by default
  • Federation — set SYNC_NODES and nodes converge on the same event set over plain HTTP
  • Built-in demos — a shared canvas, chat, event stream, and upload dashboard
  • CORS enabled — browser apps can call the API from any origin

Quick start

Docker is the supported runtime:

docker run -d --name originless -p 3232:3232 -e STORAGE_MAX=20GB ghcr.io/besoeasy/originless:latest

Open the dashboard at http://localhost:3232.

docker logs -f originless   # follow logs
docker stop originless      # stop (data preserved in the container layer)
docker rm originless        # remove (deletes all data)

To keep the IPFS repository and event database across container replacement, mount a volume at /data:

docker run -d --name originless -p 3232:3232 -v originless-data:/data ghcr.io/besoeasy/originless:latest

Configuration

Variable Default Description
STORAGE_MAX 20GB Human-readable soft limit for the Kubo repository. Stored events are capped at a fifth of this value; beyond that the oldest live events are evicted.
PORT 3232 HTTP port inside the container.
SYNC_NODES none Comma-separated base URLs of peer Originless nodes to federate with.

Automatic garbage collection runs hourly at a fixed 90% watermark. Because uploads are unpinned, a CID may become unavailable after garbage collection.

Federation

Set SYNC_NODES on each node to the other's base URL and the two exchange events over plain HTTP every 5 seconds:

docker run -d --name o1 -p 127.0.0.1:3233:3232 -e SYNC_NODES=http://localhost:3234 ghcr.io/besoeasy/originless:latest
docker run -d --name o2 -p 127.0.0.1:3234:3232 -e SYNC_NODES=http://localhost:3233 ghcr.io/besoeasy/originless:latest

Each node pulls GET /events?since=... from its peers, re-verifies every signature, and dedupes by event ID, so they converge on the union of both event sets. Only events are synced — IPFS blobs stay on the node that accepted them, and each node keeps its own /data/events.db.

Note

Sync checkpoints on created_at, so client clocks should be roughly in step and created_at should be "now" — events backdated beyond the 15-minute drift window are not guaranteed to sync. Checkpoints are persisted, so a node resumes where it left off after a restart.

Like every other part of Originless there is no authentication — expose the API only on networks you trust.

Access control

There is none, by design. No user accounts, no passwords, no API tokens: an Ed25519 signature on an event is the only credential in the protocol, and it proves authorship — who wrote an event — not permission to write it. Any client that can reach the port can publish to any collection, and CORS is * because there are no credentials for a browser to withhold.

That makes the network boundary the trust boundary. To keep a run private, bind to localhost:

docker run -d --name originless -p 127.0.0.1:3232:3232 ghcr.io/besoeasy/originless:latest

For multi-user applications, enforce authorization in your own client or in a reverse proxy in front of Originless. The settings above are resource bounds, not access control.

Upload and download files

# single file
curl -F "file=@hello.txt" http://localhost:3232/up

# folder via /upf
curl \
  -F "file=@folder/one.txt;filename=folder/one.txt" \
  -F "file=@folder/nested/two.txt;filename=folder/nested/two.txt" \
  http://localhost:3232/upf

Both return the resulting CID. For content available through the public IPFS network, use inbrowser.link, Helia Verified Fetch, or a gateway such as Rainbow.

API

The complete request and response reference is in docs/api.md.

Method Route Purpose
GET / Dashboard and live demos
GET /healthz Container health
GET /stats IPFS and event metrics
POST /up Upload a file or folder
POST /upf Explicit folder upload
GET /cid/{cid} JSON metadata and availability for a CID
POST /events Publish a signed event
GET /events Query events with filters and pagination
GET /events/{id} Retrieve one event
GET /events/stream Stream events over SSE

Events are stored in SQLite at /data/events.db and survive restarts. Uploaded content is ephemeral by default — mount a volume at /data to keep it, and remember unpinned CIDs can be garbage-collected.

Signed events

An event is a small JSON document signed by its creator. The signature is verified with the Ed25519 public key in owner; the server manages no accounts or passwords.

{
  "owner": "ed25519:<64-hex-public-key>",
  "collection": "originless/chat",
  "created_at": 1758420000,
  "expires_at": 1789956000,
  "data": {"message": "Hello from the browser"},
  "labels": ["chat:lobby"],
  "sig": "<128-hex-signature>"
}

Use /events/stream to receive matching events live. Event documents are limited to 8 KiB and one year of TTL.

Development

Requires Go 1.24+ and, for the full single-binary experience, a kubo install (or Docker).

go vet ./...     # lint
go build ./...   # build
go test ./...    # test

Build the image locally:

docker build -t originless:dev .

Links

About

One all-in-one storage backend you can drop into anything: your own apps, screenshot tools, pastebin-style pastes, Nostr clients, Reddit posts, forum embeds—anything that needs durable, anonymous file hosting. One Originless to rule them all and keep you anonymous.

Topics

Resources

Stars

86 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages