<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: agentofuser</title>
    <description>The latest articles on Forem by agentofuser (@agentofuser).</description>
    <link>https://forem.com/agentofuser</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F117544%2Fc8519aaa-f36a-45c0-be2e-923f79478fa3.png</url>
      <title>Forem: agentofuser</title>
      <link>https://forem.com/agentofuser</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/agentofuser"/>
    <language>en</language>
    <item>
      <title>Headless Ghost and Fission</title>
      <dc:creator>agentofuser</dc:creator>
      <pubDate>Wed, 24 Feb 2021 16:08:56 +0000</pubDate>
      <link>https://forem.com/fission/headless-ghost-and-fission-3b57</link>
      <guid>https://forem.com/fission/headless-ghost-and-fission-3b57</guid>
      <description>&lt;p&gt;We're exploring a number of "Headless" combinations at Fission. The first one is with the Ghost Content Management System (CMS). We use Ghost to run our blog and want to start using it to integrate with and power our home page, so it's a great place for us to start.&lt;/p&gt;

&lt;p&gt;The basic pattern of "Headless" is that your authors and editors login to a server based system with all the authoring and editing tools they are used to, but then the "head" – the usual template system and user facing website – isn't used. Instead, a modern front end framework is custom designed and built to take the published content of the CMS and host it. This fits great with the Fission app publishing platform.&lt;/p&gt;

&lt;p&gt;After we've got the basics of a headless publishing workflow setup with Fission, we'll move on to using our Webnative framework to add personalization at the edge, but that will come in later posts.&lt;/p&gt;

&lt;p&gt;Aside from Ghost, we're also looking at &lt;a href="https://talk.fission.codes/t/headless-wordpress/1448"&gt;Headless WordPress&lt;/a&gt; and &lt;a href="https://talk.fission.codes/t/headless-drupal/1513"&gt;Headless Drupal&lt;/a&gt;. Let us know in &lt;a href="https://talk.fission.codes/"&gt;the forum&lt;/a&gt; if you've got other Headless projects that you'd like to combine with Fission!&lt;/p&gt;

&lt;h1&gt;
  
  
  Build a Next.js Blog powered by Headless Ghost and Fission
&lt;/h1&gt;

&lt;p&gt;You want to have a modern static website/app built with React, deployed to a CDN (even a &lt;a href="https://ipfs.io/"&gt;distributed&lt;/a&gt; one), and loading super fast for visitors and search engines.&lt;/p&gt;

&lt;p&gt;You want to avoid the headaches and costs of managing and securing servers for traditional content management systems (CMSs) like Ghost and WordPress.&lt;/p&gt;

&lt;p&gt;That's what static site generators (like Next.js, Gatsby, and &lt;a href="https://staticgen.com/"&gt;others&lt;/a&gt;) are for, right?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But,&lt;/em&gt; you &lt;em&gt;don't&lt;/em&gt; want to have to &lt;strong&gt;retrain&lt;/strong&gt; every writer and content creator on your team to use &lt;em&gt;Markdown&lt;/em&gt; and &lt;em&gt;Git&lt;/em&gt;. Ghost and WordPress are familiar, pretty, and usable. They have been iterated over years to be approachable by almost anyone.&lt;/p&gt;

&lt;p&gt;What do you do? That's right you cut the CMS' head off 🔪&lt;/p&gt;

&lt;p&gt;More politely, you &lt;em&gt;decouple&lt;/em&gt; the interface used for &lt;em&gt;authoring&lt;/em&gt; content from the systems used for &lt;em&gt;rendering&lt;/em&gt; and &lt;em&gt;distributing&lt;/em&gt; it.&lt;/p&gt;

&lt;p&gt;With CMS and website decoupled, you can protect the CMS inside an intranet without exposing it to outside danger, or even use it as a desktop word processor running only on your machine, as I'll show you in this tutorial.&lt;/p&gt;

&lt;p&gt;To make things easier we've made a template Next.js website that connects to Ghost and pulls content from it. Follow along and try it out. Feedback welcome :)&lt;/p&gt;




&lt;p&gt;This starter template is based on the official &lt;a href="https://github.com/vercel/next.js/tree/canary/examples/blog-starter-typescript"&gt;blog-starter-typescript&lt;/a&gt; from &lt;a href="https://nextjs.org"&gt;Next.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We changed it only enough to make it possible to fetch and publish blog posts from the Ghost CMS, while keeping the ability to write Markdown files in the git repo. It's a purely additive change.&lt;/p&gt;

&lt;p&gt;There's also a GitHub Action to build and publish the static website to Fission. It works automatically on pushes to the git repo, and can be triggered manually after updating the content on Ghost. (The default Ghost webhook isn't customizable to trigger a GitHub Action, but that can be added as a plugin.)&lt;/p&gt;

&lt;p&gt;The Markdown blog posts are stored in &lt;code&gt;/_posts&lt;/code&gt; as files with frontmatter support. Adding a new Markdown file in there will create a new blog post.&lt;/p&gt;

&lt;p&gt;The Ghost blog posts are fetched using Ghost's Content API library.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨  Getting Started
&lt;/h2&gt;

