RoamRock

Hosting on the Internet Computer

How this site runs on ICP, step by step: one canister, a custom domain, and running costs under two dollars a year. If you have a static site, you can do the same in an afternoon.

What you get

What you need

1. Install the tools

sudo apt-get update
sudo apt-get install -y nodejs npm
sudo npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm
icp --version

2. Describe the canister

One file at the root of your project, icp.yaml, says there is one canister that serves a folder of static files:

canisters:
  - name: frontend
    recipe:
      type: "@dfinity/static-site@v0.3.3"
      configuration:
        dir: .icp-site

The static-site recipe uploads and certifies every file in that folder. No backend canister and no build tool are needed.

3. Stage only what you publish

Copy the public files into the staging folder, so that source art, scripts and notes never go live. List your domains in .well-known/ic-domains: ICP uses it to confirm the canister agrees to serve them.

rm -rf .icp-site
mkdir -p .icp-site/.well-known
cp index.html icp.html .icp-site/
cp -r assets .icp-site/
printf "example.com\nwww.example.com\n" > .icp-site/.well-known/ic-domains

Add .icp-site/ and .icp/ (local CLI state) to your .gitignore.

4. Try it locally

icp network start -d
icp deploy
# open the local URL it prints, then:
icp network stop

5. Create an identity and fund it

Your identity is the key that controls the canister. Create it once, keep its seed phrase in a password manager, and import that same identity on every machine you deploy from. A second identity is a different owner, and it cannot update a canister the first one created.

icp identity new my-site-deploy
icp identity default my-site-deploy
icp identity account-id --format ledger   # send a little ICP here
icp cycles mint --icp 1 --environment ic
icp cycles balance --environment ic

Run the cycles commands from inside your project folder: they read icp.yaml and fail with "project manifest not found" anywhere else.

6. Deploy to the network

icp deploy --environment ic frontend

It prints your canister ID, and the site is live at https://<canister-id>.icp.net/. This site's canister is ekyqj-aaaaa-aaaao-bbksq-cai.

7. Point your domain at it

Each domain needs three DNS records. For www:

TypeHostValue
CNAMEwwwwww.example.com.icp1.io
TXT_canister-id.wwwyour canister ID
CNAME_acme-challenge.www_acme-challenge.www.example.com.icp2.io

Once DNS has spread, register the domain and watch for its certificate:

curl -sL "https://icp.net/custom-domains/v1/www.example.com/validate"
curl -sL -X POST "https://icp.net/custom-domains/v1/www.example.com"
curl -sL "https://icp.net/custom-domains/v1/www.example.com"   # wait for "registered"

The bare domain (example.com) needs a DNS provider that allows a CNAME at the root, such as Cloudflare with the records set to DNS only. Some registrars' DNS, GoDaddy's included, cannot do this, so a subdomain is the quickest start.

8. Keep it running

A canister spends cycles every day just to exist, mostly for storage. If it runs out, it freezes, and a frozen canister is eventually deleted with the site in it. Checking the balance is the one piece of upkeep you cannot skip.

icp canister status <canister-id> --environment ic

Read three fields from the report and work out the runway:

reserve = idle cycles burned per day × freezing threshold (in days)
runway  = (cycles − reserve) ÷ idle cycles burned per day

This site's figures, from September 2026:

Balance1.49 trillion cycles
Burn3.5 billion cycles a day, about 1.3 trillion a year
Cost of a yearabout $1.70 (a trillion cycles costs about $1.35)
Runwayabout 390 days, after a 30-day freezing reserve

Top up when the runway drops below about 90 days, and look again after every deploy: if the memory size climbs each time, old files are piling up rather than being replaced.

icp cycles mint --cycles 1t --environment ic
icp canister top-up <canister-id> --amount 1t --environment ic

Keep your keys out of the repo

The seed phrase, identity password and any exported key file belong in a password manager, never in the project folder, a script or a chat. The canister ID and your principal are public; the key that controls them is not.

Further reading

Want your site on ICP without doing it yourself? hello@roamrock.com