12 Commits

Author SHA1 Message Date
github-actions[bot]
2da76a8d7c Optimised images with calibre/image-actions 2023-10-24 22:46:29 +00:00
Kyle
433d482cb8 Update ENS subdomain wording 2023-10-24 20:01:01 +01:00
Kyle
064e359130 Apply suggestions from dame's review
Co-authored-by: dame.eth <110121581+damedoteth@users.noreply.github.com>
2023-10-24 19:56:11 +01:00
Kyle
028c7b9f32 Merge branch 'main' into introducing-dappling 2023-10-16 11:02:46 +01:00
Kyle
98664e0b5b Merge branch 'main' into introducing-dappling 2023-10-04 17:12:00 +01:00
Kyle
143e4d0a8a remove image 2023-10-04 16:01:30 +01:00
Kyle
6aa9dc60cb draft 2 2023-10-04 13:48:44 +01:00
Kyle
b581dd5d2a less walkthrough more hype 2023-10-03 17:23:55 +01:00
Kyle
a6fa6b719c Merge branch 'main' into introducing-dappling 2023-09-22 11:50:35 +01:00
Kyle
62f0eea411 Update 2023-09-introducing-dappling.md 2023-09-22 11:49:22 +01:00
Kyle
7dd61aa692 Merge branch 'main' into introducing-dappling 2023-09-20 14:43:46 +01:00
Kyle
de403cf142 introducing dappling 2023-09-20 14:40:14 +01:00
10 changed files with 110 additions and 205 deletions

BIN
curl.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 MiB

16
package-lock.json generated
View File