&lt;p&gt;Let's start by making this starter yours:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Use this template&lt;/strong&gt; at the &lt;a href="https://github.com/fission-suite/nextjs-blog-starter-typescript-ghost"&gt;starter page on GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That will make a copy of the starter into a new repo under your account with a fresh git history. You can pick a different name for it too; in that case replace &lt;code&gt;nextjs-blog-starter-typescript-ghost&lt;/code&gt; with your chosen name below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone the repo (replace with your own URL):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  git clone git@github.com:fission-suite/nextjs-blog-starter-typescript-ghost.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;cd into the repo:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cd nextjs-blog-starter-typescript-ghost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install dependencies
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  yarn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All command-line instructions and directory paths from now on assume the current directory is the root of the cloned repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  👻  Setting Up Ghost
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Public or Local Ghost?
&lt;/h4&gt;

&lt;p&gt;Running a local Ghost instance is good for testing. But also, if you have no need for a Ghost instance running all the time out on the internet (for example, if you are the only author) you can do this for your production website, using Ghost locally for its nice interface if you prefer that to editing Markdown files. No servers to secure, no bills to pay.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting Up Local Ghost
&lt;/h4&gt;

&lt;p&gt;If you have a Ghost instance running already somewhere, move on to the next step. If you don't, you can set one up on your own machine with Docker.&lt;/p&gt;

&lt;p&gt;To create a local Ghost instance with Docker, run the following at the root of your repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn ghost-local-create
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ghost data will be stored at &lt;code&gt;./ghost&lt;/code&gt;, which is in &lt;code&gt;.gitignore&lt;/code&gt; by default. In a &lt;strong&gt;private&lt;/strong&gt; repo you can choose to commit that too and have your Ghost content versioned and available whenever you need it.&lt;/p&gt;

&lt;p&gt;There are other scripts like &lt;code&gt;ghost-local-start&lt;/code&gt;, &lt;code&gt;ghost-local-stop&lt;/code&gt;, and &lt;code&gt;ghost-local-remove&lt;/code&gt; which you might find handy to manage the Docker container.&lt;/p&gt;

&lt;p&gt;After Docker downloads and sets up Ghost, it will be accessible on your browser at &lt;a href="http://localhost:3001"&gt;http://localhost:3001&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next you need to create an admin account on your newly-created Ghost. To do that, visit the admin interface at &lt;a href="http://localhost:3001/ghost"&gt;http://localhost:3001/ghost&lt;/a&gt; and follow the wizard.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exposing the Ghost Content API
&lt;/h4&gt;

&lt;p&gt;I'll use &lt;code&gt;http://localhost:3001&lt;/code&gt; for the examples, but you can replace that with your Ghost URL if you have an instance already running somewhere else.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to the admin interface at &lt;a href="http://localhost:3001/ghost"&gt;http://localhost:3001/ghost&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;On the left-hand sidebar, click on "Integrations"&lt;/li&gt;
&lt;li&gt;On the Integrations screen, click on &lt;a href="http://localhost:3001/ghost/#/settings/integrations/new/"&gt;+Add custom integration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Give it a name, like &lt;code&gt;nextjs&lt;/code&gt;, and click "Create" then "Save"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the important part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the same screen, you'll find two fields we need: &lt;strong&gt;Content API Key&lt;/strong&gt; and &lt;strong&gt;API URL&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Copy those into a new &lt;code&gt;.env.local&lt;/code&gt; file, like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# .env.local&lt;/span&gt;
&lt;span class="c"&gt;# replace values with your own&lt;/span&gt;
&lt;span class="nv"&gt;GHOST_API_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://localhost:3001
&lt;span class="nv"&gt;GHOST_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2a9356e4a5214c883ba886e58e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️ &lt;em&gt;This file is ignored by git by default. &lt;strong&gt;Don't&lt;/strong&gt; commit &lt;code&gt;env.local&lt;/code&gt; to git unless you know what you're doing.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alright! Ghost part's done.&lt;/p&gt;

&lt;h3&gt;
  
  
  💻  Running Next.js Locally
&lt;/h3&gt;

&lt;p&gt;Next.js is the missing static website &lt;em&gt;head&lt;/em&gt; to our *head*less Ghost. Let's stitch them together! This should be enough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your blog should be up and running at &lt;a href="http://localhost:3000"&gt;http://localhost:3000&lt;/a&gt;! &lt;em&gt;(If anything unexpected happens, please post an &lt;a href="https://github.com/fission-suite/nextjs-blog-starter-typescript-ghost/issues/new"&gt;issue&lt;/a&gt;.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now you can change the Next.js website code and the content on Ghost, and iterate quickly on them in the browser.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: live-reload works for Next.js code and Markdown files; to see changes to Ghost content you need to refresh the page.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🌐  Deploying to Fission
&lt;/h3&gt;

&lt;p&gt;When you're ready to publish, the first step is exporting your website to a set of static files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should create a directory at &lt;code&gt;./out&lt;/code&gt; with all your ready-to-publish files.&lt;/p&gt;

&lt;p&gt;Next we use the Fission CLI to send that out onto the internets.&lt;/p&gt;

&lt;h4&gt;
  
  
  🔰  Fission CLI Install and Sign Up
&lt;/h4&gt;

&lt;p&gt;To install the Fission command-line interface using brew, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew tap fission-suite/fission
brew &lt;span class="nb"&gt;install &lt;/span&gt;fission-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more ways of installing the Fission CLI, please check the &lt;a href="https://guide.fission.codes/developers/installation"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don't have a Fission account, you can create one without leaving the command-line by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fission setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  🌱  Register New Fission App
&lt;/h4&gt;

&lt;p&gt;You can pick a subdomain or let Fission choose a random one for you.&lt;/p&gt;

