| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A minimal, fast, JSON-LD native Solid server.
| Method | Support |
|---|---|
| GET | Full - Resources and containers |
| HEAD | Full |
| PUT | Full - Create/update resources |
| POST | Full - Create in containers |
| DELETE | Full |
| PATCH | N3 Patch + SPARQL Update |
| OPTIONS | Full with CORS |
JSS runs on Android via Termux (uses pure JavaScript bcryptjs for compatibility):
pkg install nodejs git
npm install -g javascript-solid-server
jss start --port 8080 --nostr --gitUse PM2 for persistence:
npm install -g pm2
pm2 start jss -- start --port 8080 --nostr --git
pm2 savenpm install
# Or install globally
npm install -g javascript-solid-server# Initialize configuration (interactive)
jss init
# Start server
jss start
# Or with options
jss start --port 8443 --ssl-key ./key.pem --ssl-cert ./cert.pemjss start [options] # Start the server
jss init [options] # Initialize configuration
jss invite <cmd> # Manage invite codes (create, list, revoke)
jss quota <cmd> # Manage storage quotas (set, show, reconcile)
jss --help # Show help| Option | Description | Default |
|---|---|---|
| -p, --port <n> | Port to listen on | 3000 |
| -h, --host <addr> | Host to bind to | 0.0.0.0 |
| -r, --root <path> | Data directory | ./data |
| -c, --config <file> | Config file path | - |
| --ssl-key <path> | SSL private key (PEM) | - |
| --ssl-cert <path> | SSL certificate (PEM) | - |
| --conneg | Enable Turtle support | false |
| --notifications | Enable WebSocket | false |
| --idp | Enable built-in IdP | false |
| --idp-issuer <url> | IdP issuer URL | (auto) |
| --subdomains | Enable subdomain-based pods | false |
| --base-domain <domain> | Base domain for subdomains | - |
| --mashlib | Enable Mashlib (local mode) | false |
| --mashlib-cdn | Enable Mashlib (CDN mode) | false |
| --mashlib-module <url> | Enable ES module data browser from a URL | - |
| --mashlib-version <ver> | Mashlib CDN version | 2.0.0 |
| --solidos-ui | Enable modern SolidOS UI (requires --mashlib) | false |
| --git | Enable Git HTTP backend | false |
| --nostr | Enable Nostr relay | false |
| --nostr-path <path> | Nostr relay WebSocket path | /relay |
| --nostr-max-events <n> | Max events in relay memory | 1000 |
| --invite-only | Require invite code for registration | false |
| --webid-tls | Enable WebID-TLS client certificate auth | false |
| --default-quota <size> | Default storage quota per pod (e.g., 50MB) | 50MB |
| --activitypub | Enable ActivityPub federation | false |
| --ap-username <name> | ActivityPub username | me |
| --ap-display-name <name> | ActivityPub display name | (username) |
| --ap-summary <text> | ActivityPub bio/summary | - |
| --ap-nostr-pubkey <hex> | Nostr pubkey for identity linking | - |
| --public | Allow unauthenticated access (skip WAC) | false |
| --read-only | Disable PUT/DELETE/PATCH methods | false |
| --live-reload | Auto-refresh browser on file changes | false |
| --pay | Enable HTTP 402 paid access for /pay/* | false |
| --pay-cost <n> | Cost per request in satoshis | 1 |
| --pay-mempool-url <url> | Mempool API URL for deposit verification | (testnet4) |
| --pay-address <addr> | Address for receiving deposits | - |
| --pay-token <ticker> | Token to sell (enables primary market + withdrawal) | - |
| --pay-rate <n> | Sats per token for buy/withdraw | 1 |
| --pay-chains <ids> | Multi-chain deposits + AMM (e.g. "tbtc3,tbtc4") | - |
| --mongo | Enable MongoDB-backed /db/ route | false |
| --mongo-url <url> | MongoDB connection URL | mongodb://localhost:27017 |
| --mongo-database <name> | MongoDB database name | solid |
| -q, --quiet | Suppress logs | false |
All options can be set via environment variables with JSS_ prefix:
export JSS_PORT=8443
export JSS_SSL_KEY=/path/to/key.pem
export JSS_SSL_CERT=/path/to/cert.pem
export JSS_CONNEG=true
export JSS_SUBDOMAINS=true
export JSS_BASE_DOMAIN=example.com
export JSS_MASHLIB=true
export JSS_MASHLIB_MODULE=https://example.com/mashlib.js
export JSS_NOSTR=true
export JSS_INVITE_ONLY=true
export JSS_WEBID_TLS=true
export JSS_DEFAULT_QUOTA=100MB
export JSS_ACTIVITYPUB=true
export JSS_AP_USERNAME=alice
export JSS_PUBLIC=true
export JSS_READ_ONLY=true
export JSS_LIVE_RELOAD=true
export JSS_SOLIDOS_UI=true
export JSS_PAY=true
export JSS_PAY_COST=10
export JSS_PAY_ADDRESS=your-address
export JSS_PAY_TOKEN=PODS
export JSS_PAY_RATE=10
export JSS_MONGO=true
export JSS_MONGO_URL=mongodb://localhost:27017
export JSS_MONGO_DATABASE=solid
jss startCreate config.json:
{
"port": 8443,
"root": "./data",
"sslKey": "./ssl/key.pem",
"sslCert": "./ssl/cert.pem",
"conneg": true,
"notifications": true
}Then: jss start --config config.json
For personal pod servers where only one user needs access:
# Basic single-user mode (creates pod at /me/)
jss start --single-user --idp
# Custom username
jss start --single-user --single-user-name alice --idp
# Root-level pod (pod at /, WebID at /profile/card#me)
jss start --single-user --single-user-name '' --idp
# Via environment
JSS_SINGLE_USER=true jss start --idpFeatures:
curl -X POST http://localhost:3000/.pods \
-H "Content-Type: application/json" \
-d '{"name": "alice"}'Response:
{
"name": "alice",
"webId": "http://localhost:3000/alice/#me",
"podUri": "http://localhost:3000/alice/",
"token": "eyJ..."
}# Read public profile
curl http://localhost:3000/alice/
# Write to pod (with token)
curl -X PUT http://localhost:3000/alice/public/data.json \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/ld+json" \
-d '{"@id": "#data", "http://example.org/value": 42}'
# Read back
curl http://localhost:3000/alice/public/data.jsoncurl -X PATCH http://localhost:3000/alice/public/data.json \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: text/n3" \
-d '@prefix solid: <http://www.w3.org/ns/solid/terms#>.
_:patch a solid:InsertDeletePatch;
solid:inserts { <#data> <http://example.org/name> "Updated" }.'curl -X PATCH http://localhost:3000/alice/public/data.json \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/sparql-update" \
-d 'PREFIX ex: <http://example.org/>
DELETE DATA { <#data> ex:value 42 } ;
INSERT DATA { <#data> ex:value 43 }'Use If-Match for safe updates (optimistic concurrency):
# Get current ETag
ETAG=$(curl -sI http://localhost:3000/alice/public/data.json | grep -i etag | awk '{print $2}')
# Update only if ETag matches
curl -X PUT http://localhost:3000/alice/public/data.json \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/ld+json" \
-H "If-Match: $ETAG" \
-d '{"@id": "#data", "http://example.org/value": 100}'Use If-None-Match: * for create-only semantics:
# Create only if resource doesn't exist (returns 412 if it does)
curl -X PUT http://localhost:3000/alice/public/new-resource.json \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/ld+json" \
-H "If-None-Match: *" \
-d '{"@id": "#new"}'This is a JSON-LD native implementation. Unlike traditional Solid servers that treat Turtle as the primary format and convert to/from it, this server:
Enable conneg: true when:
import { createServer } from './src/server.js';
// Default: JSON-LD only (fast)
const server = createServer();
// With Turtle support (for interoperability)
const serverWithConneg = createServer({ conneg: true });createServer({
logger: true, // Enable Fastify logging (default: true)
conneg: false, // Enable content negotiation (default: false)
notifications: false, // Enable WebSocket notifications (default: false)
subdomains: false, // Enable subdomain-based pods (default: false)
baseDomain: null, // Base domain for subdomains (e.g., "example.com")
mashlib: false, // Enable Mashlib data browser - local mode (default: false)
mashlibCdn: false, // Enable Mashlib data browser - CDN mode (default: false)
mashlibVersion: '2.0.0', // Mashlib version for CDN mode
});Enable the SolidOS Mashlib data browser for RDF resources. Two modes are available:
CDN Mode (recommended for getting started):
jss start --mashlib-cdn --connegLoads mashlib from unpkg.com CDN. Zero footprint - no local files needed.
Local Mode (for production/offline):
jss start --mashlib --connegServes mashlib from src/mashlib-local/dist/. Requires building mashlib locally:
cd src/mashlib-local
npm install && npm run buildES Module Mode (for custom or next-gen mashlib builds):
jss start --mashlib-module https://example.com/mashlib.jsLoads an ES module-based data browser from any URL. Uses <script type="module"> and <div id="mashlib"> (self-initializing). CSS is auto-derived by replacing .js with .css. Content negotiation is auto-enabled.
How it works:
Note: Mashlib works best with --conneg enabled for Turtle support.
Modern UI (SolidOS UI):
jss start --mashlib --solidos-ui --connegServes a modern Nextcloud-style UI shell while reusing mashlib's data layer. The --solidos-ui flag swaps the classic databrowser interface for a cleaner, mobile-friendly design with:
Requires solidos-ui dist files in src/mashlib-local/dist/solidos-ui/. See solidos-ui for details.
Pod profiles (/alice/) use HTML with embedded JSON-LD data islands and are rendered using:
This allows profiles to work without server-side content negotiation while still providing full SolidOS editing capabilities.
Enable real-time notifications for resource changes:
const server = createServer({ notifications: true });Clients discover the WebSocket URL via the Updates-Via header:
curl -I http://localhost:3000/alice/public/
# Updates-Via: ws://localhost:3000/.notificationsProtocol (solid-0.1, compatible with SolidOS):
Server: protocol solid-0.1 Client: sub http://localhost:3000/alice/public/data.json Server: ack http://localhost:3000/alice/public/data.json Server: pub http://localhost:3000/alice/public/data.json (on change)
Enable Git HTTP backend to clone and push to pod containers:
jss start --git# Create a git repo in a pod container
cd data/alice/myrepo
git init
echo "# My Project" > README.md
git add . && git commit -m "Initial commit"# Clone (public read access)
git clone http://localhost:3000/alice/myrepo
# Push (requires write access via WAC)
cd myrepo
echo "New content" >> README.md
git add . && git commit -m "Update"
git pushGit operations respect WAC permissions - clone requires Read access, push requires Write access.
Auto-checkout: After a successful push to a non-bare repository, JSS automatically updates the working directory - no post-receive hooks needed.
Git push supports NIP-98 authentication via Basic Auth. Install the credential helper:
npm install -g git-credential-nostr
git-credential-nostr generate
git config --global credential.helper nostr
git config --global nostr.privkey <key-from-generate>Create an ACL for your repo (includes public read for clone + owner write for push):
cd myrepo
git-credential-nostr acl > .acl
git add .acl && git commit -m "Add ACL"See git-credential-nostr for more details.
Enable ActivityPub to federate with Mastodon, Pleroma, Misskey, and other Fediverse servers:
jss start --activitypub --ap-username alice --ap-display-name "Alice" --ap-summary "Hello from JSS!"| Endpoint | Description |
|---|---|
| /.well-known/webfinger | Actor discovery (Mastodon searches here) |
| /.well-known/nodeinfo | NodeInfo discovery |
| /profile/card | Actor (returns JSON-LD when Accept: application/activity+json) |
| /inbox | Shared inbox for receiving activities |
| /profile/card/inbox | Personal inbox |
| /profile/card/outbox | User's activities |
| /profile/card/followers | Followers collection |
| /profile/card/following | Following collection |
Your WebID (/profile/card#me) becomes your ActivityPub Actor. Link to Nostr identity:
jss start --activitypub --ap-nostr-pubkey <64-char-hex-pubkey>This adds alsoKnownAs: ["did:nostr:<pubkey>"] to your Actor profile, creating a verifiable link between your Solid, ActivityPub, and Nostr identities (the SAND stack).
import { createServer } from 'javascript-solid-server';
const server = createServer({
activitypub: true,
apUsername: 'alice',
apDisplayName: 'Alice',
apSummary: 'Building the decentralized web!',
apNostrPubkey: 'abc123...' // Optional: links to did:nostr
});# Check WebFinger
curl "http://localhost:3000/.well-known/webfinger?resource=acct:alice@localhost:3000"
# Get Actor (AP format)
curl -H "Accept: application/activity+json" http://localhost:3000/profile/card
# Check NodeInfo
curl http://localhost:3000/.well-known/nodeinfo/2.1JSS exposes Mastodon API endpoints so that Mastodon clients (Elk, Phanpy, Ice Cubes) can connect:
jss start --activitypub --idp| Endpoint | Description |
|---|---|
| POST /api/v1/apps | Dynamic client registration |
| GET /api/v1/accounts/verify_credentials | Current user profile |
| GET /api/v1/instance | Instance metadata |
| GET /oauth/authorize | OAuth authorize page |
| POST /oauth/authorize | Process login |
| POST /oauth/token | Exchange code for Bearer token |
The OAuth layer is shared between Mastodon clients, remoteStorage apps, and third-party Solid panes:
Supports out-of-band (OOB) redirect for CLI/desktop clients.
# Register a client
curl -X POST http://localhost:3000/api/v1/apps \
-H "Content-Type: application/json" \
-d '{"client_name": "Test App", "redirect_uris": "urn:ietf:wg:oauth:2.0:oob"}'
# Check instance info
curl http://localhost:3000/api/v1/instanceJSS implements the remoteStorage protocol. The storage routes are always available, but WebFinger discovery and OAuth require --activitypub (which provides the WebFinger and OAuth endpoints). Any remoteStorage-compatible app can store and sync data on your pod.
jss start --activitypub --idpremoteStorage clients discover the storage endpoint via WebFinger:
curl "http://localhost:3000/.well-known/webfinger?resource=acct:me@localhost:3000"The response includes a remotestorage link relation pointing to /storage/me/.
| Method | Endpoint | Description |
|---|---|---|
| GET | /storage/:user/* | Read file or list folder (JSON-LD) |
| HEAD | /storage/:user/* | Get metadata (ETag, Content-Type, size) |
| PUT | /storage/:user/* | Write file (creates parent folders) |
| DELETE | /storage/:user/* | Delete file |
# Write a file (needs Bearer token from OAuth flow)
curl -X PUT http://localhost:3000/storage/me/documents/hello.txt \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: text/plain" \
-d "Hello, remoteStorage!"
# Read it back
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:3000/storage/me/documents/hello.txt
# List a folder
curl -H "Authorization: Bearer YOUR_TOKEN" \
http://localhost:3000/storage/me/documents/
# Read from public folder (no auth needed)
curl http://localhost:3000/storage/me/public/readme.txtBridge your Nostr identity to a Solid WebID for seamless authentication:
Step 1: Add your WebID to your Nostr profile (kind 0 event):
{
"name": "alice",
"alsoKnownAs": ["https://solid.social/alice/profile/card#me"]
}Step 2: Add the did:nostr link to your WebID profile:
{
"@id": "#me",
"owl:sameAs": "did:nostr:<your-64-char-hex-pubkey>"
}How it works:
This enables Nostr users to access their Solid pods using existing NIP-07 browser extensions.
Control who can create accounts by requiring invite codes:
jss start --idp --invite-only# Create a single-use invite
jss invite create
# Created invite code: ABCD1234
# Create multi-use invite with note
jss invite create -u 5 -n "For team members"
# List all active invites
jss invite list
# CODE USES CREATED NOTE
# -------------------------------------------------------
# ABCD1234 0/1 2026-01-03
# EFGH5678 2/5 2026-01-03 For team members
# Revoke an invite
jss invite revoke ABCD1234| Mode | Registration | Pod Creation |
|---|---|---|
| Open (default) | Anyone can register | Anyone can create pods |
| Invite-only | Requires valid invite code | Via registration only |
When --invite-only is enabled:
Invite codes are stored in .server/invites.json in your data directory.
Limit storage per pod to prevent abuse and manage resources:
jss start --default-quota 50MB# Set quota for a user (overrides default)
jss quota set alice 100MB
# Show quota info
jss quota show alice
# alice:
# Used: 12.5 MB
# Limit: 100 MB
# Free: 87.5 MB
# Usage: 12%
# Recalculate from actual disk usage
jss quota reconcile aliceOptional MongoDB-backed route for JSON-LD documents that need scale (social feeds, posts, follows). All other routes continue using the filesystem unchanged.
# Install the optional MongoDB driver
npm install mongodb
# Start with MongoDB enabled
jss start --mongo --mongo-url mongodb://localhost:27017 --mongo-database solid# Store a document
curl -X PUT http://localhost:3000/db/alice/notes/1 \
-H "Content-Type: application/ld+json" \
-H "Authorization: Bearer <token>" \
-d '{"@context": "https://schema.org/", "@type": "Note", "text": "Hello"}'
# Read it back
curl http://localhost:3000/db/alice/notes/1
# List container (derived from URI prefixes)
curl http://localhost:3000/db/alice/
# Delete
curl -X DELETE http://localhost:3000/db/alice/notes/1 \
-H "Authorization: Bearer <token>"Supported formats: 50MB, 1GB, 500KB, 1TB
Monetize API endpoints with per-request satoshi payments. Resources under /pay/* require NIP-98 authentication and a positive balance.
jss start --pay --pay-cost 10 --pay-address your-address --pay-token PODS --pay-rate 10| Method | Path | Description |
|---|---|---|
| GET | /pay/.info | Public: cost, token info, chains, pool |
| GET | /pay/.balance | Check your balance (NIP-98 auth) |
| POST | /pay/.deposit | Deposit sats via TXO URI or MRC20 state proof |
| POST | /pay/.buy | Buy tokens with sat balance (requires --pay-token) |
| POST | /pay/.withdraw | Withdraw balance as portable tokens (requires --pay-token) |
| GET | /pay/.offers | List open sell orders (secondary market) |
| POST | /pay/.sell | Create a sell order (requires --pay-token) |
| POST | /pay/.swap | Execute a swap against a sell order |
| GET | /pay/.pool | AMM pool state (requires --pay-chains) |
| POST | /pay/.pool | AMM swap, add/remove liquidity |
| GET | /pay/* | Paid resource access (deducts balance) |
# Check balance
curl -H "Authorization: Nostr <base64-event>" http://localhost:3000/pay/.balance
# Deposit (post a confirmed transaction output)
curl -X POST -H "Authorization: Nostr <base64-event>" \
http://localhost:3000/pay/.deposit \
-d "txid:vout"
# Access paid resource
curl -H "Authorization: Nostr <base64-event>" http://localhost:3000/pay/my-resource
# Buy tokens with sat balance
curl -X POST -H "Authorization: Nostr <base64-event>" \
-H "Content-Type: application/json" \
http://localhost:3000/pay/.buy \
-d '{"amount": 100}'
# Withdraw entire balance as portable tokens
curl -X POST -H "Authorization: Nostr <base64-event>" \
-H "Content-Type: application/json" \
http://localhost:3000/pay/.withdraw \
-d '{"all": true}'Deposit verification uses the mempool API (default: testnet4). The X-Balance and X-Cost headers are returned on successful paid requests. Buy and withdraw return portable MRC20 proofs with Bitcoin anchor data for independent verification.
Users can trade tokens peer-to-peer through the pod. Sell orders are created via /pay/.sell and filled via /pay/.swap. The pod acts as escrow — transferring tokens on the Bitcoin-anchored MRC20 trail and settling sats in the webledger.
Enable multi-chain deposits and an automated market maker:
jss start --pay --pay-chains "tbtc3,tbtc4"Deposits detect the chain from the TXO URI prefix (txo:tbtc3:txid:vout). Each chain's balance is tracked separately. The AMM uses a constant-product formula (x × y = k) with a 0.3% fee.
# Add liquidity
curl -X POST -H "Authorization: Nostr <token>" \
-H "Content-Type: application/json" \
http://localhost:3000/pay/.pool \
-d '{"action": "add-liquidity", "tbtc3": 1000, "tbtc4": 5000}'
# Swap
curl -X POST -H "Authorization: Nostr <token>" \
-H "Content-Type: application/json" \
http://localhost:3000/pay/.pool \
-d '{"action": "swap", "sell": "tbtc3", "amount": 100}'
# Check pool state
curl http://localhost:3000/pay/.poolSupported chains: btc, tbtc3, tbtc4, ltc, signet.
Use the token returned from pod creation:
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/alice/private/Enable the built-in Solid-OIDC Identity Provider:
jss start --idpWith IdP enabled, pod creation requires email and password:
curl -X POST http://localhost:3000/.pods \
-H "Content-Type: application/json" \
-d '{"name": "alice", "email": "alice@example.com", "password": "secret123"}'Response:
{
"name": "alice",
"webId": "http://localhost:3000/alice/#me",
"podUri": "http://localhost:3000/alice/",
"idpIssuer": "http://localhost:3000",
"loginUrl": "http://localhost:3000/idp/auth"
}OIDC Discovery: /.well-known/openid-configuration
For automated testing and scripts, use the credentials endpoint:
curl -X POST http://localhost:3000/idp/credentials \
-H "Content-Type: application/json" \
-d '{"email": "alice@example.com", "password": "secret123"}'Response:
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"webid": "http://localhost:3000/alice/#me"
}For DPoP-bound tokens (Solid-OIDC compliant), include a DPoP proof header.
Enable passwordless login with WebAuthn/FIDO2:
jss start --idpHow it works:
Benefits:
Passkeys are stored per-account and work across devices via platform sync (iCloud Keychain, Google Password Manager, etc.).
Sign in with your Nostr key using NIP-07 browser extensions:
jss start --idpHow it works:
Requirements:
Benefits:
The server also accepts DPoP-bound access tokens from external Solid identity providers:
curl -H "Authorization: DPoP ACCESS_TOKEN" \
-H "DPoP: DPOP_PROOF" \
http://localhost:3000/alice/private/For backend services, CLI tools, and automated agents that need non-interactive authentication:
jss start --ssl-key key.pem --ssl-cert cert.pem --webid-tlsHow it works:
Testing with curl:
# Generate self-signed cert with WebID in SAN
openssl req -x509 -newkey rsa:2048 -keyout client-key.pem -out client-cert.pem -days 365 \
-subj "/CN=Test" -addext "subjectAltName=URI:https://example.com/alice/#me" -nodes
# Make authenticated request
curl --cert client-cert.pem --key client-key.pem https://localhost:8443/alice/private/Profile requirement: Your WebID profile must contain the certificate's public key:
@prefix cert: <http://www.w3.org/ns/auth/cert#> .
<#me> cert:key [
a cert:RSAPublicKey;
cert:modulus "abc123..."^^xsd:hexBinary;
cert:exponent 65537
] .Use cases:
/alice/
├── index.html # WebID profile (HTML with JSON-LD)
├── .acl # Root ACL (owner + public read)
├── inbox/ # Notifications (public append)
│ └── .acl
├── public/ # Public files
├── private/ # Private files (owner only)
│ └── .acl
└── settings/ # User preferences (owner only)
├── .acl
├── prefs
├── publicTypeIndex
└── privateTypeIndex
By default, JSS uses path-based pods (/alice/, /bob/). This is simple but has a security limitation: all pods share the same origin, making cross-site scripting (XSS) attacks possible between pods.
Subdomain mode provides origin isolation - each pod gets its own subdomain (alice.example.com, bob.example.com), preventing XSS attacks between pods.
| Mode | URL | Origin | XSS Risk |
|---|---|---|---|
| Path-based | example.com/alice/ | example.com | Shared origin - pods can XSS each other |
| Subdomain | alice.example.com/ | alice.example.com | Isolated - browser's Same-Origin Policy protects |
jss start --subdomains --base-domain example.comOr via environment variables:
export JSS_SUBDOMAINS=true
export JSS_BASE_DOMAIN=example.com
jss startYou need a wildcard DNS record pointing to your server:
*.example.com A <your-server-ip>
| Path Mode | Subdomain Mode |
|---|---|
| example.com/alice/ | alice.example.com/ |
| example.com/alice/public/file.txt | alice.example.com/public/file.txt |
| example.com/alice/#me | alice.example.com/#me |
Pod creation still uses the main domain:
curl -X POST https://example.com/.pods \
-H "Content-Type: application/json" \
-d '{"name": "alice"}'| Server | Size | Deps | Notes |
|---|---|---|---|
| JSS | ~14K LoC | 14 | Minimal, JSON-LD native |
| NSS | 777 KB | 58 | Original Solid server |
| CSS | 5.8 MB | 70 | Modular, configurable |
| Pivot | ~6 MB | 70+ | Built on CSS |
JSS uses restrictive mode by default: if no ACL file exists for a resource, access is denied. This prevents unauthorized writes to unprotected containers.
You must create a root .acl file in your data directory. Example (JSON-LD format):
{
"@context": {
"acl": "http://www.w3.org/ns/auth/acl#",
"foaf": "http://xmlns.com/foaf/0.1/"
},
"@graph": [
{
"@id": "#owner",
"@type": "acl:Authorization",
"acl:agent": { "@id": "https://your-domain.com/profile/card#me" },
"acl:accessTo": { "@id": "https://your-domain.com/" },
"acl:default": { "@id": "https://your-domain.com/" },
"acl:mode": [
{ "@id": "acl:Read" },
{ "@id": "acl:Write" },
{ "@id": "acl:Control" }
]
},
{
"@id": "#public",
"@type": "acl:Authorization",
"acl:agentClass": { "@id": "foaf:Agent" },
"acl:accessTo": { "@id": "https://your-domain.com/" },
"acl:default": { "@id": "https://your-domain.com/" },
"acl:mode": [
{ "@id": "acl:Read" }
]
}
]
}Save this as data/.acl (replacing your-domain.com with your actual domain).
See Issue #32 for background.
This server is designed for speed. Benchmark results on a typical development machine:
| Operation | Requests/sec | Avg Latency | p99 Latency |
|---|---|---|---|
| GET resource | 5,400+ | 1.2ms | 3ms |
| GET container | 4,700+ | 1.6ms | 3ms |
| PUT (write) | 5,700+ | 1.1ms | 2ms |
| POST (create) | 5,200+ | 1.3ms | 3ms |
| OPTIONS | 10,000+ | 0.4ms | 1ms |
Run benchmarks yourself:
npm run benchmarknpm testCurrently passing: 289 tests (including 27 conformance tests)
This server passes the Solid Conformance Test Harness authentication tests:
# Start server with IdP and content negotiation
JSS_PORT=4000 JSS_CONNEG=true JSS_IDP=true jss start
# Create test users
curl -X POST http://localhost:4000/.pods \
-H "Content-Type: application/json" \
-d '{"name": "alice", "email": "alice@example.com", "password": "alicepassword123"}'
curl -X POST http://localhost:4000/.pods \
-H "Content-Type: application/json" \
-d '{"name": "bob", "email": "bob@example.com", "password": "bobpassword123"}'
# Run CTH authentication tests
docker run --rm --network=host \
-e SOLID_IDENTITY_PROVIDER="http://localhost:4000/" \
-e USERS_ALICE_WEBID="http://localhost:4000/alice/#me" \
-e USERS_ALICE_PASSWORD="alicepassword123" \
-e USERS_BOB_WEBID="http://localhost:4000/bob/#me" \
-e USERS_BOB_PASSWORD="bobpassword123" \
solidproject/conformance-test-harness:latest \
--filter="authentication"CTH Status (v0.0.15):
src/
├── index.js # Entry point
├── server.js # Fastify setup
├── handlers/
│ ├── resource.js # GET, PUT, DELETE, HEAD, PATCH
│ ├── container.js # POST, pod creation
│ ├── git.js # Git HTTP backend
│ └── pay.js # HTTP 402 paid access
├── storage/
│ ├── filesystem.js # File operations
│ └── quota.js # Storage quota management
├── auth/
│ ├── middleware.js # Auth hook
│ ├── token.js # Simple token auth
│ ├── solid-oidc.js # DPoP verification
│ ├── nostr.js # NIP-98 Nostr authentication
│ ├── did-nostr.js # did:nostr → WebID resolution
│ └── webid-tls.js # WebID-TLS client certificate auth
├── wac/
│ ├── parser.js # ACL parsing
│ └── checker.js # Permission checking
├── ldp/
│ ├── headers.js # LDP Link headers
│ └── container.js # Container JSON-LD
├── webid/
│ └── profile.js # WebID generation
├── patch/
│ ├── n3-patch.js # N3 Patch support
│ └── sparql-update.js # SPARQL Update support
├── notifications/
│ ├── index.js # WebSocket plugin
│ ├── events.js # Event emitter
│ └── websocket.js # solid-0.1 protocol
├── idp/
│ ├── index.js # Identity Provider plugin
│ ├── provider.js # oidc-provider config
│ ├── adapter.js # Filesystem adapter
│ ├── accounts.js # User account management
│ ├── credentials.js # Credentials endpoint
│ ├── keys.js # JWKS key management
│ ├── interactions.js # Login/consent handlers
│ ├── passkey.js # WebAuthn/FIDO2 passkey support
│ ├── views.js # HTML templates
│ └── invites.js # Invite code management
├── ap/
│ ├── index.js # ActivityPub plugin
│ ├── keys.js # RSA keypair management
│ ├── store.js # SQLite storage (followers, activities)
│ └── routes/
│ ├── actor.js # Actor JSON-LD
│ ├── inbox.js # Receive activities
│ ├── outbox.js # User's activities
│ ├── collections.js # Followers/following
│ ├── mastodon.js # Mastodon API (apps, instance, verify_credentials)
│ └── oauth.js # OAuth 2.0 authorize/token flow
├── webledger.js # Web Ledger balance tracking (webledgers.org)
├── mrc20.js # State chain verification
├── remotestorage.js # remoteStorage protocol (draft-dejong-remotestorage-22)
├── rdf/
│ ├── turtle.js # Turtle <-> JSON-LD
│ └── conneg.js # Content negotiation
├── mashlib/
│ └── index.js # Mashlib data browser plugin
└── utils/
├── url.js # URL utilities
├── conditional.js # If-Match/If-None-Match
└── ssrf.js # SSRF protection
14 direct dependencies for a fast, secure server:
AGPL-3.0-only
This project is licensed under the GNU Affero General Public License v3.0. If you run a modified version as a network service, you must make the source code available to users of that service.
| Back | FazBrowse Home | New Git URL |