Jan 26, 2024 - 12 min read
(ICP represents a layer one public blockchain network that has captured the attention of innovators worldwide. Its defining feature is the novel consensus algorithm known as “Threshold Relay,” which combines the computing power of numerous independent data centers around the globe. This fusion creates a vast decentralized world computer, known as the Internet Computer.)
The Internet Computer (ICP) is a layer one public blockchain that offers numerous benefits including smart contracts that can serve web/HTTP at web speed. This allows developers to build decentralized applications (dApps) completely on-chain without the need for traditional cloud hosting services such as AWS and GCP.
Additionally, the reverse gas model implemented on ICP ensures that dApp developers cover the computation costs, liberating users from the obligation of owning or managing tokens. Through the use of chainkey cryptography smart contracts on ICP can effortlessly control Bitcoin balances and can interact with contracts on Ethereum and vice versa, without the need for wrapping or bridging.
Developed by the DFINITY Foundation, ICP uses consensus algorithm known as Threshold Relay which "harmoniously combines the computing power of numerous independent data centers around the globe using ICP. This fusion creates a vast decentralized world computer..." known today as the Internet Computer.
Hosting your applications on the Internet Computer offers several benefits when compared to competing blockchains as well as traditional cloud hosting services.
First, ICP offers infinite scaling capabilities, meaning the Internet Computer can host an unlimited number of canisters (smart contracts), store an unlimited amount of memory, and process an unlimited amount of transactions per second. In simple words, Internet Computer is designed to host even large scale social media platforms in a fully decentralized way.
A browser is all you need to interact with smart contracts on the Internet Computer. Canisters (i.e. ICP smart contracts) have the ability to serve web content directly to end users, meaning individuals can interact with blockchain services without the requirement of holding tokens. The reverse gas model implemented on ICP ensures that dApp developers cover the computation costs, liberating users from the obligation of owning or managing tokens.
On the other hand, this also means that developers need to learn how to purchase and secure ICP tokens to keep their dApps funded for hosting. There is a small learning curve and some hard to calculate forecasts developers need to make re: how much ICP is needed to fund their apps (especially once the app starts scaling). In general, ICP apps need Cycles in order to run so developers need to make a USD -> ICP -> Cycles conversion in order to properly run their apps. For more info see the Tokens page.
Another noteworthy advantage of ICP lies in its cost efficiency. Storing 1GB of data on ICP costs approximately $5 per year, a stark contrast to Ethereum’s staggering $350,000,000 and Solana’s approximately $800,000 for the same storage capacity. This also counts as a benefit compared to traditional cloud services like AWS and GCP which have higher data storage costs (though not by as much).
While many developers reading this have heard the terms four- or five-9s, corresponding to 99.99% or 99.999% annual server up-time for a given service which is hard to achieve, the Internet Computer offers a fully autonomous and unstoppable cloud that abstracts much of the required infrastructure and corresponding human expertise needed.
By utilizing a decentralized blockchain protocol the IC also enjoys other benefits especially when compared to traditional cloud hosting services. For developers looking for serverless architecture the IC offers Serverless Computing, enabling quick and agile development cycles that can greatly reduce infrastructure maintenance and operational costs.
The IC enjoys additional security benefits such as tamper-proof and unstoppable software systems and services that do not require safeguarding through firewalls, SIEM logging, or other conventional cybersecurity frameworks.
Additionally, chain-key cryptography and secure multiparty computation enable enterprise-grade custody of digital assets on the Internet Computer. Security built into the protocol reduces the complexity of digital asset custody associated with traditional solutions.
I've migrated two of my apps to the Internet Computer so far and to my surprise generally found it a straight forward and simple process, which I believe is another advantage of the IC and helps add to its increasing popularity with developers.
As the 2nd requirement above states the IC SDK is natively supported on Linux or macOS 12 Monterey or later. As of this writing there is no native support for
dfx
on Windows; however by installing the Windows Subsystem for Linux (WSL 2), it's possible to run dfx on a Windows system (more info).
The DFINITY command-line execution environment (dfx
) is the primary tool for creating, deploying, and managing the dApps you develop for the IC. Let's start by downloading the IC SDK locally:
sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"
To verify the SDK is ready to use run the following command:
dfx --version
For general SDK usage information and commands run:
dfx --help
For simplicity, we will first build and deploy a "Hello World" project locally. Once that's running it's a straight forward process for replacing the app's source with the source code of an app you want to migrate and host on the IC.
With the dfx
SDK downloaded the first thing we want to do is start a local replica instance (The --background flag will start the replica in the background and return your terminal prompt for more commands):
dfx start --background
You should see output similar to the following:
Running dfx start for version 0.15.3
Using the default definition for the 'local' shared network because /Users/user/.config/dfx/networks.json does not exist.
Initialized replica.
Dashboard: http://localhost:55762/_/dashboard
Next we use the dfx new
command to create a basic Hello World project:
dfx new hello_world
This creates a "Hello, world!" project that contains a basic frontend UI (for a full, detailed guide on this project see here). The project structure of this app should look similar to the following:
hello_world/
├── README.md # Default project documentation
├── dfx.json # Project configuration file
├── node_modules # Libraries for frontend development
├── package-lock.json
├── package.json
├── src # Source files directory
│ ├── hello_world_backend
│ │ └── main.mo
│ ├── hello_world_frontend
│ ├── assets
│ │ ├── logo.png
│ │ ├── main.css
│ │ └── sample-asset.txt
│ └── src
│ ├── index.html
│ └── index.js
└── webpack.config.js
Now we can build and deploy the project locally using the dfx deploy
command:
cd hello_world
dfx deploy
Upon successful execution, the project URL(s) will be returned in the output (e.g.):
...
Committing batch.
Committing batch with 18 operations.
Deployed canisters.
URLs:
Frontend canister via browser
hello_world_frontend: http://127.0.0.1:4943/?canisterId=a4tbr-q4aaa-aaaaa-qaafq-cai
Backend canister via Candid interface:
hello_world_backend: http://127.0.0.1:4943/?canisterId=ajuq4-ruaaa-aaaaa-qaaga-cai&id=a3shf-5eaaa-aaaaa-qaafa-cai
You can now view the running app by accessing the frontend URL in a browser, for example:
http://127.0.0.1:4943/?canisterId=a4tbr-q4aaa-aaaaa-qaafq-cai
Assuming no errors you now have an IC app running against your local canister execution environment.
By default, all
dfx
commands run against the local environment. To run any command in production add the --network ic flag (or --ic for shorthand). For example, when ready to deploy to production we would dodfx deploy --network ic
.
With the template project successfully running, hopefully you have a better understanding of how to run and deploy apps on the Internet Computer. But what if you want to test your own app(s) on the IC instead of the Hello World template? Well the good news is that's there's two basic steps:
dfx.json
configuration file to the root folder of your application.Start by copying the dfx.json
file that we created above, which should look similar to the following:
{
"canisters": {
"hello_world_backend": {
"main": "src/hello_world_backend/main.mo",
"type": "motoko"
},
"hello_world_frontend": {
"dependencies": [
"hello_world_backend"
],
"frontend": {
"entrypoint": "src/hello_world_frontend/src/index.html"
},
"source": [
"src/hello_world_frontend/assets",
"dist/hello_world_frontend/"
],
"type": "assets"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 1
}
Next update the file to point to the source and entrypoint locations of your frontend and backend applications. Note that the canister names, hello_world_backend and hello_world_frontend in the above example, are user-defined.
If your app only contains a frontend then you simply need to specify that part of the configuration, for example:
{
"canisters": {
"my_website_fe": {
"frontend": {
"entrypoint": "build/index.html"
},
"source": ["build"],
"type": "assets"
}
}
}
The above example assumes frontend static assets are contained in a folder named
/build
located at the root of the project. For example, when using Create React App (CRA) by default optimized production builds are created under the /build folder.
With all proper paths and references updated in your dfx.json file you can build and deploy your project locally using:
dfx deploy
Once your app is successfully running in the local environment and you're ready to deploy to production you'll need to acquire and add ICP cycles to your canister(s).
When you are ready to deploy your app to production - i.e. the Internet Computer mainnet - you will first need to add cycles to power your app's storage and compute costs.
If you already have enough cycles available in your production wallet you can issue the following command to deploy you app to production:
dfx deploy --network ic
or shorthand:
dfx deploy --ic
If you do not have enough cycles to power your app you will need to add more to your production wallet by obtaining new ICP tokens and converting into cycles as mentioned above.
If you want to make a canister accessible through a custom domain DFINITY actually has a decent guide that walks you through the process. However I still encountered numerous problems and issues that I wanted to highlight here.
There are two approaches for configuring a cansister to work with a custom domain:
Here we will follow the first approach of Registering the Domain with the Boundary Nodes. If you want to host the domain on your own infrastucture see here.
The general steps for registering your custom domain are:
.well-known/ic-domains
and .ic-assets.json
config files to your project.Let's say you want to register a custom domain foo.bar.com
, first add the following DNS records through your domain provider:
Record Type | Host | Value |
---|---|---|
CNAME | foo.bar.com | icp1.io |
TXT | _canister-id.foo.bar.com | _acme-challenge.foo.bar.com |
CNAME | hwvjt-wqaaa-aaaam-qadra-cai | _acme-challenge.foo.bar.com.icp2.io |
You may need to wait minutes or even hours for the DNS changes to propogate out. Next you'll need to add two new configuration files to your project.
.well-known/ic-domains
and .ic-assets.json
files The next step seems obvious but can be tricky based on which framework you are using for your project and how it creates production builds. First you need to create two new files, one in a hidden folder and a second hidden file at the root of your canister source folder:
mkdir .well-known
Next using your editor create a .well-known/ic-domains
file and add the following contents to the file:
foo.bar.com
Now create a .ic-assets.json
file which contains the following:
[
{
"match": ".well-known",
"ignore": false
}
]
One potentially tricky issue here is that the DFINITY documentation states these two files should be added to your "canister source root". This might be clear for backend projects, however for frontend projects using React or Next.js it can be misleading.
As was covered earlier in this article, when we initially configured our project for IC hosting we added a dfx.json
file to the project root that specifies entrypoints and source locations for canister(s). A simpler version of this file that works for frontend projects is:
{
"canisters": {
"my_website_fe": {
"frontend": {
"entrypoint": "build/index.html"
},
"source": ["build"],
"type": "assets"
}
}
}
With regards to the .well-known/ic-domains
and .ic-assets.json
files these files would need to be included in the /build
folder in the example above.
For React or Next.js developers, this means you'll need to add the .well-known/ic-domains
and .ic-assets.json
files to the /public
folder at your project root and rely on your framework's build process to properly include them in the optimized build output.
With your DNS records configured and above configuration files properly added to your project you'll need to re-deploy your canister to the IC. To deploy to production IC do:
dfx deploy --ic
Assuming successfull deploy the last step is to register the custom domain.
To start the registration process for domain foo.bar.com
issue the following command:
curl -sLv -X POST \
-H 'Content-Type: application/json' \
https://icp0.io/registrations \
--data @- <<EOF
{
"name": "foo.bar.com"
}
EOF
If the call was successfull the response will look like:
{"id":"REQUEST_ID"}
For help dealing with potential errors see here.
You may need to wait a few minutes for the certificates to become available across the boundary nodes but once they do you should be able to access your canister application by navigating to your custom domain!
Thanks for reading!