&lt;p&gt;To host the Next.js website at a random subdomain on &lt;code&gt;.fission.app&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fission app register
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To choose your own subdomain, use the &lt;code&gt;--name&lt;/code&gt; option like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fission app register &lt;span class="nt"&gt;--name&lt;/span&gt; my-beautiful-subdomain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That will create a &lt;code&gt;fission.yaml&lt;/code&gt; file. &lt;strong&gt;This one is safe to commit to git&lt;/strong&gt;, and you &lt;em&gt;should&lt;/em&gt; do that if you want to use the GitHub Action to build and deploy the website for you. Make sure there is a line saying &lt;code&gt;build: ./out&lt;/code&gt; in it. That's the directory where Next.js puts the exported website files.&lt;/p&gt;

&lt;h4&gt;
  
  
  🚀   Aand... Launch!
&lt;/h4&gt;

&lt;p&gt;One last step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;fission app publish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you're done! Your website should be up at a random URL returned to you by the Fission CLI or at &lt;code&gt;my-beautiful-subdomain.fission.app&lt;/code&gt; if you used the &lt;code&gt;--name&lt;/code&gt; option. Yay!&lt;/p&gt;

&lt;h4&gt;
  
  
  🤖  (Semi-)Automatic Deployment with the GitHub Action
&lt;/h4&gt;

&lt;p&gt;If you don't want to run the build locally and deploy to Fission every time you make a change to the Next.js code or Markdown files (who does?), this starter comes with &lt;strong&gt;a GitHub Action that automates that for you&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To get it working you need to set up 3 secrets for your repo. To do that, go to the &lt;strong&gt;"Settings" &amp;gt; "Secrets"&lt;/strong&gt; screen on your GitHub repo, then create a &lt;strong&gt;"New repository secret"&lt;/strong&gt; for each of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GHOST_API_URL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GHOST_API_KEY&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FISSION_KEY&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The values for the &lt;code&gt;GHOST_API_&lt;/code&gt; fields are the same ones you used for the &lt;code&gt;.env.local&lt;/code&gt; file above.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FISSION_KEY&lt;/code&gt; was created and stored locally for you by the Fission CLI when you set it up. Here's how you get it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat ~/.config/fission/key/machine_id.ed25519 | base64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all 3 secrets set up, you can trigger the &lt;code&gt;deploy&lt;/code&gt; action manually by clicking on &lt;strong&gt;"Run workflow" &amp;gt; "Run workflow"&lt;/strong&gt;, or see it in action after your next &lt;code&gt;git push&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Note:&lt;/p&gt;

&lt;p&gt;⚠️  To fetch the content from Ghost, &lt;strong&gt;the GitHub Action must be able to access the URL&lt;/strong&gt; entered in the &lt;code&gt;GHOST_API_URL&lt;/code&gt; secret.&lt;/p&gt;

&lt;p&gt;If you are running a local Ghost instance on your machine, &lt;code&gt;http://localhost:3001&lt;/code&gt; won't be visible to the outside.&lt;/p&gt;

&lt;p&gt;A simple way of exposing your local Ghost instance to a publicly-accessible URL is by using one of the &lt;a href="https://github.com/anderspitman/awesome-tunneling"&gt;open source alternatives to ngrok&lt;/a&gt; or &lt;a href="https://ngrok.com/"&gt;ngrok&lt;/a&gt; itself.&lt;/p&gt;

&lt;p&gt;With ngrok you do something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ngrok http 3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️  This is great for testing, but &lt;strong&gt;not secure&lt;/strong&gt;. Look into using &lt;code&gt;https&lt;/code&gt; if you're going to rely on this and don't want your Ghost API key and data to leak.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Why &lt;strong&gt;"(semi-)&lt;/strong&gt;" automatic then? 🤔&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Glad you asked. The GitHub Action can detect when you push to the GitHub repo because &lt;strong&gt;there's a built-in "on push" event&lt;/strong&gt; that can be used to &lt;strong&gt;trigger&lt;/strong&gt; it.&lt;/p&gt;

&lt;p&gt;But when you create a new post on Ghost or update an existing one, GitHub needs a way of finding out about it so it can run the deploy action. There's no &lt;code&gt;git push&lt;/code&gt; event happening, so the trigger is usually a &lt;a href="https://docs.github.com/en/rest/reference/actions#create-a-workflow-dispatch-event"&gt;&lt;strong&gt;webhook&lt;/strong&gt;&lt;/a&gt; (i.e. a POST request you send to a GitHub API URL.)&lt;/p&gt;

&lt;p&gt;🙂  Luckily, Ghost comes with the built-in ability to send webhooks when content changes happen.&lt;/p&gt;

&lt;p&gt;🙃  &lt;strong&gt;*Un*luckily&lt;/strong&gt;, though, Ghost doesn't let you customize the payload that goes in the webhook requests it sends, and GitHub &lt;strong&gt;requires&lt;/strong&gt; a certain field to be present telling it which &lt;code&gt;ref&lt;/code&gt; (usually a branch) you are referring to.&lt;/p&gt;

&lt;p&gt;Bottom line: &lt;strong&gt;after changing things &lt;em&gt;on Ghost&lt;/em&gt;, you need to trigger a build manually&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can do that via the GitHub interface ("Actions" &amp;gt; "Continuous Deployment" &amp;gt; "Run workflow" &amp;gt; "Run workflow"), or by &lt;strong&gt;running the handy script&lt;/strong&gt; we added to this starter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GITHUB_USER=your-username GITHUB_REPO=your-repo GITHUB_AUTH_TOKEN=your-auth-token trigger-github-deploy-action.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's how you can get an &lt;a href="https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token"&gt;auth token&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This situation is definitely not ideal, and can be solved with Ghost plugins, but we wanted to stick to the basic install.&lt;/p&gt;