@@ -6364,9 +6364,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001549",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
"integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
"version": "1.0.30001470",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001470.tgz",
"integrity": "sha512-065uNwY6QtHCBOExzbV6m236DDhYCCtPmQUCoQtwkVqzud8v5QPidoMr6CoMkC2nfp6nksjttqWQRRh75LqUmA==",
"dev": true,
"funding": [
{
@@ -6376,10 +6376,6 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
},
@@ -30071,9 +30067,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001549",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
"integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
"version": "1.0.30001470",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001470.tgz",
"integrity": "sha512-065uNwY6QtHCBOExzbV6m236DDhYCCtPmQUCoQtwkVqzud8v5QPidoMr6CoMkC2nfp6nksjttqWQRRh75LqUmA==",
"dev": true
},
"caseless": {

View File

@@ -10,6 +10,16 @@ function shouldBeHidden(frontmatter) {
shouldHide = shouldHide || frontmatter.sitemap.exclude
}
// scheduled posts
// see auto-publishing of scheduled posts here: https://github.com/ipfs/ipfs-blog/issues/147
if (
!shouldHide &&
frontmatter.permalink && // permalink is unique to posts
frontmatter.date
) {
shouldHide = shouldHide || isDateInFuture(frontmatter.date)
}
// scheduled links (path is unique to links)
if (!shouldHide && frontmatter.path && frontmatter.publish_date) {
shouldHide = shouldHide || isDateInFuture(frontmatter.publish_date)

View File

@@ -0,0 +1,94 @@
---
title: dAppling - a New Way to Deploy IPFS Sites in Minutes
description: Introducing a seamless way to launch your code on IPFS, featuring straightforward setup, automatic deployments, and more.
author: 🙏 namaskar
date: 2023-10-10
header_image: '/2023-10-introducing-dappling-header.png'
tags:
- 'web3'
- 'tooling'
- 'ipns'
---
Welcome! I would love to share what I'm building at dAppling, a platform that aims to simplify the build and deployment process for sites hosted on IPFS. I'll share a bit about us, a bit about the platform, and a bit about what you will get. By the end, it should be clear if dAppling is a tool you'll want to add to your developer toolbox.
## A Bit about Us
I'm Kyle. My co-founder Russell and I have been professional developers (whatever that means) for the last 7 years. We've worked at startups, big tech, and things in between. The last 2 of those years has been in the web3 space where we started with the creation of a DeFi protocol. We're excited to now be building tools for developers working on the next generation of the web.
## A Bit about dAppling
The first of those tools is dAppling. The word is a portmanteau of "dApp", a term short for decentralized application, and "sapling," because nature is wonderful 🌱. However, we support all kinds of web projects, not just [dApps](https://app.gogopool.com.dappling.eth.limo/): [landing pages](https://arbor-landing.dappling.eth.limo/), [blogs](https://blog.dappling.network), or even a simple page of content arguing against the [usage of acronyms](https://nomoreacronyms-xczmz4.dappling.org).
Basically, we fetch your code, build it into html/css/js files, and host those files on IPFS. What makes us special are the features we provide to make your experience easier. Even if you have an existing site, you can use dAppling to create a resilient "alternative frontend" that is hosted on IPFS.
## A Bit about What You Get
When you add a project to dAppling, you will tell us where the code is and what commands to use. After it's built you will get:
- automatic updates when your code on **GitHub** changes
- hosting on the **InterPlanetary File System** (IPFS)
- a working **dappling.network** subdomain
- a working **dappling.eth** ENS subdomain
- an automatically updating **IPNS** key
## Our Focuses
We have two major focuses at dAppling: **simplicity** and **access**.
We want to make it as easy as possible to get your code hosted. After that, we want it to be accessible and fast. What we want to avoid is a first-time experience where you only see an error screen or have your users waiting forever to load your site.
### Simplicity
We simplify the setup process by automatically detecting your app's configuration. If something does go wrong, we have easy to use debugging tools.
#### Simple Setup
Since we have access to your code, we look at a few things like what package manager you use, what sort of framework the project is built with, and certain configuration files. We use this information to prefill the configuration form, so you don't have to.
Additionally, we have easy to use dropdowns for what GitHub branch to use as well as the code location for cases like a monorepo.
![Autodetect Configuration](../assets/2023-10-introducing-dappling-autodetect.png)
#### Simple Debugging
Try as we might, projects fail to build. Quite a bit! From a linting error to a missing dependency, seeing the error screen seems inevitable. We want to make it as easy as possible to understand what went wrong and how to fix it. We parse the logs and show you the error in, what we think, is a pretty readable format.
![Readable Error Logs](../assets/2023-10-introducing-dappling-error.png)
If reading logs isn't your thing, we have a button that sends your logs to be parsed by AI and returns a summary of the error. And while it's not perfect, the output has been helpful more often than not.
### Accessibility
Websites need to be accessed, even if the reader is only you! We think the more points of access the better, and each should be available and fast.
#### Speed of Access
The foundation of our storage starts with [Filebase](https://filebase.com/) whose geo-redundant storage locations keep your files available. On top of that, the CDN quickly fetches and caches those files.
#### Points of Access
There are a couple of ways to access your site. When the code is built and uploaded to IPFS, you will receive what is called a [Content Identifier (CID)](https://docs.ipfs.tech/concepts/content-addressing/). It's basically the hash of all your files.
You will receive a new CID every time your site is re-built because the resulting files have changed. Luckily, we use the [InterPlanetary Name System (IPNS)](https://docs.ipfs.tech/concepts/ipns/) to create a key that will always point to the most recent CID.
The most straightforward way to fetch your content would be directly from an [IPFS node](https://docs.ipfs.tech/concepts/nodes/). Since not everyone is running an IPFS node (yet), you can instead use an [IPFS gateway](https://docs.ipfs.tech/concepts/ipfs-gateway/) in which a third party fetches the content from their node and serves it over HTTPS.
Since we store the auto-updating key on a custom `*.dappling.eth` ENS subname, you can also fetch the content through a service like [eth.limo](https://eth.limo). This service first reads the IPNS key that we set, resolves it to a CID, and then serves the content like a gateway.
Even simpler would be using the existing DNS system either using our custom `*.dappling.network` subdomain that we created for you. We also allow adding your custom domain like `ipfs.crypto-protocol.app`.
## Future
We plan to be constantly upgrading the platform as new decentralization techniques appear. As a user, you will notice more points of access, quicker speeds, and features to make usage easier. We hope to increase decentralization through...
- SSR: Serverless applications are popular on platforms like Next.js and we will be using decentralized compute to increase the types of applications we support.
- Collaboration: The more participants in a project the better the decentralizaton becomes. We are working on tools to allow multiple people configure the project.
## Get Involved
As we continue to improve, we're always looking for user feedback to guide us. Our focus remains on providing a platform that is not just decentralized but also highly performant and user-friendly.
If you run into **any** problems, want to connect or just say hi, our DMs are open on [𝕏](https://x.com/0xBookland). We would love to hear your feedback and help you get all of your projects deployed as we transition to the infrastructure of the future.
🙏

View File

@@ -1,195 +0,0 @@
---
title: IPFS URL support in CURL
description: 'CURL 8.4.0 shipped with built-in support for ipfs:// and ipns:// addresses.'
author: Mark Gaiser
date: 2023-10-16
permalink: '/ipfs-uri-support-in-curl/'
header_image: '/curl.png'
tags:
- 'community'
- 'URI'
- 'URL'
- 'HTTP'
- 'curl'
---
# `ipfs://` URL support in `curl`
[CURL 8.4.0](https://github.com/curl/curl/releases/tag/curl-8_4_0) shipped with built-in support for `ipfs://` and `ipns://` addresses.
This enables `curl` to seamlessly integrate with the user's preferred [IPFS gateway](https://docs.ipfs.tech/reference/http/gateway/) through the `IPFS_GATEWAY` environment variable or a `gateway` file. Best of all, these capabilities are available for immediate use today:
```bash
$ export IPFS_GATEWAY="http://127.0.0.1:8080" # local (trusted) gateway provided by ipfs daemon like Kubo
$ curl ipfs://bafkreih3wifdszgljcae7eu2qtpbgaedfkcvgnh4liq7rturr2crqlsuey
hello from IPFS
```
In this blog post, we will:
- explore the journey of implementing IPFS URI support in CURL,
- delve into the mechanics of [how CURL locates an IPFS gateway](#how-does-curl-find-an-ipfs-gateway),
- learn how to be immune to [malicious gateways](#malicious-gateways-and-data-integrity),
- and finally, provide [practical CURL examples](#curl-examples) for leveraging IPFS URLs for either deserialized or verifiable responses.
## A brief history
Supporting IPFS in CURL has been attempted [before](https://github.com/curl/curl/pull/8468) as a CURL library feature. Some discussions lead to a belief that this should be implemented in the CURL tool itself, not its library. A renewed [implementation attempt](https://github.com/curl/curl/pull/8805) took the tool-side approach which ultimately was accepted and is available right now in CURL 8.4.0!
The support of IPFS in CURL is effectively consisting of two implementation details.
1. CURL tries to find a locally installed or [configured gateway](#how-does-curl-find-an-ipfs-gateway).
2. It then rewrites an `ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi` to a gateway URL. This is how curl handles it internally, you see nothing of this URL rewriting.
If you have IPFS installed locally then running `curl ipfs://` will Just Work™. If not, CURL will return an error with details about how to set up the gateway preference. This ensures the user agency is respected, no third-party gateway is used as implicit default.
## Why `ipfs://` URL support is so important?
Why isn't `https://ipfs.io/ipfs/bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi` equally acceptable?
Or why isn't a local URL `http://localhost:8080/ipfs/bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi` fine?
Both addresses are tied to a specific _location_.
IPFS is a modular suite of protocols purpose built for the organization and transfer of [content-addressed](https://docs.ipfs.tech/concepts/content-addressing) data. It shouldn't matter where the content is. Content Identifier ([CID](https://docs.ipfs.tech/concepts/glossary/#cid)) is all that is required. The "where" part is implementation detail an IPFS system takes care of. Hardcoding a location in addition to a CID (like a specific HTTP gateway) limits end users to IPFS resources available through that one specific, centralized point of entry.
If we pull the URL apart we see:
![](../assets/ipfs_uri_where_protocol_what.png)
Users of the IPFS system should not care about the _where_ part, nor be coerced to use a specific, hard-coded entry point into the system.
Public gateways like `ipfs.io` are always owned by some entity and could get censored or shut down at any time. Many gateways will not allow playback of deserialized videos or only respond to CIDs from allowlists to reduce costs. Other gateways will block specific CIDs from resolving in specific jurisdictions for legal reasons. Community-run public gateways will have limits and throttle usage.
These are not limitations of IPFS but purely a limitation a specific gateway has set through custom configuration. IPFS user should always have ability to avoid such limitations if they choose to self-host and [run their own IPFS node with a local gateway](https://docs.ipfs.tech/install/).
<!-- TODO: remove? feels like duplicate of we already say in this and "malicious" sections, but mentioning ffmpeg blogpost feels like something we should keep somewhere
This is why running a local node (and therefore a local gateway, it's part of a node) is so important. Even though you still effectively use `http://localhost:8080` as gateway, it's hosted by you locally backed by the many peers your node is connected with. Your experience in using IPFS is going to be best and fastest with a local node. Even when your local gateway isn't working it's easy for you to restart your node and get that gateway back and running. You can't do that on public gateways that you don't control.
One of the many reasons why we're putting in the effort to make applications recognize IPFS URIs (like [ffmpeg](https://blog.ipfs.tech/2022-08-01-ipfs-and-ffmpeg/)) `ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi` is to let the application in the background find that gateway you're running and giving you the freedom of being truly distributed! This also allows url's to be shared as IPFS url's (like `ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi`) without any trace of a (central) gateway and bring us one step closer to a distributed world where it doesn't matter anymore where that data is located.
-->
## How does CURL find an IPFS Gateway?
Any IPFS implementation that has support for [IPIP-280](https://github.com/ipfs/specs/pull/280) exposes an IPFS gateway that CURL (and [ffmpeg](https://blog.ipfs.tech/2022-08-01-ipfs-and-ffmpeg/)) can use. At the moment of writing that's just [Kubo](https://github.com/ipfs/kubo/releases).
CURL 8.4.0 and greater looks for a gateway in the following order:
1. `IPFS_GATEWAY`, if set it's used.
2. The `--ipfs-gateway` CLI argument.
3. The `~/.ipfs/gateway` file, where it reads the first line.
If a gateway hint is found at any of those places, and if that is a valid HTTP URL, then CURL will use it. If not, then you'll be getting an error message pointing to the [CURL documentation related to IPFS](https://curl.se/docs/ipfs.html) to help you further.
One can specify any IPFS gateway that is in compliance with [Gateway Specifications](https://specs.ipfs.tech/http-gateways/). It is highly recommended to use a local gateway, as it provides the best security guarantees.
## Malicious gateways and data integrity?
Requesting deserialized responses and delegating hash verification to a third-party gateway comes with risks. It is possible that a public gateway is malicious. Or, that a well-known and respected gateway gets hacked and changed to return payload that does not match requested CID. How can one protect themselves against that?
If deserialized responses are necessary, one should run their own gateway in a local, controlled environment. Every block of data retrieved though self-hosted IPFS gateway is verified to match the hash from CID. For the maximum flexibility and security, find an implementation that provides the gateway endpoint (i.e. [Kubo](https://docs.ipfs.tech/install/command-line/)) and run it yourself!
When using a third-party gateway that one can't fully trust, the only secure option is to [request verifiable response types](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval) such as [application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw) (a single block) or [application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car) (multiple blocks in CAR archive). Both allow to locally verify if the data returned by gateway match the requested CID, removing the surface for [Man-in-the-middle attacks](https://en.wikipedia.org/wiki/Man-in-the-middle_attack).
## CURL Examples
### Deserialized responses
::: callout
By default, a trusted local gateway acts as a bridge between traditional HTTP clients and IPFS.
It performs necessary hash verification, UnixFS _deserialization_ and return reassembled files to the client, as if they were stored in a traditional HTTP server. This means all validation happens on the gateway, and clients trust that the gateway is correctly validating content-addressed data before returning it to them.
:::
#### Downloading a file from IPFS with CURL
```bash
$ curl ipfs://bafkreih3wifdszgljcae7eu2qtpbgaedfkcvgnh4liq7rturr2crqlsuey -o out.txt
```
If curl responds with `curl: IPFS automatic gateway detection failure`, make sure `IPFS_GATEWAY` is set (see examples below).
#### Explicitly specifying a gateway
To use local gateway on custom port 48080:
```bash
$ export IPFS_GATEWAY=http://127.0.0.1:48080
$ curl ipfs://bafkreih3wifdszgljcae7eu2qtpbgaedfkcvgnh4liq7rturr2crqlsuey
hello from IPFS
```
When setting environment variable is not feasible, one can use `--ipfs-gateway` instead:
```bash
$ curl --ipfs-gateway http://127.0.0.1:48080 ipfs://bafkreih3wifdszgljcae7eu2qtpbgaedfkcvgnh4liq7rturr2crqlsuey
hello from IPFS
```
#### Following subdomain redirects
::: callout
By default, the URL resolution in `curl` does not follow HTTP redirects and assumes the endpoint implements deserializing [path gateway](https://specs.ipfs.tech/http-gateways/path-gateway/), or at the very least, the [trustless gateway](https://specs.ipfs.tech/http-gateways/trustless-gateway/).
When pointing `curl` at a [subdomain gateway](https://specs.ipfs.tech/http-gateways/subdomain-gateway) (like `https://dweb.link` or the `http://localhost:8080` provided by a [local Kubo node](https://docs.ipfs.tech/how-to/command-line-quick-start/)) one has to pass `-L` in the curl command to follow the redirect.
:::
```bash
$ IPFS_GATEWAY=https://localhost:8080 curl -s -L ipfs://bafkreih3wifdszgljcae7eu2qtpbgaedfkcvgnh4liq7rturr2crqlsuey
hello from IPFS
```
#### Piping and streaming responses
Deserialized response returned by CURL can be piped directly to a video player:
```
$ curl ipfs://bafybeigagd5nmnn2iys2f3doro7ydrevyr2mzarwidgadawmamiteydbzi | ffplay -
```
### Verifiable responses
::: callout
By explicitly requesting [application/vnd.ipld.raw](https://www.iana.org/assignments/media-types/application/vnd.ipld.raw) (a block) or [application/vnd.ipld.car](https://www.iana.org/assignments/media-types/application/vnd.ipld.car) (a stream of blocks) responses, by means defined in [Trustless Gateway Specification](https://specs.ipfs.tech/http-gateways/trustless-gateway/), the user is able to fetch raw content-addressed data and [perform hash verification themselves](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval).
:::
#### Fetching and verifying a directory from an untrusted gateway
Requesting [trustless and verifiable](https://docs.ipfs.tech/reference/http/gateway/#trustless-verifiable-retrieval) CAR response via `Accept` HTTP header:
```bash
$ export IPFS_GATEWAY="https://ipfs.io" # using untrusted public gateway
$ curl -H "Accept: application/vnd.ipld.car" "ipfs://bafybeiakou6e7hnx4ms2yangplzl6viapsoyo6phlee6bwrg4j2xt37m3q" > dag.car
```
Then, CAR can be moved around and imported into some other IPFS node:
```bash
$ ipfs dag import dag.car
```
or verified and unpacked locally, without having to run a full IPFS node, with tools like [go-car](https://github.com/ipld/go-car/tree/master/cmd/car#readme) or [ipfs-car](https://www.npmjs.com/package/ipfs-car):
```
$ npm i -g ipfs-car
$ ipfs-car unpack dag.car --output dag.out
$ ls dag.out
1007 - Sustainable - alt.txt
1007 - Sustainable - transcript.txt
1007 - Sustainable.png
```
## What's next?
More places supporting IPFS addresses. Everyone can integrate `ipfs://` and `ipns://` URL support into their application. See specifications proposed in [IPIP-280](https://github.com/ipfs/specs/pull/280) for technical details. We are [tracking potential project](https://github.com/ipfs/integrations/issues) where an integration makes sense! If you feel up to the challenge, don't hesitate to drop a comment in one of the [potential projects](https://github.com/ipfs/integrations/issues) for IPFS URL integration or find us on:
* [Matrix](https://matrix.to/#/#ipfs-space:ipfs.io), [Discord](https://discord.com/invite/ipfs) or [Slack](https://filecoin.io/slack)
* [Discussion Forum](https://discuss.ipfs.tech/)
Or one of the other many places where the [IPFS community](https://docs.ipfs.tech/community/) is active.

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 MiB

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 12 KiB