tape deploy and share it
at https://<tape-address-base32>.tape.site/ on Tapenet. There is no server to run
or DNS to configure. You can add your own domain later.
What you need
- The
tapeCLI (install). - A configured local deployment, or a funded wallet from the Tapenet setup guide.
- A built site: a directory with an
index.htmlat its root. Any static site generator’s output works.
~/.config/solana/id.json, the CLI’s default. Pass
-k <path> for another keypair, and use -u <rpc url> or TAPE_RPC_URL to choose the
Solana RPC (CLI context).
1. Reserve a tape
A tape is prepaid storage: a capacity, for a number of epochs. Size it to your build with room for redeploys, and pick how long the site should stay up. The example below reserves 100 MiB for at least a week.--duration buys enough epochs to cover that time
at the network’s current epoch duration, which is one hour on Tapenet
(epochs). Pass --epochs <n> instead to buy an exact
number of epochs.
Check the price and your balance first. --dry-run spends nothing:
Output
Output
tape create checks that the wallet can pay before it signs anything. The expiry time is
an estimate based on the network’s current epoch duration.
The tape’s keypair is saved under ~/.tape/cassettes/ and the tape becomes the active one, so the next commands need no --tape flag. Keep the keypair: it is the only thing that can write to this tape.
2. Upload the site
Output
.well-known/ namespace is never published and cannot be enabled with an
override, so tape content cannot answer domain-ownership or ACME challenges.
Check what landed:
Output
3. Open it
Open theURL that tape deploy printed and share it. Visitors do not need a wallet or
the CLI. The subdomain is the tape address encoded as lowercase base32, because hostnames
are case-insensitive while tape addresses are not; the CLI does the encoding for you.
The reservation controls how long the site is stored. tape info shows the estimated
expiry time, and tape extend --duration 7d adds another week.
Paths map to object names. / serves index.html, /docs/ serves docs/index.html, /app.css serves app.css, and a path with no object serves your 404.html with status 404. A request for /docs without the trailing slash redirects to /docs/, so relative links inside the page resolve.
The URL uses tape.site, Tapenet’s site domain. For a local deployment or your own
gateway, set TAPE_SITE_DOMAIN (or site_domain in the
CLI config) to its configured site domain, or use
the /site/{tape}/ route.
4. Use your own domain (optional)
Thetape.site URL is ready to share without this step. To use a domain you own,
choose a gateway with self-serve domains enabled (txt_domains: true).
Add two DNS records at your domain:
https://example.com/ from the domain root. Nothing else is needed. Confirm with:
Redeploy
Run the same command again after a rebuild:Output
--prune to
remove stale names after the new entry point is safely published, or delete a
single name with tape object rm <name>.
Frameworks
Astro.astro build output deploys as it is. Nested routes, hashed assets and images all work. Astro’s default output puts each page at about/index.html, and the gateway’s redirect from /about to /about/ handles the links.
Vite, React Router, or any single-page app. On tape.site,
the site is served from the domain root. Add a settings file to the build output
so unknown routes serve the index page instead of the 404 page:
dist/_site.json
/missing.png still returns 404. The gateway honours _site.json unless the operator has turned per-site settings off (site settings).
If you serve through a gateway’s /site/{tape}/ path instead, build with relative
asset URLs (vite build --base=./) and configure your router’s base path to match
that prefix.
Next.js. Use output: 'export' and deploy the out directory. A dapp that calls an RPC from the browser lists its endpoints in _site.json under connect_origins (site settings).
Put Cloudflare in front
If your domain is on Cloudflare, proxy the record from step 4 (the orange cloud). Hashed assets are cached at the edge on the second request. HTML pages are not cached by default and need a cache rule on your zone if you want them cached. The operator side is under fronting with a CDN below.Deploy from CI with an S3 tool
If your pipeline already speaks S3, the gateway’s S3 endpoint accepts the same site as a bucket sync:--checksum to rclone: ETags here are not MD5 hashes, so rclone would compare sizes instead and miss a changed file of the same length.
Troubleshooting
For operators
The rest of this page is the gateway side: what the site route does, and the settings that give sites domains, caching and a CDN.Site conventions
Single-page apps can opt into serving
index.html for unknown paths instead of the 404 page, per site through _site.json below, or gateway-wide with the operator’s site.spa_fallback setting (off by default).
Custom domains and subdomains
A gateway can serve sites by hostname, from the domain root, with no path prefix. Three forms:txt_domains on, any domain owner can attach their domain with two DNS records and no operator involvement:
subdomain_suffix, wildcard DNS plus a wildcard certificate gives every tape a hostname with zero per-site setup; the subdomain label is the lowercase encoding printed by tape info and included in the URL tape deploy prints, because hostnames are case-insensitive while tape addresses are not.
Host-served sites each get their own browser origin, which is the real tenant isolation story: cookies and storage on one site are invisible to every other. The path-based /site/ route shares the gateway’s origin across sites, fine for previews and internal use.
Site settings on the tape
A site can carry its own serving settings as a reserved object named_site.json at the tape root, synced like any other file:
site.tenant_overrides: false, which ignores per-site settings entirely.
Caching
Names are pointers that can be re-aimed at new tracks, so site responses are cached briefly and revalidated:Cache-Control: public, max-age=60, must-revalidate with the content commitment as ETag, answering 304 Not Modified to If-None-Match. A redeploy propagates within a minute, and unchanged files revalidate without re-downloading.
Fronting with a CDN
Any pull-through CDN works, and the general guidance in serving through a CDN applies. For Cloudflare in front of a custom-domain site, the operator side:- Add the site hostname to
gateway.site.domainsand CNAME it to the gateway, proxied. - Trust Cloudflare’s edges in gateway config so per-visitor metering follows the real client IP.
trusted_proxiesaccepts CIDR ranges:
- Nothing else. The gateway’s revalidation headers mean the edge re-checks every minute with a cheap
304instead of re-downloading, andRangerequests pass through.
/* to /site/<tape>/$1 serves a path-based site the same way.
Cross-origin reads
When another origin needs to fetch site content (an app embedding hosted assets), allow it explicitly:Access-Control-Allow-Origin. With no entries, site content is same-origin only.
Calling APIs from hosted pages
A dapp needs its RPC endpoint, and by default the content security policy keeps hosted pages same-origin, so browser calls to external APIs are blocked. Allow endpoints explicitly:connect-src, so hosted pages can fetch and open websockets to them; a single "*" entry allows any endpoint. Wallet extensions inject their own providers and are unaffected either way. With this set, a statically exported dapp (for example a Next.js output: 'export' build published with tape deploy) runs entirely from the tape.
Boundaries
Site responses carryX-Content-Type-Options: nosniff and a same-origin content security policy, and the gateway sets no cookies. Site reads are metered separately from object reads, with headroom sized for multi-asset page loads (rate limits). Route details live in the gateway API reference.