&lt;h2&gt;
  
  
  🙏  Show your support
&lt;/h2&gt;

&lt;p&gt;Please &lt;a href="https://github.com/fission-suite/nextjs-blog-starter-typescript-ghost"&gt;give a  ⭐️&lt;/a&gt;  if you liked this project! We appreciate it :)&lt;/p&gt;

</description>
      <category>headless</category>
      <category>ghost</category>
      <category>nextjs</category>
      <category>fission</category>
    </item>
    <item>
      <title>The Complete Beginner's Guide to Deploying Your First Static Website to IPFS</title>
      <dc:creator>agentofuser</dc:creator>
      <pubDate>Sun, 12 May 2019 12:59:36 +0000</pubDate>
      <link>https://forem.com/agentofuser/the-complete-beginner-s-guide-to-deploying-your-first-static-website-to-ipfs-33po</link>
      <guid>https://forem.com/agentofuser/the-complete-beginner-s-guide-to-deploying-your-first-static-website-to-ipfs-33po</guid>
      <description>&lt;p&gt;This is going to be like the quickest tutorial ever. Underwhelming almost.&lt;/p&gt;

&lt;p&gt;You don't need to know anything about IPFS or distributed nothing, not even static site generators.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0kei65mk4lgtevcs4e0p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F0kei65mk4lgtevcs4e0p.jpg" title="static fire" alt="static&amp;lt;br&amp;gt;
fire"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ready? Ok, the first step is you gotta open up your terminal and type this in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; dwebsite/public
&lt;span class="nb"&gt;cd &lt;/span&gt;dwebsite
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;h1&amp;gt;Hello, worlds!&amp;lt;/h1&amp;gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; public/index.html

yarn global add @agentofuser/ipfs-deploy
&lt;span class="c"&gt;# or: npm install -g @agentofuser/ipfs-deploy&lt;/span&gt;
ipd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You with me? Ok, typed that. What else? Nothing.&lt;/p&gt;

