I launched this very website on the Internet Computer using Claude Code and the ICP CLI, and I turned that real workflow into the step-by-step guide below so you can do the same thing. This is a practical Claude Code + ICP CLI guide for beginners: from no Ubuntu setup to a deployed website on the Internet Computer, with a custom domain workflow you can reuse for your own project.
Who this is for: creators, founders, coaches, communities, small businesses, and builders who want to put a real website on ICP without manually coding every file. What you will build: a static website generated and edited with Claude Code, configured with icp.yaml, deployed with the icp command, and optionally mapped to your domain. One important promise up front: this guide uses ICP CLI commands only — it is written for practical deployment, not theory. Use it as a template and replace the example domain example.com, project name my-icp-site, and canister name frontend with your own values.
The 10-step roadmap
You do not need to understand every part before starting. Work through the steps in order and let Claude Code help you generate, edit, and troubleshoot the project files.
| Step | What you do |
|---|---|
| 1. Install Ubuntu | Use WSL on Windows, or use your normal terminal on Mac/Linux. |
| 2. Install Node.js + basics | Install Git, build tools, curl, and a current Node.js LTS. |
| 3. Install Claude Code | Run Claude Code in your project folder and use it as your coding partner. |
| 4. Install ICP CLI | Install the icp command and its companion tool with npm. |
| 5. Create the website | Use Claude Code to create the HTML/CSS/JS or Vite project. |
| 6. Add ICP config | Create icp.yaml and .ic-assets.json5 for the asset canister. |
| 7. Test locally | Build the site and deploy to a local ICP network. |
| 8. Deploy to ICP | Deploy the frontend canister to mainnet with ICP CLI. |
| 9. Add your domain | Add DNS records, deploy /.well-known/ic-domains, and register the domain. |
| 10. Update safely | Make edits, build, deploy or sync, and keep backups. |
The fastest path is a static or static-generated website. Add backend canisters later only when you need logins, payments, user data, or dynamic application logic.
Step 1: Install Ubuntu on Windows
If you are on Windows, use Windows Subsystem for Linux so your development environment behaves like a Linux server. Microsoft documents installing WSL with the wsl --install command; new installs default to WSL 2. Mac and Linux users can skip this step and use Terminal.
Run this in PowerShell as Administrator:
wsl --install -d Ubuntu # After install, restart if Windows asks you to. # Then open Ubuntu from the Start menu and create your Linux username/password.
Confirm WSL is working:
wsl --list --verbose
Inside Ubuntu, update packages and install basic tools:
sudo apt update && sudo apt upgrade -y sudo apt install -y curl git build-essential ca-certificates unzip
Good habits from the beginning:
- Keep website projects in your Linux home folder, for example ~/icp-sites.
- Avoid spaces in project folder names. Use names like my-icp-site.
- Use Git so you can undo mistakes Claude Code or you make.
- Do not paste seed phrases, private keys, or account recovery phrases into Claude Code.
Step 2: Install Node.js and Claude Code
Claude Code and ICP CLI both use npm-based installation paths. Claude Code's npm install requires Node.js 18 or later, while the current ICP quickstart recommends Node.js LTS v22+. Use a current LTS version when possible.
Install Node.js and npm:
sudo apt install -y nodejs npm node --version npm --version
If your Node version is below the required version, install a newer LTS version before continuing. Ask Claude Code or check Node.js/Ubuntu docs for your current best install path.
Set npm global packages to install without sudo:
mkdir -p ~/.npm-global npm config set prefix ~/.npm-global echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc source ~/.bashrc
Install Claude Code:
npm install -g @anthropic-ai/claude-code claude
Claude plan recommendation
For serious website building, a paid Claude plan saves time. The $100/month Max 5x plan gives substantially more usage than Pro and includes access to Claude Code; the $200/month Max 20x tier is for daily heavy use. Pricing can change, so check Anthropic before buying.
When Claude Code asks which model to use, choose the highest Opus model available for planning, architecture, large refactors, and debugging. You can use faster/cheaper models for tiny edits, but Opus is usually worth it when the project is unfamiliar or the deployment is breaking.
Step 3: Install ICP CLI
ICP CLI is the command-line tool used here to build and deploy ICP projects. The official quickstart installs the ICP CLI package and the WebAssembly optimization tool through npm.
npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm icp --version ic-wasm --version
If you plan to build Motoko backends later, also install the Motoko package manager:
npm install -g ic-mops
For a simple static website, you may not need Motoko or Rust yet. Start with the asset canister path first, then add backend logic when the site actually needs it.
Optional local network dependency
On Windows, ICP's quickstart notes that local networks require WSL and Docker Desktop. If you only deploy to mainnet, you may not need the local network at first, but local testing is useful before publishing changes.
Quick sanity check:
mkdir -p ~/icp-sites cd ~/icp-sites icp --help
Step 4: Start a new website project
Create a dedicated folder for the website and run Claude Code from the project root. Do not run Claude Code from a huge parent folder full of unrelated projects.
mkdir -p ~/icp-sites cd ~/icp-sites mkdir my-icp-site cd my-icp-site claude
Starter prompt for Claude Code
Create a clean static website project that can be deployed to ICP with ICP CLI. Requirements: - Use a simple static or Vite-based frontend. - Keep the project lightweight and easy to understand. - Add a README with build and deploy commands. - Add an icp.yaml configured for an asset canister named frontend. - Add .ic-assets.json5 in the public folder. - Do not deploy automatically. - Before editing, inspect the folder and explain your plan. - After editing, summarize every file changed and how to preview/build/deploy.
What Claude should create
| File or folder | Purpose |
|---|---|
| package.json | Scripts such as npm run dev and npm run build. |
| src/ or index.html | Your website source files. |
| public/ | Static files copied into the build output. |
| public/.ic-assets.json5 | Asset canister rules, security headers, SPA fallback, hidden file handling. |
| icp.yaml | ICP CLI project configuration and asset canister recipe. |
| README.md | How to edit, build, deploy, and maintain the site. |
Step 5: Work with Claude Code correctly
Claude Code is powerful because it can inspect files, write code, run commands, and fix errors. Treat it like a fast junior developer with excellent memory: useful, but still requiring your review.
Good operating rules:
- Ask Claude to inspect the project before editing.
- Ask for a plan, approve the plan, then let it edit.
- Use Git before major changes: git init, git add ., git commit.
- Do not approve commands you do not understand. Ask Claude to explain them.
- Keep deploy commands separate from code-generation commands so you control publishing.
Useful Claude prompts:
Inspect this project and tell me exactly how it builds and deploys with ICP CLI. Do not edit files yet. Fix the build errors. Make the smallest safe changes and explain what changed. Add a new page, but preserve the existing design system and do not break deployment. Review this site for mobile layout, accessibility, broken links, and deployment issues. Prepare this for ICP deployment, but do not run the mainnet deploy command until I approve.
For complex work, use the highest Opus model available. The extra reasoning is usually cheaper than wasting hours chasing broken configs.
Step 6: Add ICP asset canister configuration
For a website, the simplest ICP deployment target is an asset canister. It hosts static files like HTML, CSS, JavaScript, and images directly on ICP. ICP's asset canister docs explain that ICP CLI deploys a pre-built asset canister, creates it if needed, installs it, and syncs your build output directory.
Example icp.yaml:
canisters:
- name: frontend
recipe:
type: "@dfinity/asset-canister@v2.2.1"
configuration:
dir: dist
build:
- npm install
- npm run build
The important parts:
- frontend is the canister name you deploy and update.
- dir: dist must match the output folder created by your build command.
- build tells ICP CLI what to run before upload.
Example public/.ic-assets.json5:
[
{
"match": ".well-known",
"ignore": false
},
{
"match": "**/*",
"security_policy": "standard",
"headers": {
"Cache-Control": "public, max-age=0, must-revalidate"
},
"allow_raw_access": false
},
{
"match": "assets/**/*",
"headers": {
"Cache-Control": "public, max-age=31536000, immutable"
}
},
{
"match": "**/*",
"enable_aliasing": true
}
]
Step 7: Build and test locally
Before deploying to mainnet, build the site and verify that the output folder exists. Most failed deployments are simple build/output-folder problems.
Build the website:
npm install npm run build ls -la dist
Start a local ICP network and deploy:
icp network start -d icp network ping icp deploy
Open the frontend URL shown in the deploy output. It will look like:
http://<canister-id>.localhost:8000/
Check project and canister state:
icp project show icp canister list icp canister status frontend
When finished:
icp network stop
If local testing fails, ask Claude Code to read the error and fix the smallest likely problem. Common issues are missing Node packages, a wrong build output folder, or a canister name mismatch.
Step 8: Deploy to ICP mainnet
Mainnet deployment puts your website on the public Internet Computer. Your frontend will be accessible at a canister URL first, then you can map a custom domain.
Build one last time:
npm run build
Deploy the frontend canister to mainnet:
icp deploy -e ic frontend
Your output should include a canister ID and a URL like:
https://<canister-id>.icp.net/
Verify the canister:
icp canister status frontend
If your deploy fails because the canister needs cycles or an identity setup, pause and follow the current ICP CLI guidance shown in your terminal. Run these help commands to see the exact current workflow:
icp identity --help icp cycles --help icp token --help
Security rule: keep your identity files and recovery material private. Never paste private keys, seed phrases, or account recovery text into Claude Code, chat tools, screenshots, or public support forums.
Step 9: Connect your own domain
By default, your site is live at the canister URL. To use your own domain, you need DNS records, a domain ownership file served by the canister, and a registration API call. Replace example.com with your domain.
Add the domain ownership file:
mkdir -p public/.well-known echo 'example.com' > public/.well-known/ic-domains npm run build icp deploy -e ic frontend
Verify the file is live:
curl -sL https://<canister-id>.icp.net/.well-known/ic-domains
Add DNS records at your DNS provider:
| Type | Name / Host | Value |
|---|---|---|
| CNAME or ALIAS | example.com | example.com.icp1.io |
| TXT | _canister-id | <canister-id> |
| CNAME | _acme-challenge | _acme-challenge.example.com.icp2.io |
Cloudflare note: use DNS only, not proxied, while registering. If Cloudflare Universal SSL interferes with certificate validation, disable it during registration and re-enable only after the domain is working.
Validate and register:
curl -sL -X GET "https://icp.net/custom-domains/v1/example.com/validate" curl -sL -X POST "https://icp.net/custom-domains/v1/example.com" curl -sL -X GET "https://icp.net/custom-domains/v1/example.com"
Wait for certificate provisioning. If the browser shows a certificate warning immediately after registration, give it several minutes, then test again in a private/incognito window.
Step 10: Update, sync, and maintain
Once the site is live, your normal workflow is simple: edit, build, test, deploy, verify. Keep changes small and recoverable.
Everyday update workflow:
git status # edit with Claude Code npm run build icp deploy -e ic frontend # or, when only static assets changed: icp sync -e ic frontend
When to use deploy vs sync:
| Use | When |
|---|---|
| icp deploy -e ic frontend | You changed config, build process, or anything that may need a full reinstall/update. |
| icp sync -e ic frontend | You only changed built static assets and want to upload changed files faster. |
Troubleshooting checklist:
- Build output empty? Confirm dir in icp.yaml matches the real output folder.
- 404 on refresh? Make sure .ic-assets.json5 has enable_aliasing: true.
- Custom domain validation fails? Check DNS, the .well-known file, and hidden-directory handling.
- Wrong site deploys? Check the canister name in icp.yaml and the deploy command.
- Ask Claude to explain every error message before trying random fixes.
Reusable Claude Code prompt
Use this prompt when you want Claude Code to create or repair an ICP website project. Replace bracketed text with your own details.
I want to launch a website on ICP using ICP CLI. Project goal: [Describe your website: business site, community page, portfolio, app landing page, etc.] Requirements: - Build a clean, fast, mobile-friendly static website. - Configure it for ICP CLI with an asset canister named frontend. - Use icp.yaml for deployment configuration. - Use public/.ic-assets.json5 for asset settings. - Include support for a future custom domain by adding public/.well-known/ic-domains with placeholder domain example.com. - Use npm scripts: dev, build, preview if applicable. - Add a README explaining local preview, ICP local deploy, mainnet deploy, custom domain steps, and update workflow. - Do not deploy automatically. - Do not add unnecessary dependencies. - Inspect the folder first, explain your plan, then make the smallest safe implementation. - After editing, summarize all files changed and the exact commands I should run next.
For an existing project, add this line:
This project already has files. Preserve the existing design and do not rewrite the whole app unless necessary.
Best practices before sharing your site
A working deployment is not the same as a trustworthy website. Before you send traffic to it, make the site clear, complete, and safe.
- Add a clear headline and a simple call to action.
- Add About, Contact, Privacy Policy, and Terms pages if you will run ads or collect leads.
- Use a custom domain if you want credibility beyond the canister URL.
- Compress images before upload so your site stays fast.
- Test on mobile, desktop, and private/incognito browser windows.
- Keep a private backup of your project and identity material.
If you are running paid ads
Make the landing page focused and trustworthy. Avoid unsupported claims, sensitive personal targeting, misleading guarantees, and broken links. If you use remarketing or analytics, make sure your privacy policy explains how data and cookies may be used.
Simple launch checklist
- Ubuntu/terminal works
- Node.js current enough
- Claude Code installed
- ICP CLI installed
- Project builds
- Local deploy works
- Mainnet deploy works
- Canister URL works
- Custom domain file deployed
- DNS records added
- Domain registered
- HTTPS works
- Pages and links tested
Sources and current notes
This guide was generalized from a real website launch workflow — the same one behind the site you are reading right now — and checked against official documentation. Commands and pricing can change, so verify the latest docs if something fails.
| Topic | Where to verify |
|---|---|
| Microsoft WSL installation | learn.microsoft.com/windows/wsl/install |
| Claude Code npm installation | code.claude.com/docs/en/setup |
| Claude plan comparison and Max plan pricing | support.claude.com |
| ICP CLI quickstart and installation | docs.internetcomputer.org/getting-started/quickstart and github.com/dfinity/icp-cli |
| ICP asset canister configuration | docs.internetcomputer.org/guides/frontends/asset-canister/ |
| ICP custom domains | docs.internetcomputer.org/guides/frontends/custom-domains/ |
In my own launch, the site was deployed to an ICP asset canister, then the custom domain was connected by adding DNS records, deploying the .well-known/ic-domains file, validating the domain, registering it, and waiting for HTTPS certificate provisioning. Use your own domain and canister ID — and enjoy having a website that runs entirely on the Internet Computer.