Deployment
Prerequisites
- Linux with
flockinstalled (apk add flockon Alpine, orapt install util-linuxon Debian/Ubuntu). The Docker image includes it. The service identity directory must use a local filesystem supporting file locks, atomic rename, and directory fsync; see service signing key history. - Node.js 20+
- pnpm (package manager)
- Domain with HTTPS (for OAuth callbacks)
did:webidentifier for the service
Step 1: Clone and Build
git clone https://github.com/NorthskySocial/stratos.git
cd stratos
pnpm install
pnpm buildStep 2: Create Service DID
Stratos serves its current key at /.well-known/did.json. Route that path to the service so rotations update the public document. The document has this shape; use the service's generated key, not the example value:
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:web:stratos.example.com",
"verificationMethod": [
{
"id": "did:web:stratos.example.com#atproto",
"type": "Multikey",
"controller": "did:web:stratos.example.com",
"publicKeyMultibase": "zQ3shXjHeiBuRCKmM36cuYnm7YEMzhGnCmCyW92sRJ9pribSF"
}
],
"service": [
{
"id": "#stratos",
"type": "StratosService",
"serviceEndpoint": "https://stratos.example.com"
}
]
}Step 3: Configure Environment
Create a .env file:
# Service Identity
STRATOS_SERVICE_DID="did:web:stratos.example.com"
STRATOS_SERVICE_FRAGMENT="atproto_pns"
STRATOS_PORT=3100
STRATOS_PUBLIC_URL="https://stratos.example.com"
# Storage
STRATOS_DATA_DIR="/var/lib/stratos/data"
STORAGE_BACKEND="sqlite"
# Blob Storage
STRATOS_BLOB_STORAGE="local"
# Identity Resolution
PLC_DIRECTORY="https://plc.directory"
# Enrollment
STRATOS_ENROLLMENT_MODE="allowlist"
STRATOS_ALLOWED_DIDS="did:plc:abc123,did:plc:def456"
# OAuth
STRATOS_OAUTH_CLIENT_ID="https://stratos.example.com/client-metadata.json"
STRATOS_OAUTH_REDIRECT_URI="https://stratos.example.com/oauth/callback"
# Boundaries
STRATOS_ALLOWED_DOMAINS="general,writers"
# AppViews
STRATOS_ALLOWED_APPVIEWS="did:web:appview.example.com"
STRATOS_LOG_LEVEL="info"See Configuration for all available variables.
Step 4: Create OAuth Client Metadata
Host this JSON at https://stratos.example.com/client-metadata.json:
{
"client_id": "https://stratos.example.com/client-metadata.json",
"client_name": "Stratos Private Namespace Service",
"client_uri": "https://stratos.example.com",
"redirect_uris": ["https://stratos.example.com/oauth/callback"],
"scope": "atproto repo:zone.stratos.actor.enrollment repo:zone.stratos.feed.post rpc:zone.stratos.feedgen.getFeed?aud=*",
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"application_type": "web",
"dpop_bound_access_tokens": true
}Step 5: Run the Service
# Direct
node dist/bin/stratos.js
# With PM2
pm2 start dist/bin/stratos.js --name stratos
# With systemd
sudo systemctl start stratosStep 6: Verify Deployment
# Health check
curl https://stratos.example.com/health
# {"status":"ok","version":"0.1.0"}
# DID document
curl https://stratos.example.com/.well-known/did.json
# Check enrollment status
curl "https://stratos.example.com/xrpc/zone.stratos.enrollment.status?did=did:plc:abc123"Add the Feed Generator
To serve private feeds, deploy the Rust stratos-feedgen-ng service with its own DID, signing key, feed list, and encrypted data volume. Do not reuse the older TypeScript feed generator's database. See Feed Generator for how it collects posts, checks membership, and protects local data.
Before startup, the feed generator's
did:webmust be under the Stratos-controlled space domain. For example, if Stratos usesdid:web:stratos.example.com, setFEEDGEN_SERVICE_DID=did:web:feeds.stratos.example.comandFEEDGEN_PUBLIC_URL=https://feeds.stratos.example.com. Configure DNS, HTTPS, and routing for that host. Grant the same DID service membership in each feed boundary through Stratos Enrollments; a feed registry entry alone grants no access. After startup, check the feed host's/.well-known/did.jsonand make an authenticated feed request.
Start it with a separate, empty database and test an authenticated feed request before changing traffic routing. Follow stratos-feedgen-ng/CUTOVER.md for comparison and rollback.