&lt;p&gt;What? Yep. &lt;strong&gt;You're done here.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now you sit back and watch as the victory parade logs by 😎&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ℹ 🤔 No path argument specified. Looking for common ones…
✔ 📂 Found local public directory. Deploying that.
✔ 🚚 public weighs 24 B.
✔ 📌 It's pinned to Infura now with hash:
ℹ 🔗 QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
✔ 📋 Copied HTTP gateway URL to clipboard:
ℹ 🔗 https://ipfs.infura.io/ipfs/QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
✔ 🏄 Opened web browser (call with -O to disable.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there you have it. Your very own l33t &lt;a href="https://twitter.com/search?q=%23dweb" rel="noopener noreferrer"&gt;#dwebsite&lt;/a&gt; live on the hashlinked Merkleverse. &lt;a href="https://cloudflare-ipfs.com/ipfs/QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY" rel="noopener noreferrer"&gt;Check it out&lt;/a&gt;. Share with your friends.&lt;/p&gt;

&lt;p&gt;Sweet, huh? 🍬&lt;/p&gt;

&lt;h2&gt;
  
  
  Slow down, what exactly just happened?
&lt;/h2&gt;

&lt;p&gt;Alright, that was a bit much to take in at once. Let's rewind a little and look at it in slow-motion, with backstage commentary:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Where's the stuff?
&lt;/h3&gt;

&lt;p&gt;Truth be told, I could have called &lt;code&gt;ipd ./public&lt;/code&gt;, passing the directory to be deployed (&lt;code&gt;public&lt;/code&gt;) explicitly.&lt;/p&gt;

&lt;p&gt;But then you wouldn't see the "hard thinking" emoji as &lt;strong&gt;ipfs-deploy&lt;/strong&gt; probes smartly about for one of the many, often undocumented, &lt;a href="https://github.com/agentofuser/ipfs-deploy/blob/8023d82b5df68076ca79bc684f45ea64e5e67c06/index.js#L75" rel="noopener noreferrer"&gt;build destinations commonly used by static site generators&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ℹ 🤔 No path argument specified. Looking for common ones…
✔ 📂 Found local public directory. Deploying that.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, I actually combed through &lt;a href="https://www.staticgen.com" rel="noopener noreferrer"&gt;staticgen.com&lt;/a&gt;, installed a bunch of those static site generators, and built little test sites just so I could claim that "zero-config" headline. It's the little things, you know.&lt;/p&gt;

&lt;p&gt;This is what ipfs-deploy looks for when we're too lazy to type it out:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;guesses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// jekyll, hakyll, eleventy&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// forgot which&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// gatsby, hugo&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// nuxt&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;output&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// pelican&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// hexo&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;// metalsmith, middleman&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;website/build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// docusaurus&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;docs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// many others&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see from this blog's domain name, I'm a fan of Gatsby, but &lt;strong&gt;ipfs-deploy&lt;/strong&gt; serves all in need. Bring your own SSG and we'll slap an interplanetary jetpack on its back and send it flying. 🚀&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The upload
&lt;/h3&gt;

&lt;p&gt;This is what we're here for, that is, putting the website &lt;strong&gt;into space&lt;/strong&gt; (figuratively, for now). So a few seconds later, ipfs-deploy delivers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ 📌 It's pinned to Infura now with hash:
ℹ 🔗 QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Jackpot! That's the money shot right there.&lt;/p&gt;

&lt;p&gt;That little rambling of a &lt;a href="https://multiformats.io/multihash/" rel="noopener noreferrer"&gt;hash&lt;/a&gt; is the crux of the whole dweb judo. The magic utterance that summons by name your website from the cavernous depths of the connected dungeons, caring not where it lies, but only what it &lt;strong&gt;is&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intrinsic addressing, unbound by location or route.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Welcome &amp;lt;grave pause&amp;gt; to the distributed future.&lt;/p&gt;

&lt;h4&gt;
  
  
  Wait a minute, I thought I heard you say "distributed" 🧐
&lt;/h4&gt;

&lt;p&gt;Oh, you perspicacious reader.&lt;/p&gt;

&lt;p&gt;You're right: if IPFS is supposed to be a peer-to-peer protocol, why are we even &lt;em&gt;uploading&lt;/em&gt; at all, right? To a &lt;strong&gt;server&lt;/strong&gt;!? 🤢&lt;/p&gt;

&lt;p&gt;Shouldn't we just announce to the network that we have the hash and then wait to serve it ourselves to other peers as they request it?&lt;/p&gt;

&lt;p&gt;Yeah, you can do that. Then you close your laptop, wifi goes down, 💩 happens, and poof ✨ there goes your website.&lt;/p&gt;

&lt;p&gt;This is just like torrents: you need at least one seeder to be available for content to be reachable. If your website has tons of people &lt;em&gt;who run their own IPFS node&lt;/em&gt; visiting it and re-serving it to others, then on average your uptime will be pretty high.&lt;/p&gt;

&lt;p&gt;But there aren't that many such visitors around yet (hopefully &lt;a href="https://brave.com" rel="noopener noreferrer"&gt;Brave&lt;/a&gt; will fix that for us) and besides, it's a brand new website! 🐣 Poor thing wasn't born famous. Give it some time.&lt;/p&gt;

&lt;p&gt;It would be a different story if browsers had a decent &lt;a href="https://twitter.com/search?q=%23asyncUX" rel="noopener noreferrer"&gt;#asyncUX&lt;/a&gt; and visitors could easily tell them to queue the download for when a peer is available and then notify when it's ready (like a seamless "read it later" flow).&lt;/p&gt;

&lt;p&gt;But as it stands, if there's no one live the moment a request is made, things just hang and then time out. Definitely not &lt;a href="https://dev.to/foreword/"&gt;space-ready&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So we need a high-uptime seeder on our side. Or, in IPFS lingo, a &lt;strong&gt;"pinner."&lt;/strong&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Zero-Config Pinning with Infura.io
&lt;/h4&gt;

&lt;p&gt;A big design goal of &lt;strong&gt;ipfs-deploy&lt;/strong&gt; is to let you have that &lt;strong&gt;first happy experience&lt;/strong&gt; of just seeing something you made up on IPFS as fast as possible.&lt;/p&gt;

&lt;p&gt;One way to do that is to run a local IPFS daemon and have you serve the content yourself.&lt;/p&gt;

&lt;p&gt;But as we saw above, that would be a little gimmicky as it doesn't represent what an actual deployment that you can share with your friends would look like. Gotta have a stable pinner.&lt;/p&gt;

&lt;p&gt;Pinning stuff with decent uptime costs money though, so most pinning services understandably require you to at least sign up for a free tier before they'll agree to host your website.&lt;/p&gt;

&lt;p&gt;Not &lt;a href="https://infura.io/docs/ipfs/get/block_get.md" rel="noopener noreferrer"&gt;Infura.io&lt;/a&gt;, though!&lt;/p&gt;

&lt;p&gt;By some magic of careful rate-limiting, clever abuse prevention, growth capital, or reckless abandon, they let you just upload stuff out of the blue, &lt;a href="https://community.infura.io/t/how-often-do-you-garbage-collect-files-on-your-ipfs-node-and-how-long-will-a-file-persist-after-upload/44/2" rel="noopener noreferrer"&gt;unauthenticated&lt;/a&gt;, and they'll serve it for you indefinitely. (Even against your will it seems, as there is no clear way of *un*pinning things at the moment.)&lt;/p&gt;

&lt;p&gt;So we owe that slick on-ramp to their generosity: thank y'all at Infura, and please keep it up!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Also, if you own a pinning service yourself and would like to be part of the zero-config welcome package, please consider adding an "even freer" tier that doesn't require signup.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Newly-created static websites don't take up much room, have very little traffic, and are a great gateway into further IPFS consumption.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  You did it! 🏁
&lt;/h2&gt;

&lt;p&gt;If you got this far, condragulations. You rock! 🗿&lt;/p&gt;

&lt;p&gt;Not only did you deploy your first IPFS website, you can now boast you actually understand how it works by waving your hands and saying &lt;strong&gt;"oh, it's pretty much like git + bittorrent you know, easy peasy!"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you diligently followed the instructions, and somehow things blew up in your face, that's on me, not you. This is my commitment: &lt;strong&gt;your first happy experience, or it's a bug!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So please &lt;a href="https://github.com/agentofuser/ipfs-deploy/issues/new" rel="noopener noreferrer"&gt;tell me what went wrong&lt;/a&gt; and I'll smooth it out for you.&lt;/p&gt;

&lt;p&gt;We're all about removing friction around here 🧹🥌&lt;/p&gt;

&lt;p&gt;If you haven't had enough, stick around for some extra credit.&lt;/p&gt;

&lt;p&gt;And if you are content with where we got for now, please share that feeling with others by spreading and upvoting this guide far and wide :) Thank you!&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus chapter
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Free Redundancy with Pinata.cloud
&lt;/h3&gt;

