Skip to main content

Shelby Sites — Static Website Hosting

Deploy static websites to immutable Shelby blobs — a Vercel-like deploy flow on decentralized storage. Every file in your ZIP becomes a content-addressed blob on Shelbynet, served at a public URL with full SHA-256 verification.

Quick Start​

# 1. Create a site
curl -X POST https://your-app.vercel.app/api/sites \
-H "Content-Type: application/json" \
-H "X-Provenode-Token: $TOKEN" \
-d '{"name": "My Portfolio", "slug": "my-portfolio"}'

# 2. Zip your static build and deploy
zip -r site.zip dist/
curl -X POST https://your-app.vercel.app/api/sites/$SITE_ID/deploy \
-H "X-Provenode-Token: $TOKEN" \
-F file=@site.zip

# 3. Visit your site
open https://your-app.vercel.app/s/my-portfolio

How It Works​

ZIP upload ──▶ unpack + MIME sniff ──▶ per-file SHA-256
│ │
▼ ▼
Shelby blob per file manifest blob (__manifest.json)
sites/<slug>/<depId>/<path> sites/<slug>/<depId>/__manifest.json
  1. Upload — POST a ZIP (or single HTML file) to /api/sites/:id/deploy
  2. Unpack — the server extracts entries, skips junk (__MACOSX/, .DS_Store), and sniffs MIME types per extension
  3. Store — each file is uploaded as an immutable Shelby blob at sites/<slug>/<deploymentId>/<path>; a __manifest.json blob records every file's path, size, SHA-256, and objectId
  4. Serve — /s/:slug/* resolves the latest deployment's manifest, fetches the blob from Shelby, and streams it with the correct Content-Type and a 60s edge cache
  5. SPA fallback — unknown paths fall back to path.html, then path/index.html, then index.html

Each deployment is an immutable snapshot — like a Vercel preview. Redeploy to the same slug to update the public URL.

API Reference​

MethodRouteDescription
GET/api/sitesList all sites
POST/api/sitesCreate site { name, slug?, description?, framework? }
GET/api/sites/:idOrSlugGet site + deployment history
DELETE/api/sites/:idOrSlugDelete site + all deployments
POST/api/sites/:id/deployDeploy ZIP / HTML / JSON files
POST/api/sites/:id/rollbackPromote an existing deployment to production
GET/api/sites/:id/deploymentsList deployments
GET/api/sites/:id/serve/<path>Serve latest deployment file
GET/api/sites/:id/preview/:depId/<path>Preview a specific deployment

Deploy Request Formats​

Multipart ZIP (recommended):

-F file=@site.zip # ZIP containing index.html at root
-F entry=index.html # optional entry override

Single HTML file:

-F file=@index.html # becomes index.html automatically

JSON body:

{
"html": "<h1>Hello</h1>"
}

or

{
"files": [
{ "path": "index.html", "contentBase64": "..." },
{ "path": "assets/app.js", "contentBase64": "..." }
]
}

Instant Rollback​

Every deployment is an immutable snapshot whose blobs stay on Shelby. Rolling back therefore does not re-upload anything — it only moves the production pointer, so it completes in milliseconds and is itself reversible.

In the console: Sites → your site → Deployments → Rollback to this. The live deployment is marked LIVE.

curl -X POST https://your-app.vercel.app/api/sites/$SITE_ID/rollback \
-H "Content-Type: application/json" \
-H "X-Provenode-Token: $TOKEN" \
-d '{"deploymentId": "dep_abc123"}'

Response includes the promoted deployment and the public URL. Each rollback is written to the audit log (site.rolled_back), dispatched to webhooks, and appended to the site's rollbackHistory (last 20 entries).

Limits​

LimitValue
Upload size (ZIP)50 MB
Total per deployment40 MB
Files per deployment200
Max single file10 MB
Blob lifetime90 days (auto-renewed by cron)

Push-to-Deploy from GitHub​

Deploy automatically on every git push — GitHub Actions builds, Provenode hosts on Shelby.

1. Create a deploy key​

In the console: Sites → your site → GitHub → Create deploy key. Or via API:

curl -X POST https://your-app.vercel.app/api/sites/$SITE_ID/keys \
-H "X-Provenode-Token: $TOKEN"
# → { "token": "pvnd_..." } # shown ONCE — store it now

The key is site-scoped: it can only deploy that one site and is revoked by deleting it. Add it to your repo as the PROVENODE_DEPLOY_KEY secret (Settings → Secrets and variables → Actions).

2. Add the workflow​

Save as .github/workflows/deploy.yml (the Sites console generates this pre-filled):

name: Deploy to Provenode
on:
push:
branches: [main]
pull_request:

jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write # comments preview URLs on PRs
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }

- name: Build
run: npm ci && npm run build

# If your build outputs to dist/, zip that folder:
# cd dist && zip -r ../site.zip .
- name: Package
run: zip -r site.zip .

- name: Deploy to Provenode
env:
PROVENODE_KEY: ${{ secrets.PROVENODE_DEPLOY_KEY }}
run: |
curl -sf -X POST "$PROVENODE_URL/api/sites/$SITE_ID/deploy" \
-H "Authorization: Bearer $PROVENODE_KEY" \
-F file=@site.zip -o deploy_result.json
cat deploy_result.json

- name: Comment preview URL on PR
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
URL=$(node -e "console.log(JSON.parse(require('fs').readFileSync('deploy_result.json')).previewUrl)")
gh pr comment "$PR_NUMBER" --body "Shelby preview: $PROVENODE_URL$URL"

3. Push​

  • main → deploys to production at /s/your-slug
  • Pull requests → immutable preview deployment, URL commented on the PR
  • Redeploying to the same slug atomically flips production to the new snapshot

CI auth model​

CredentialHeaderScope
Admin token (DEPLOY_SECRET)X-Provenode-Tokenall sites
Site deploy key (pvnd_...)Authorization: Bearer pvnd_...one site only

Key routes: POST /api/sites/:id/keys (create, returns token once) · GET /api/sites/:id/keys (list, masked) · DELETE /api/sites/:id/keys/:token (revoke — accepts masked prefix).

Verification​

Every deployment manifest is itself a Shelby blob. To audit a live site:

# Fetch the manifest from Shelby
curl "$SHELBY_RPC/shelby/v1/blobs/$ADDRESS/sites/my-portfolio/$DEP_ID/__manifest.json"

# Check any served file against its recorded SHA-256
curl -s https://your-app.vercel.app/s/my-portfolio/app.js | sha256sum

A hash mismatch between served content and the manifest means the site was tampered with — this is impossible on traditional CDNs where the origin can be silently edited.

Frameworks​

FrameworkBuild commandZIP root
Vitevite builddist/
Next.jsnext build (static export)out/
Astroastro builddist/
CRAnpm run buildbuild/
Plain HTML—.

Console​

The Sites page in the console (/app/sites) provides:

  • Site creation with automatic slug preview
  • Drag-and-drop ZIP deployment
  • Deployment history with file counts and sizes
  • Inline iframe preview of the live site
  • Copyable public URLs

FAQ​

Is this a Neon replacement? No. Shelby is blob storage, not Postgres. Use Shelby Sites for your frontend and immutable assets; pair it with Neon/Upstash for mutable state.

What happens after 90 days? The expiry cron re-anchors manifests before expiry and emails a warning 7 days ahead. Sites with traffic renew automatically.

Custom domains? Roadmap — a CNAME-based gateway with automatic TLS is planned. Today every site lives at /s/<slug>.