Introduction
Blocnet is a decentralized hosting platform. You push a site — it gets pinned across a distributed IPFS node network. No server to babysit. No availability to worry about. No bill at the end of the month.
Every deployment produces a content identifier (CID) — a cryptographic fingerprint of your site's files. That CID is immutable and permanent. You can verify it, share it, and it will resolve from any IPFS gateway on the planet. When you deploy a new version, the pointer updates; the old CID stays accessible forever.
IPFS (InterPlanetary File System) is a peer-to-peer network for storing and sharing files. Instead of a URL pointing to a server (like https://myserver.com/index.html), IPFS addresses content by what it is — a hash of the file contents. This means:
- No single point of failure — any node that has the content can serve it.
- Tamper-proof — if the content changes, the address changes. What you requested is guaranteed to be what you receive.
- Permanent — as long as at least one node pins your content, it's accessible.
Think of it like BitTorrent for websites: instead of one server hosting your files, the content lives across many nodes simultaneously.
Why blocnet?
No single company, server, or government can take your site down.
Every deployment gets a permanent CID. Old versions never disappear.
Install, register, deploy. From zero to live in under a minute.
Nothing to patch, no origin to DDoS, no region to go down.
Who is this for?
- Developers shipping static sites, SPAs, or documentation
- Projects that need censorship resistance or permanent URLs
- Anyone who wants immutable deployment history
- Builders tired of paying $20/month for three hobby projects
Quick Start
From zero to a live, permanently-hosted site in four steps.
Install the CLI
Install the blocnet CLI globally using npm. You'll need Node.js 18 or later.
$ npm install -g blocnetCreate an account
Register directly from the CLI. It'll ask for your email and password — no browser required.
$ blocnet register
Email: you@example.com
Password: ••••••••
Account created. Logged in as you@example.comAlready have an account? Use blocnet login instead.
Deploy your site
Navigate to your project's build output directory and run deploy. Blocnet zips your files, uploads them to IPFS, and gives you a live URL.
$ cd my-project/dist
$ blocnet deploy
Site: my-project.blocnet.cc
⠙ Packing files…
⠹ Uploading to IPFS…
✓ Deployed!
URL: https://my-project.blocnet.ccdist/. For Next.js with static export it's out/. For plain HTML, it's your project root.Open your site
Open the live URL in your browser directly from the terminal:
$ blocnet open
Opening https://my-project.blocnet.cc…Framework examples
Blocnet deploys the static output of any framework. Here's how to prep common setups:
npm run builddist/next build && next exportout/npm run builddist/npm run buildbuild/npm run builddist/—project rootHow It Works
Blocnet is a deployment layer on top of IPFS. Understanding the pieces makes debugging easier and builds confidence in the platform.
Content addressing vs. location addressing
Traditional web hosting serves files at a fixed URL — a location. If the server at that location goes down, the file is unreachable. IPFS addresses files by their content — a cryptographic hash that is unique to those exact bytes.
https://myserver.com/index.htmlQmXoypizjW3WknF
jJnVx1KVrmfQkr5...What is a CID?
A CID (Content Identifier) is the address of your content on IPFS. It's generated by hashing your files — the same files always produce the same CID, and different files always produce a different CID.
The deployment flow
Here's what happens when you run blocnet deploy:
- The CLI zips your build directory and uploads it to the blocnet API.
- The API unpacks the zip and uploads each file to Pinata (IPFS pinning service). A root CID is returned for the whole directory.
- The CID is saved in the database alongside your site's slug (e.g.
my-project). - Your
my-project.blocnet.ccURL is now live. The gateway resolves it.
How the gateway works
*.blocnet.cc is an HTTP gateway. When someone visits my-project.blocnet.cc:
- The gateway looks up
my-projectin the database and finds the active CID. - It fetches the requested path from IPFS (e.g.
CID/about/index.html). - It streams the file back to the browser with the correct
Content-Typeheader. - For client-side routed SPAs, unknown paths fall back to
index.htmlautomatically.
CLI Reference
All blocnet operations are available from the command line. The CLI stores your credentials at ~/.blocnet/config.json.
npm install -g blocnetCommands
blocnet registerCreate a new blocnet account. Prompts for email and password. Automatically saves credentials so you're logged in immediately.
$ blocnet register
Email: you@example.com
Password: ••••••••
Account created. Logged in as you@example.comblocnet loginAuthenticate an existing account. Saves a token to ~/.blocnet/config.json. Run this if you've logged out or switched machines.
$ blocnet login
Email: you@example.com
Password: ••••••••
Logged in as you@example.comblocnet logoutClear stored credentials. Deletes ~/.blocnet/config.json. You'll need to run login or register before deploying again.
$ blocnet logout
Logged out.blocnet deployZips a directory and deploys it to IPFS via the blocnet API. Creates a new site automatically on first deploy. Writes the site slug to a .blocnet-site file in the deployed directory so status and open work without the --site flag.
--dir <path> | Path to deploy. Defaults to the current directory (.). |
--site <id> | Redeploy to an existing site by ID instead of creating a new one. |
$ blocnet deploy --dir ./dist
Site: my-project.blocnet.cc
⠙ Packing files…
⠹ Uploading to IPFS…
✓ Deployed!
URL: https://my-project.blocnet.ccblocnet sitesList all sites associated with your account, with their URLs and deployment status.
$ blocnet sites
my-project my-project.blocnet.cc live
old-site old-site.blocnet.cc liveblocnet statusShow the deployment history for a site — each deploy's CID, date, and whether it's the current live version. Run from a deployed directory and --site can be omitted.
--site <slug> | Show status for a specific site. If omitted, reads .blocnet-site from the current directory. |
$ blocnet status
my-project https://my-project.blocnet.cc
# CID Date
2 QmXoypizjW3WknFj… 30 Apr 2026 14:00 latest
1 QmYoypizjW3WknFj… 29 Apr 2026 09:30blocnet openOpen the live URL for a site in your default browser. Works on macOS, Linux, and Windows.
--site <slug> | Open a specific site. If omitted, reads .blocnet-site from the current directory. |
$ blocnet open
Opening https://my-project.blocnet.cc….blocnet-site file to the deployed directory containing the site's slug. The status and open commands read this file automatically — so if you run them from the same directory, you don't need to specify --site.GitHub Integration
Connect a GitHub repository and every push to your production branch triggers an automatic build and deployment — no CI/CD setup required.
How it works
When you connect a repo, blocnet registers a webhook with GitHub. Every git push to the configured branch sends a notification to the blocnet API. The API clones the repo, runs your build command, and deploys the output to IPFS — exactly like blocnet deploy, but triggered automatically.
Setup
- Open your site in the Dashboard and click Connect GitHub.
- Authorize the blocnet GitHub App to access your repositories.
- Select the repository and the branch to deploy from (usually
main). - Set your build command and output directory (or leave as auto-detected).
- Click Connect. Push anything to the branch — the first automated deploy starts immediately.
Build configuration
Blocnet auto-detects the framework from your package.json. You can override this with a blocnet.json in your project root:
{
"buildCommand": "npm run build",
"outputDir": "dist",
"installCommand": "npm install"
}All three fields are optional. Defaults:
buildCommand— auto-detected (e.g.npm run build)outputDir— auto-detected (e.g.dist,out,build)installCommand—npm install
Supported frameworks
blocnet.json to specify an installCommand that sets these up..env files to your repository. Build-time environment variables can be set in the Dashboard under your site's settings.Custom Domains
Every site gets a free slug.blocnet.cc subdomain. You can also point your own domain — mysite.com, docs.mycompany.com, anything — at it.
Add a custom domain
- Open your site in the Dashboard and click Domains → Add domain.
- Enter your domain (e.g.
mysite.comorwww.mysite.com). - Blocnet shows you the DNS record to add. Copy it.
- Log in to your domain registrar and add the CNAME record.
- Wait for DNS propagation (usually 5–30 minutes, up to 48 hours in rare cases).
- Blocnet detects propagation automatically and provisions an SSL certificate.
DNS records
Add a CNAME record at your registrar pointing to proxy.blocnet.cc:
# Root domain (mysite.com)
@ CNAME proxy.blocnet.cc
# Subdomain (www.mysite.com)
www CNAME proxy.blocnet.cc
# Any subdomain (docs.mysite.com)
docs CNAME proxy.blocnet.ccCommon registrars — Cloudflare, Namecheap, Google Domains, GoDaddy — all support CNAME records. Look for a "DNS Management" or "DNS Records" section in your registrar's dashboard.
SSL certificates
SSL is automatic. Once blocnet detects your CNAME is live, it provisions a Let's Encrypt certificate — usually within 5 minutes of DNS propagation. Certificates renew automatically every 90 days. You never need to manage them.
*.mysite.com) are supported. Instead of a CNAME record, they require a DNS TXT record for Let's Encrypt validation. The Dashboard will provide the exact TXT record value when you add a wildcard domain.API Reference
The REST API lets you manage sites and trigger deployments programmatically. The CLI uses this API internally — anything the CLI can do, you can do directly via HTTP.
https://api.blocnet.ccAuthentication
All endpoints except /auth/register and /auth/login require a Bearer token. Get your token by calling login:
curl -X POST https://api.blocnet.cc/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","password":"yourpass"}'
# Response:
{ "token": "eyJhbGci...", "user": { "email": "you@example.com" } }Pass the token in all subsequent requests:
Authorization: Bearer eyJhbGci...Endpoints
/auth/registerpublicCreate a new account.
{ "email": "you@example.com", "password": "yourpass" }{ "token": "eyJhbGci...", "user": { "email": "you@example.com" } }/auth/loginpublicAuthenticate and receive a JWT token.
{ "email": "you@example.com", "password": "yourpass" }{ "token": "eyJhbGci...", "user": { "email": "you@example.com" } }/sitesList all sites for the authenticated user. Returns each site with its most recent deployment.
{ "sites": [{ "id": "...", "name": "My Site", "slug": "my-site",
"deployments": [{ "ipfsCid": "Qm...", "deployedAt": "..." }] }] }/sitesCreate a new site. The slug is auto-generated from the name.
{ "name": "My Site" }{ "site": { "id": "...", "name": "My Site", "slug": "my-site" } }/sites/slug/:slugGet full details for a site including the last 5 deployments and GitHub configuration.
{ "site": { "id": "...", "slug": "my-site", "name": "My Site",
"deployments": [...], "github": null } }/sites/:idDelete a site. This removes the registry entry (blocnet.cc URL stops resolving) but does not unpin IPFS content.
204 No Content/deployments/:siteIdDeploy a zip archive to a site. Send as multipart/form-data with an "archive" field containing the zip file.
multipart/form-data: archive=<zip file>{ "deployment": { "id": "...", "ipfsCid": "Qm...", "status": "active" },
"url": "https://my-site.blocnet.cc" }FAQ
Common questions from developers new to decentralized hosting.
Run a Node
Node operators extend the blocnet network by serving IPFS content from their own infrastructure. When your node is healthy, the blocnet gateway routes real user traffic through it — reducing latency for visitors near your region and making the network more resilient.
Requirements
Before you register, you need a server that is already running and reachable over HTTPS. Specifically:
- A publicly accessible server — a VPS, cloud VM (DigitalOcean, Hetzner, AWS EC2, etc.), or bare metal machine with a fixed IP address
- A domain name pointed at that server, e.g.
node1.example.com— this becomes your node's endpoint URL - A valid TLS certificate for that domain so the endpoint is reachable over
https://(Let's Encrypt / Certbot works fine) - Node.js 18+ installed on the server
- Outbound access from the server to IPFS gateways (port 443)
The endpoint is simply https:// + the domain you pointed at your server. For example, if you set up node1.example.com to point at your VPS and got an SSL certificate for it, your endpoint is https://node1.example.com. You will enter this when registering.
Step 1 — Register your node
- Log in and open the Dashboard.
- Click the Nodes tab.
- Click Register a Node and fill in the form:
- Name — a human-readable label for your own reference (e.g.
frankfurt-01) - Endpoint — the
https://URL of the domain you pointed at your server (e.g.https://node1.example.com). This is where blocnet will send traffic. - Region — choose the region closest to your server's physical location
- Name — a human-readable label for your own reference (e.g.
- Submit. Your node appears in the list with status Pending.
Step 2 — Await approval
The blocnet team reviews pending nodes manually. We check that the endpoint is reachable and the region is accurate. Approval typically takes 24–48 hours. You'll see the status change to Approved in your Dashboard.
Step 3 — Run the node daemon
The node daemon does two things: it serves IPFS content at /ipfs/:cid/*, and it sends a heartbeat to the blocnet API every 60 seconds so the gateway knows your node is alive. Any HTTP server that implements this contract qualifies. Here is a minimal reference implementation:
const express = require('express');
const app = express();
const NODE_KEY = process.env.BLOCNET_NODE_KEY;
const IPFS_GATEWAY = process.env.IPFS_GATEWAY || 'https://ipfs.io';
// Serve IPFS content — the gateway calls this endpoint
app.get('/ipfs/:cid/*', async (req, res) => {
const filePath = req.params[0] || 'index.html';
try {
const upstream = await fetch(
`${IPFS_GATEWAY}/ipfs/${req.params.cid}/${filePath}`
);
if (!upstream.ok) { res.status(upstream.status).send(); return; }
res.set(
'Content-Type',
upstream.headers.get('content-type') || 'application/octet-stream'
);
res.send(Buffer.from(await upstream.arrayBuffer()));
} catch {
res.status(502).send();
}
});
// Heartbeat — tells blocnet your node is alive
async function heartbeat() {
try {
await fetch('https://api.blocnet.cc/nodes/heartbeat', {
method: 'POST',
headers: { Authorization: `Bearer ${NODE_KEY}` },
});
} catch {}
}
setInterval(heartbeat, 60_000);
heartbeat(); // send one immediately on startup
app.listen(process.env.PORT || 3000, () =>
console.log('blocnet node daemon running')
);Install the single dependency and start the daemon:
npm install express
BLOCNET_NODE_KEY=<your-node-key> node server.jsIn production, run the daemon under a process manager (PM2, systemd, Docker) so it restarts automatically on crash. Example with PM2:
npm install -g pm2
BLOCNET_NODE_KEY=<your-node-key> pm2 start server.js --name blocnet-node
pm2 save
pm2 startup # follow the printed command to auto-start on rebootStep 4 — Verify the node is online
Once the daemon is running and sending heartbeats, refresh the Nodes tab in your Dashboard. The Last Heartbeat column should show a time within the last two minutes. The blocnet gateway will begin routing traffic to your node automatically — no further configuration needed.
API contract
The blocnet gateway expects two things from your node:
GET /ipfs/:cid/:filePath
# Example:
GET /ipfs/QmXyZ.../index.html
# Expected: 200 with the file body, correct Content-Type header
# On missing file: 404
# On upstream error: 502 or 500POST https://api.blocnet.cc/nodes/heartbeat
Authorization: Bearer <node-key>
# Expected: { "ok": true }
# Send every 60 seconds. Nodes with no heartbeat in the last 5 minutes
# are removed from routing automatically.