&lt;p&gt;Having a stable pinner is cool and all, but isn't much different from regular web hosting. (In the "distributedness" sense, that is. In the "&lt;a href="https://www.youtube.com/watch?v=YIc6MNfv5iQ" rel="noopener noreferrer"&gt;content-addressable&lt;/a&gt;ness" sense, it's night and day.)&lt;/p&gt;

&lt;p&gt;One way to get a taste of the distributed nature of IPFS is by adding a second pinner, and &lt;strong&gt;ipfs-deploy&lt;/strong&gt; makes that easier.&lt;/p&gt;

&lt;p&gt;We're going to deploy both to &lt;strong&gt;Infura.io&lt;/strong&gt; and &lt;strong&gt;Pinata.cloud&lt;/strong&gt; so that visitors can download from both at the same time, or from one in case the other fails.&lt;/p&gt;

&lt;p&gt;Resilience! 🤹&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pinata.cloud" rel="noopener noreferrer"&gt;Pinata.cloud&lt;/a&gt; is a dedicated IPFS pinning service that gives you more control over what is being hosted.&lt;/p&gt;

&lt;p&gt;It allows you to delete pins and to add metadata that you can later use to filter and manage your deployments.&lt;/p&gt;

&lt;p&gt;There is a &lt;strong&gt;1 GB free tier&lt;/strong&gt; which is plenty enough for dev blogs, landing pages, documentation, and &lt;a href="https://twitter.com/search?q=%23yanggang" rel="noopener noreferrer"&gt;#YangGang&lt;/a&gt; fanpages. It &lt;em&gt;does&lt;/em&gt; require signup, but it's pretty straightforward and doesn't require credit card or personal information.&lt;/p&gt;

&lt;p&gt;After &lt;a href="https://pinata.cloud/signup" rel="noopener noreferrer"&gt;signing up&lt;/a&gt; and getting your &lt;a href="https://www.pinata.cloud/documentation#GettingStarted" rel="noopener noreferrer"&gt;API keys&lt;/a&gt;, go to your website's directory and copy your keys into a &lt;code&gt;.env&lt;/code&gt; file like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# dwebsite/.env&lt;/span&gt;
&lt;span class="nv"&gt;IPFS_DEPLOY__PINATA__API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;paste-the-api-key-here
&lt;span class="nv"&gt;IPFS_DEPLOY__PINATA__SECRET_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;and-the-secret-api-key-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;⚠ You don't want to make that information public ⚠&lt;/strong&gt;, so when you're doing this in a repository that you're going to host publicly, make sure to add the &lt;code&gt;.env&lt;/code&gt; file to your &lt;code&gt;.gitignore&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; .env &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One last config: to deploy to Pinata, you'll need to forward &lt;strong&gt;port 4002&lt;/strong&gt; on your router to your machine.&lt;/p&gt;

&lt;p&gt;Why? Because deploying to Pinata works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We first start a temporary local IPFS node,&lt;/li&gt;
&lt;li&gt;Pin the website locally,&lt;/li&gt;
&lt;li&gt;And send the hash to Pinata.&lt;/li&gt;
&lt;li&gt;Pinata then &lt;strong&gt;connects to our local node as a peer&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;Requests the hash we sent it,&lt;/li&gt;
&lt;li&gt;Then downloads and hosts it itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because of step 4, we need to be able to listen to external connections.&lt;/p&gt;

&lt;p&gt;Manually forwarding ports is a pain, I know, but support for &lt;a href="https://github.com/libp2p/js-libp2p/issues/104#issuecomment-488720839" rel="noopener noreferrer"&gt;NAT traversal is coming this quarter to js-ipfs&lt;/a&gt;, so that is one less hoop we'll need to jump soon 🤞&lt;/p&gt;

&lt;p&gt;By contrast, Infura exposes their IPFS node's HTTP API, so we can upload to it directly as an HTTP client without running a local node or listening for connections.&lt;/p&gt;

&lt;p&gt;Pinata's custom API strikes a different point in the flexibility-zeroconfigurability spectrum.&lt;/p&gt;

&lt;p&gt;Thankfully, with &lt;strong&gt;ipfs-deploy&lt;/strong&gt; we can have both ✌️&lt;/p&gt;

