` (self-initializing). CSS is auto-derived by replacing `.js` with `.css`. Content negotiation is auto-enabled.
**How it works:**
1. Browser requests `/alice/public/data.ttl` with `Accept: text/html`
2. Server returns Mashlib HTML wrapper
3. Mashlib fetches the actual data via content negotiation
4. Mashlib renders an interactive, editable view
**Note:** Mashlib works best with `--conneg` enabled for Turtle support.
**Modern UI (SolidOS UI):**
```bash
jss start --mashlib --solidos-ui --conneg
```
Serves 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:
- Modern file browser with breadcrumb navigation
- Profile, Contacts, Sharing, and Settings views
- Path-based URLs (browser URL reflects current resource)
- Responsive design for mobile devices
Requires solidos-ui dist files in `src/mashlib-local/dist/solidos-ui/`. See [solidos-ui](https://github.com/solidos/solidos/tree/main/workspaces/solidos-ui) for details.
### Profile Pages
Pod profiles (`/alice/`) use HTML with embedded JSON-LD data islands and are rendered using:
- [mashlib-jss](https://github.com/JavaScriptSolidServer/mashlib-jss) - A fork of mashlib with `getPod()` fix for path-based pods
- [solidos-lite](https://github.com/SolidOS/solidos-lite) - Parses JSON-LD data islands into the RDF store
This allows profiles to work without server-side content negotiation while still providing full SolidOS editing capabilities.
### WebSocket Notifications
Enable real-time notifications for resource changes:
```javascript
const server = createServer({ notifications: true });
```
Clients discover the WebSocket URL via the `Updates-Via` header:
```bash
curl -I http://localhost:4443/alice/public/
# Updates-Via: ws://localhost:4443/.notifications
```
Protocol (solid-0.1, compatible with SolidOS):
```
Server: protocol solid-0.1
Client: sub http://localhost:4443/alice/public/data.json
Server: ack http://localhost:4443/alice/public/data.json
Server: pub http://localhost:4443/alice/public/data.json (on change)
```
## CLI Start Options
### Start Options
| Option | Description | Default |
|--------|-------------|---------|
| `-p, --port ` | Port to listen on | 4443 |
| `-h, --host ` | Host to bind to | 0.0.0.0 |
| `-r, --root ` | Data directory | ./data |
| `-c, --config ` | Config file path | - |
| `--ssl-key ` | SSL private key (PEM) | - |
| `--ssl-cert ` | SSL certificate (PEM) | - |
| `--conneg` | Enable Turtle support | false |
| `--notifications` | Enable WebSocket | false |
| `--idp` | Enable built-in IdP | false |
| `--idp-issuer ` | IdP issuer URL | (auto) |
| `--subdomains` | Enable subdomain-based pods | false |
| `--base-domain ` | Base domain for subdomains | - |
| `--mashlib` | Enable Mashlib (local mode) | false |
| `--mashlib-cdn` | Enable Mashlib (CDN mode) | false |
| `--mashlib-module ` | Enable ES module data browser from a URL | - |
| `--mashlib-version ` | 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 ` | Nostr relay WebSocket path | /relay |
| `--nostr-max-events ` | 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 ` | Default storage quota per pod (e.g., 50MB) | 50MB |
| `--activitypub` | Enable ActivityPub federation | false |
| `--ap-username ` | ActivityPub username | me |
| `--ap-display-name ` | ActivityPub display name | (username) |
| `--ap-summary ` | ActivityPub bio/summary | - |
| `--ap-nostr-pubkey ` | 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 ` | Cost per request in satoshis | 1 |
| `--pay-mempool-url ` | Mempool API URL for deposit verification | (testnet4) |
| `--pay-address ` | Address for receiving deposits | - |
| `--pay-token ` | Token to sell (enables primary market + withdrawal) | - |
| `--pay-rate ` | Sats per token for buy/withdraw | 1 |
| `--pay-chains ` | Multi-chain deposits + AMM (e.g. "tbtc3,tbtc4") | - |
| `--mongo` | Enable MongoDB-backed /db/ route | false |
| `--mongo-url ` | MongoDB connection URL | mongodb://localhost:27017 |
| `--mongo-database ` | MongoDB database name | solid |
| `--webrtc` | Enable WebRTC signaling server | false |
| `--webrtc-path ` | WebRTC signaling WebSocket path | /.webrtc |
| `--tunnel` | Enable tunnel proxy (decentralized ngrok) | false |
| `--tunnel-path ` | Tunnel WebSocket path | /.tunnel |
| `--terminal` | Enable WebSocket shell at `/.terminal` | false |
| `-q, --quiet` | Suppress logs | false |
### Environment Variables
All options can be set via environment variables with `JSS_` prefix:
```bash
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_SINGLE_USER=true
export JSS_SINGLE_USER_NAME=me
export JSS_SINGLE_USER_PASSWORD=choose-a-good-one # seeds IDP account on first start
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
export JSS_WEBRTC=true
jss start
```
### Config File
Create `config.json`:
```json
{
"port": 8443,
"root": "./data",
"sslKey": "./ssl/key.pem",
"sslCert": "./ssl/cert.pem",
"conneg": true,
"notifications": true
}
```
Then: `jss start --config config.json`
### Creating a Pod
```bash
curl -X POST http://localhost:4443/.pods \
-H "Content-Type: application/json" \
-d '{"name": "alice"}'
```
Response:
```json
{
"name": "alice",
"webId": "http://localhost:4443/alice/#me",
"podUri": "http://localhost:4443/alice/",
"token": "eyJ..."
}
```
### Single-User Mode
For personal pod servers where only one user needs access:
```bash
# Basic single-user mode (creates pod at /me/)
# On first run JSS will prompt for an initial password (TTY only).
jss start --single-user --idp
# Provide the initial IDP password non-interactively (systemd, containers, CI):
jss start --single-user --idp --single-user-password 'choose-a-good-one'
JSS_SINGLE_USER_PASSWORD='choose-a-good-one' 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 --idp
```
**Features:**
- Pod auto-created on first startup with full structure (inbox, public, private, profile)
- IDP account auto-seeded so the operator can log in immediately
- Registration endpoint disabled (returns 403)
- Login works for the single user via password (`POST /idp/credentials`) or any other configured method
- Proper ACLs generated automatically
**Initial password sources, in priority order:**
1. `--single-user-password ` CLI flag
2. `JSS_SINGLE_USER_PASSWORD` env var
3. Interactive no-echo prompt (TTY only)
4. None the server starts and warns; the pod is created but isn't loggable until you restart with `--single-user-password `, set `JSS_SINGLE_USER_PASSWORD`, or run on a TTY to be prompted. (`jss passwd ` does not work here it returns "User not found" until an account exists.)
The password is only consulted on the first start once an account exists, subsequent restarts skip the seed step and never overwrite it. The password is never written to the saved config file (`.jss/config`).
## Invite-Only Registration
Control who can create accounts by requiring invite codes:
```bash
jss start --idp --invite-only
```
### Managing Invite Codes
```bash
# 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
```
### How It Works
| 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:
- The registration page shows an "Invite Code" field
- Invalid or expired codes are rejected with an error
- Each use decrements the invite's remaining uses
- Depleted invites are automatically removed
Invite codes are stored in `.server/invites.json` in your data directory.
## Storage Quotas
Limit storage per pod to prevent abuse and manage resources:
```bash
jss start --default-quota 50MB
```
### Managing Quotas
```bash
# 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 alice
```
### How It Works
- Quotas are tracked incrementally on PUT, POST, and DELETE operations
- When quota is exceeded, the server returns HTTP 507 Insufficient Storage
- Each pod stores its quota in `/{pod}/.quota.json`
- Use `reconcile` to fix quota drift from manual file changes
### Size Formats
Supported formats: `50MB`, `1GB`, `500KB`, `1TB`
### Mashlib Data Browser
Enable the [SolidOS Mashlib](https://github.com/SolidOS/mashlib) data browser for RDF resources. Two modes are available:
**CDN Mode** (recommended for getting started):
```bash
jss start --mashlib-cdn --conneg
```
Loads mashlib from unpkg.com CDN. Zero footprint - no local files needed.
**Local Mode** (for production/offline):
```bash
jss start --mashlib --conneg
```
Serves mashlib from `src/mashlib-local/dist/`. Requires building mashlib locally:
```bash
cd src/mashlib-local
npm install && npm run build
```
**ES Module Mode** (for custom or next-gen mashlib builds):
```bash
jss start --mashlib-module https://example.com/mashlib.js
```
Loads an ES module-based data browser from any URL. Uses `` and `
` (self-initializing). CSS is auto-derived by replacing `.js` with `.css`. Content negotiation is auto-enabled.
**How it works:**
1. Browser requests `/alice/public/data.ttl` with `Accept: text/html`
2. Server returns Mashlib HTML wrapper
3. Mashlib fetches the actual data via content negotiation
4. Mashlib renders an interactive, editable view
**Note:** Mashlib works best with `--conneg` enabled for Turtle support.
**Modern UI (SolidOS UI):**
```bash
jss start --mashlib --solidos-ui --conneg
```
Serves 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:
- Modern file browser with breadcrumb navigation
- Profile, Contacts, Sharing, and Settings views
- Path-based URLs (browser URL reflects current resource)
- Responsive design for mobile devices
Requires solidos-ui dist files in `src/mashlib-local/dist/solidos-ui/`. See [solidos-ui](https://github.com/solidos/solidos/tree/main/workspaces/solidos-ui) for details.
### Profile Pages
Pod profiles (`/alice/`) use HTML with embedded JSON-LD data islands and are rendered using:
- [mashlib-jss](https://github.com/JavaScriptSolidServer/mashlib-jss) - A fork of mashlib with `getPod()` fix for path-based pods
- [solidos-lite](https://github.com/SolidOS/solidos-lite) - Parses JSON-LD data islands into the RDF store
This allows profiles to work without server-side content negotiation while still providing full SolidOS editing capabilities.
### WebSocket Notifications
Enable real-time notifications for resource changes:
```javascript
const server = createServer({ notifications: true });
```
Clients discover the WebSocket URL via the `Updates-Via` header:
```bash
curl -I http://localhost:4443/alice/public/
# Updates-Via: ws://localhost:4443/.notifications
```
Protocol (solid-0.1, compatible with SolidOS):
```
Server: protocol solid-0.1
Client: sub http://localhost:4443/alice/public/data.json
Server: ack http://localhost:4443/alice/public/data.json
Server: pub http://localhost:4443/alice/public/data.json (on change)
```