An AT Protocol PDS
TypeScript 85.3%
Nix 8.8%
Rust 5.9%
9 1 0

Clone this repository

https://tangled.org/ewancroft.uk/moonstone https://tangled.org/did:plc:ofrbh253gwicbkc5nktqepol/moonstone
git@tangled.org:ewancroft.uk/moonstone git@tangled.org:did:plc:ofrbh253gwicbkc5nktqepol/moonstone

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

moonstone#

Personal ATProto PDS — optimised for NixOS/Caddy, no Bluesky infrastructure defaults.

I DO NOT RECOMMEND YOU DEPLOY, THIS IS EXPERIMENTAL AND COMPLETELY DONE FOR FUN. I DO NOT INTEND TO MAINTAIN IT AFTER IT IS IN A WORKING STATE.

Wraps @atproto/pds with:

  • No Bluesky infra defaults — no api.bsky.app, mod.bsky.app etc. wired in.
  • did:plc supported — via configurable PDS_PLC_URL (defaults to plc.directory, the canonical ATProto PLC registry).
  • Rust identity layer (@ewanc26/moonstone-native) — handle/DID syntax validation and async identity resolution backed by rsky-syntax and rsky-identity via neon N-API bindings.
  • Typed, validated config — zod schema, personal-PDS defaults, fast-fail on missing secrets.
  • Self-contained — all dependencies declared within this repo (git deps for rsky crates; no path deps outside the folder).
  • NixOS module at nix/module.nix — SOPS secrets, systemd service, Caddy virtualHost.

Packages#

Package Description
@ewanc26/moonstone-config Env parsing + zod validation
@ewanc26/moonstone-native Rust native addon (neon) — syntax validation + DID/handle resolution
@ewanc26/moonstone-server PDS server entry point

Quick start#

# 1. Build the Rust native addon
pnpm run build:native

# 2. Build TypeScript
pnpm run build:ts

# 3. Set env vars (see .env.example)
cp .env.example .env && $EDITOR .env

# 4. Run
node packages/server/dist/index.js

Required env vars (injected via SOPS in production):

PDS_HOSTNAME=pds.example.com
PDS_JWT_SECRET=<openssl rand --hex 16>
PDS_ADMIN_PASSWORD=<openssl rand --hex 16>
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX=<see .env.example>

Federation#

moonstone defaults to the relay list from nix-config options.nix — a broad set of independent ATProto relays plus bsky.network. To use a different set, override PDS_CRAWLERS with a comma-separated list:

PDS_CRAWLERS=https://relay.cerulea.blue,https://relay.feeds.blue

To disable all relay announcements entirely:

PDS_CRAWLERS=

did:plc resolution uses plc.directory by default — an ATProto protocol dependency, not a Bluesky product. Override with PDS_PLC_URL to point at a self-hosted PLC directory.

NixOS#

See nix/module.nix. Add to nix-config:

inputs.moonstone.url = "github:ewanc26/moonstone";
# pass as specialArgs and import the module
imports = [ inputs.moonstone.nixosModules.moonstone ];

License#

AGPL-3.0-only