&lt;p&gt;Now that Pinata is set up, let's get back to the show. Here's what you run to deploy to both pinning services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipd &lt;span class="nt"&gt;-p&lt;/span&gt; infura &lt;span class="nt"&gt;-p&lt;/span&gt; pinata
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what you get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ℹ 🤔 No path argument specified. Looking for common ones…
✔ 📂 Found local public directory. Deploying that.
✔ 🚚 public weighs 24 B.
✔ 📌 It's pinned to Infura now with hash:
ℹ 🔗 QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing new so far. Now to Pinata (featuring new emojis!):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ ☎️ Connected to temporary local IPFS node.
✔ 📶 Port 4002 is externally reachable.
✔ 📌 Pinned to temporary local IPFS node with hash:
ℹ 🔗 QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
✔ 📌 It's pinned to Pinata now with hash:
ℹ 🔗 QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
✔ ✋️ Stopped temporary local IPFS node.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there it is: same hash, different locations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ 📋 Copied HTTP gateway URL to clipboard:
ℹ 🔗 https://ipfs.infura.io/ipfs/QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY
✔ 🏄 Opened web browser (call with -O to disable.)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the same content on whichever gateway you want by replacing "ipfs.infura.io" with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gateway.pinata.cloud/ipfs/QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY" rel="noopener noreferrer"&gt;gateway.pinata.cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ipfs.io/ipfs/QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY" rel="noopener noreferrer"&gt;ipfs.io&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudflare-ipfs.com/ipfs/QmQzKWGdjjQeTXrruYL2vLkCqRP8TyXnG1a9QEJjDM8WTY" rel="noopener noreferrer"&gt;cloudflare-ipfs.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or any of the ones listed here: &lt;a href="https://ipfs.github.io/public-gateway-checker" rel="noopener noreferrer"&gt;https://ipfs.github.io/public-gateway-checker&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've said it before, but I find this so cool that it bears repeating:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Intrinsic addressing, unbound by location or route.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or: &lt;strong&gt;calling data by &lt;em&gt;what&lt;/em&gt; it is, not &lt;em&gt;where&lt;/em&gt; it is.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's cryptographic hashing for ya 💪&lt;/p&gt;

&lt;h3&gt;
  
  
  The telling-your-friends part 🗣
&lt;/h3&gt;

&lt;p&gt;Alright, we're done here, right? Feeling all great and distributed. Now go tell your friends about it over the phone 📞&lt;/p&gt;

&lt;p&gt;— Hey Jessie, guess what?&lt;br&gt;&lt;br&gt;
— What?&lt;br&gt;&lt;br&gt;
— I've got my website up on the dwebs!!&lt;br&gt;&lt;br&gt;
— Yay friend, how cool! I bet that was super hard.&lt;br&gt;&lt;br&gt;
— Nah, there's this npm package, y'know...&lt;br&gt;&lt;br&gt;
— Yeah, yeah, lemme see the website, where's it at?&lt;br&gt;&lt;br&gt;
— Oh it's at i-p-f-s-dot-i-o-slash-i-p-f-s-slash... Er...&lt;br&gt;&lt;br&gt;
— Slash what?&lt;br&gt;&lt;br&gt;
— It's uh... You got a pen? It's uh... uppercase Q, lowercase m, uppercase Q,&lt;br&gt;
uppercase T... Ugh... How about I text you the URL?&lt;br&gt;&lt;br&gt;
— Ok, sure, but what if I'm just some random person who sees your URL on a billboard? You won't be able to text me then, will you?&lt;br&gt;&lt;br&gt;
— Hm, I guess not.&lt;br&gt;&lt;br&gt;
— You know what, how about you call me when you have something memorable I can type in the browser?&lt;br&gt;&lt;br&gt;
 — Wow, harsh.&lt;/p&gt;

&lt;p&gt;Ok that very lifelike conversation went south pretty fast.&lt;/p&gt;

&lt;p&gt;It turns out content-addressing on its own &lt;a href="https://en.wikipedia.org/wiki/Zooko's_triangle" rel="noopener noreferrer"&gt;doesn't gel quite well&lt;/a&gt; with the limited human memory buffer.&lt;/p&gt;

&lt;p&gt;Plus, friends can be tough.&lt;/p&gt;

&lt;p&gt;What do we do then?&lt;/p&gt;
&lt;h4&gt;
  
  
  A pretty URL
&lt;/h4&gt;

&lt;p&gt;Human-readable naming for IPFS websites is definitely an area that needs smoothing out.&lt;/p&gt;

