| name | host-website |
| description | Deploy and update static websites on Swarm via one-off or feed-based publishing, with optional ENS integration and stamp lifecycle notes. |
| user-invocable | true |
Host a Website on Swarm
Guide a developer through hosting a static website on Swarm. Ask which method they prefer (swarm-cli or bee-js), then walk them through step by step.
Formatting
When presenting to the user, use consistent labels before each code block:
- Run in your terminal: — a command the user should execute
- Expected output: — example of what a successful result looks like
- Save as
filename: — file contents the user should write to disk
Add a --- horizontal rule before each labeled code block to visually separate it from surrounding text.
Before Starting (run immediately)
Silently check node status (curl -s http://localhost:1633/node) and stamp availability (swarm-cli stamp list). If the node is down, offer to walk through /setup-bee-interactive. If no usable stamp exists, route to /stamps.
Then present the prerequisites to the user:
Prerequisites
- Static website files with at least an
index.html (common output folders: dist/, build/, out/, public/)
- swarm-cli installed (handled by
/setup-bee-interactive — if missing, run that first)
- If using bee-js instead:
npm install @ethersphere/bee-js in your project
Ask the user to confirm they have these before continuing.
Decision: One-time upload vs Feed (updateable)
Ask: "Will you need to update this website later, or is this a one-time deploy?"
- One-time → Upload by hash (simpler, but new hash on every change, requires ENS update each time)
- Updateable → Use a Feed (fixed manifest URL, update content without changing ENS)
Always recommend Feeds for production websites.
Method 1: swarm-cli
One-time upload
swarm-cli upload ./website \
--stamp <BATCH_ID> \
--index-document index.html \
--error-document 404.html
Access at: http://localhost:1633/bzz/<SWARM_HASH>/
Feed-based (recommended)
Step 1: Create publisher identity (first time only)
swarm-cli identity create website-publisher --password <SECURE_PASSWORD>
Save the output securely. To export later: swarm-cli identity export website-publisher --password <SECURE_PASSWORD>
Step 2: Upload to feed
swarm-cli feed upload ./website \
--identity website-publisher \
--topic-string website \
--stamp <BATCH_ID> \
--index-document index.html \
--error-document 404.html \
--password <SECURE_PASSWORD>
Save the manifest hash from the "Feed Manifest URL" output (the part after /bzz/). This is the permanent reference — it never changes.
Step 3: Update the site (repeat as needed)
Run the same feed upload command with updated files. Same identity + topic = same manifest URL.
Method 2: bee-js
One-time upload
import { Bee } from "@ethersphere/bee-js";
const bee = new Bee("http://localhost:1633");
const batchId = "<BATCH_ID>";
const result = await bee.uploadFilesFromDirectory(batchId, "./website", {
indexDocument: "index.html",
errorDocument: "404.html"
});
console.log("Swarm hash:", result.reference.toHex());
Feed-based (recommended)
Generate a publisher key (first time only)
import crypto from "crypto";
import { PrivateKey } from "@ethersphere/bee-js";
const hexKey = "0x" + crypto.randomBytes(32).toString("hex");
const privateKey = new PrivateKey(hexKey);
console.log("Private key:", privateKey.toHex());
console.log("Public address:", privateKey.publicKey().address().toHex());
Security: Store this private key securely (e.g., environment variable or encrypted keyfile). Never commit it to version control. Losing this key means losing the ability to update this feed.
Upload website + create feed
import { Bee, Topic, PrivateKey } from "@ethersphere/bee-js";
const bee = new Bee("http://localhost:1633");
const batchId = "<BATCH_ID>";
const privateKey = new PrivateKey("<PUBLISHER_KEY>");
const owner = privateKey.publicKey().address();
const topic = Topic.fromString("website");
const writer = bee.makeFeedWriter(topic, privateKey);
const upload = await bee.uploadFilesFromDirectory(batchId, "./website", {
indexDocument: "index.html",
errorDocument: "404.html"
});
console.log("Website Swarm Hash:", upload.reference.toHex());
await writer.uploadReference(batchId, upload.reference);
const manifestRef = await bee.createFeedManifest(batchId, topic, owner);
console.log("Feed Manifest:", manifestRef.toHex());
Update the site
const newUpload = await bee.uploadFilesFromDirectory(batchId, "./website", {
indexDocument: "index.html",
errorDocument: "404.html"
});
await writer.uploadReference(batchId, newUpload.reference);
Connect to ENS Domain (optional)
After uploading, ask: "Do you want to connect this to an ENS domain?"
If yes:
- Go to app.ens.domains → open your domain → Records tab
- Add Content Hash with value:
bzz://<MANIFEST_HASH>
- Confirm the transaction
Once registered, the site is accessible at:
https://yourname.eth.limo/
https://yourname.bzz.link/
http://localhost:1633/bzz/yourname.eth/
Use the feed manifest hash (not the website hash) so future updates don't require ENS changes.
ENS localhost note
Some RPC endpoints don't resolve ENS on localhost. Working alternatives:
https://mainnet.infura.io/v3/<your-key>
https://eth-mainnet.public.blastapi.io
- Your own Ethereum node
Stamp Expiry Warning
When your stamp expires, your website becomes inaccessible — silently. ENS will still resolve but the content will be gone.
- Monitor stamp TTL:
swarm-cli stamp show <stamp-id>
- Top up before expiry:
swarm-cli stamp topup --stamp <stamp-id> --amount <amount>
- Set a calendar reminder for stamp renewal
- For production sites, use stamps with 6+ month duration
ENS Prerequisites
ENS integration requires:
- An existing ENS name (buy at app.ens.domains)
- A funded Ethereum mainnet wallet (ETH for gas)
- Familiarity with ENS content records
If you don't have these, use the raw bzz:// link or Beeport instead.
Conceptual Questions
For any conceptual or technical question not covered by the steps above, invoke /docs to find the relevant authoritative source rather than answering from prior knowledge.
Reference