&lt;p&gt;But if (and that's a big if) you keep within the constraint of using the free Cloudflare IPFS Gateway for now, ipfs-deploy wraps it all together in a pretty neat way.&lt;/p&gt;

&lt;p&gt;Here is &lt;em&gt;actual footage&lt;/em&gt; of me deploying interplanetarygatsby.com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ipd &lt;span class="nt"&gt;-p&lt;/span&gt; infura &lt;span class="nt"&gt;-p&lt;/span&gt; pinata &lt;span class="nt"&gt;-d&lt;/span&gt; cloudflare
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what I see after the uploads are over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✔ 🙌 SUCCESS!
ℹ 🔄 Updated DNS TXT interplanetarygatsby.com to:
ℹ 🔗 dnslink=/ipfs/QmSNf4sScZUmpNqBWAAs9S5tC4XkQRNepA3KbF4aipGGeq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It makes me smile every time at the sheer effortlessness of it 😌&lt;/p&gt;

&lt;p&gt;There are some one-time steps you need to take to get there though:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Buy a domain&lt;/li&gt;
&lt;li&gt;Sign up for a Cloudflare account&lt;/li&gt;
&lt;li&gt;Move your domain's DNS zone to Cloudflare&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.cloudflare.com/distributed-web-gateway/#connectingyourwebsite" rel="noopener noreferrer"&gt;Hook up your domain&lt;/a&gt;
to their IPFS gateway&lt;/li&gt;
&lt;li&gt;Get your
&lt;a href="https://support.cloudflare.com/hc/en-us/articles/200167836-Where-do-I-find-my-CloudFlare-API-key-" rel="noopener noreferrer"&gt;API keys&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Between actually performing those configuration steps and waiting for DNS information to propagate, this whole thing can take a couple of hours.&lt;/p&gt;

&lt;p&gt;That's why I put that part in this bonus chapter and left the base instructions zero-config. In time, we'll remove more and more friction and make that first happy experience ever happier 😃⬅️🧹🥌&lt;/p&gt;

&lt;p&gt;So after steps 1-5 are done, the last thing you need to do is add your domain and Cloudflare API credentials to your website's &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# dwebsite/.env&lt;/span&gt;
&lt;span class="nv"&gt;IPFS_DEPLOY_SITE_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example.com
&lt;span class="nv"&gt;IPFS_DEPLOY_CLOUDFLARE__API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;paste-your-cloudflare-api-key-here
&lt;span class="nv"&gt;IPFS_DEPLOY_CLOUDFLARE__API_EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;the-email-you-used-to-sign-up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now go ahead, fire away with &lt;code&gt;ipd -d cloudflare&lt;/code&gt;, and tell all those billboards about it! 📣📣📣&lt;/p&gt;

&lt;p&gt;៚&lt;/p&gt;




&lt;h2&gt;
  
  
  Postface: A Call for Curlers 🧹🥌
&lt;/h2&gt;

&lt;p&gt;While writing this guide, I happened upon the &lt;a href="https://emojipedia.org/curling-stone/" rel="noopener noreferrer"&gt;"curling stone" emoji&lt;/a&gt; and felt an instant connection to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fue0j9gslx87p5mddzby7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fue0j9gslx87p5mddzby7.gif" title="wild sweeping" alt="wild sweeping"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To be honest, I've always found the idea of curling a little... odd. But a whole team sport dedicated to frantically &lt;strong&gt;removing friction&lt;/strong&gt; from a path just so that this peculiar artifact can gracefully and &lt;strong&gt;effortlessly&lt;/strong&gt; glide its way onto a goal is so... moving.&lt;/p&gt;

&lt;p&gt;That's how I want &lt;a href="https://github.com/agentofuser/ipfs-deploy" rel="noopener noreferrer"&gt;ipfs-deploy&lt;/a&gt; to feel to the user. A silk-smooth experience landing them right on the distributed web without breaking a sweat, and a wild sweeping crowd cheering them on.&lt;/p&gt;

&lt;p&gt;If that sounds like your kind of sport, say hello in the &lt;a href="https://github.com/agentofuser/ipfs-deploy/issues?q=is%3Aissue+is%3Aopen+label%3A" rel="noopener noreferrer"&gt;issues&lt;/a&gt; and let's polish some stuff!&lt;/p&gt;

</description>
      <category>ipfs</category>
      <category>gatsby</category>
      <category>dweb</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Foreword: Space-Ready Publishing with Gatsby and IPFS</title>
      <dc:creator>agentofuser</dc:creator>
      <pubDate>Sat, 04 May 2019 13:37:00 +0000</pubDate>
      <link>https://forem.com/agentofuser/foreword-space-ready-publishing-with-gatsby-and-ipfs-2hc3</link>
      <guid>https://forem.com/agentofuser/foreword-space-ready-publishing-with-gatsby-and-ipfs-2hc3</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://interplanetarygatsby.com"&gt;Interplanetary Gatsby&lt;/a&gt;&lt;/strong&gt; is a blog about making &lt;strong&gt;space-grade websites&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;“Static” and “offline-first” don’t really do them justice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In space, there is no such thing as “online”&lt;/strong&gt; —this naïve illusion of near-simultaneity bore by the small window of low-latency communications that graced our species in the few decades that followed millenia of foot, horse, and sea, and preceded our belated (re)launch into the deeper waters of the cosmic ocean.&lt;/p&gt;

&lt;p&gt;For light is slow, and so far as our minds have been able to see, there is no short-term escape to its grasp on the reach of our interstellar voice.&lt;/p&gt;

&lt;p&gt;Asynchronicity is all that is or ever was or ever will be.&lt;/p&gt;




&lt;p&gt;Mars is 3.2 light-minutes away at its closest and 22.2 light-minutes away at its farthest.&lt;/p&gt;

&lt;p&gt;Imagine clicking a link to a news article and sitting there for a &lt;em&gt;minimum&lt;/em&gt; of &lt;strong&gt;6 minutes&lt;/strong&gt; for it to load.&lt;/p&gt;

&lt;p&gt;It doesn’t matter how hand-optimized the page is or how high your bandwidth. That’s the fixed cost that the very first bit will have to crawl through before it gets to you.&lt;/p&gt;

&lt;p&gt;How do you design around this constraint?&lt;/p&gt;

&lt;p&gt;You cache the hell out of everything. You prefetch. You reach out to people on your own planet before capitulating to the space link. You change the user experience to decouple fetching from reading, you queue and notify instead of blocking and spinning.&lt;/p&gt;

&lt;p&gt;These are the things I want to explore with &lt;a href="https://gatsbyjs.org"&gt;Gatsby&lt;/a&gt; and &lt;a href="https://ipfs.io"&gt;IPFS&lt;/a&gt;—the InterPlanetary File System.&lt;/p&gt;

&lt;p&gt;They are the perfect tools for this job, and I invite you to join me on this journey &lt;em&gt;into the vastness of the Merkleverse&lt;/em&gt;.&lt;/p&gt;

</description>
      <category>ipfs</category>
      <category>gatsby</category>
      <category>dweb</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
