I’m excited to announce that jpfchang.org now supports IPFS (InterPlanetary File System) content delivery via Cloudflare’s IPFS Gateway! This integration allows images and static assets to be served from a decentralized network, improving content resilience, permanence, and censorship resistance.
🌐 What is IPFS?
IPFS is a peer-to-peer distributed file system that seeks to connect all computing devices with the same system of files. Unlike traditional web hosting (which uses location-based addressing like https://example.com/image.jpg), IPFS uses content addressing based on cryptographic hashes.
Key Concepts
- Content Identifiers (CIDs): Every piece of content gets a unique hash (e.g.,
QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco) - Immutability: Content with the same CID is always identical - you can’t change it without changing the hash
- Decentralization: Files are distributed across many nodes rather than a single server
- Permanence: Content stays available as long as at least one node hosts it
Why IPFS Matters
- Censorship Resistance: No single point of failure or control
- Content Permanence: Archives and historical content remain accessible
- Bandwidth Efficiency: Popular content cached by many nodes reduces origin load
- Verifiability: CID proves content hasn’t been tampered with
- Offline Access: IPFS nodes can sync content for offline availability
🚀 Technical Implementation
The integration uses Cloudflare’s IPFS Gateway (cloudflare-ipfs.com), which provides a bridge between traditional HTTP/HTTPS and the IPFS network. This approach gives us the benefits of IPFS without requiring users to run IPFS nodes or install browser extensions.
Architecture Components
1. IPFS Utility Library (src/lib/ipfs.ts)
Core functionality for working with IPFS:
import { getIpfsUrl, isValidCid } from '../lib/ipfs';
// Generate IPFS gateway URL
const url = getIpfsUrl('QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco');
// => 'https://cloudflare-ipfs.com/ipfs/QmXoy...'
// Validate CID format
isValidCid('QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco'); // true
isValidCid('invalid'); // false
Features:
- CID validation (supports both CIDv0
Qm...and CIDv1bafy...formats) - Multiple gateway support (Cloudflare, IPFS.io, Dweb.link, Pinata)
- Path resolution within IPFS directories
- Content mapping system for local-to-IPFS fallback
- Gateway health checking (client-side)
2. IpfsImage Component (src/components/IpfsImage.astro)
Astro component for IPFS-enabled images:
---
import IpfsImage from '../components/IpfsImage.astro';
---
<!-- Serve image from IPFS -->
<IpfsImage
cid="QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco"
alt="Example IPFS image"
loading="lazy"
/>
<!-- With path for directory content -->
<IpfsImage
cid="QmDirectory..."
path="/image.png"
alt="Image from IPFS directory"
/>
<!-- Fallback to multiple gateways -->
<IpfsImage
cid="QmExample..."
alt="Resilient image"
fallback={true}
/>
Props:
cid: IPFS Content Identifier (required ifsrcnot provided)src: Local path fallback (used ifcidnot provided)path: Optional path within IPFS contentgateway: Which IPFS gateway to use (defaults to Cloudflare)fallback: Enable srcset with multiple gateways for resilience- Standard HTML image attributes:
alt,width,height,loading,class
3. TypeScript Type Definitions
Updated src/env.d.ts with IPFS configuration types:
interface CloudflareEnv {
// ... existing environment variables
// IPFS Gateway configuration
IPFS_GATEWAY?: string;
IPFS_PINNING_SERVICE?: 'pinata' | 'web3storage' | 'nftstorage';
IPFS_PINNING_API_KEY?: string;
IPFS_PINNING_API_SECRET?: string;
}
📚 Usage Examples
Basic IPFS Image
---
import IpfsImage from '../components/IpfsImage.astro';
---
<article>
<IpfsImage
cid="QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG"
alt="IPFS Logo"
class="w-64 h-64"
/>
</article>
Content Mapping (Local → IPFS)
For gradual migration, map local paths to IPFS CIDs in src/lib/ipfs.ts:
export const IPFS_CONTENT_MAP: Record<string, string> = {
'/images/blog/article-1/hero.webp': 'QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco',
'/images/blog/article-2/diagram.png': 'QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG',
};
// Use helper to automatically resolve
import { getAssetUrl } from '../lib/ipfs';
const imageUrl = getAssetUrl('/images/blog/article-1/hero.webp');
// Returns IPFS URL if mapped, otherwise returns local path
Multiple Gateway Fallback
For critical content, enable multiple gateways:
<IpfsImage
cid="QmCriticalContent..."
alt="Important diagram"
fallback={true}
/>
<!-- Generates srcset with multiple gateways: -->
<!-- src="https://cloudflare-ipfs.com/ipfs/Qm..." -->
<!-- srcset="https://ipfs.io/ipfs/Qm... 2x, https://dweb.link/ipfs/Qm... 3x, ..." -->
Markdown Blog Posts
In markdown files, reference IPFS images using standard markdown syntax after adding content mapping:

Then add to IPFS_CONTENT_MAP:
'/images/blog/my-article/hero.webp': 'QmYourCID...'
🛠️ Gateway Options
The system supports multiple IPFS gateways:
| Gateway | URL | Best For |
|---|---|---|
| Cloudflare | cloudflare-ipfs.com | Primary (fastest, most reliable) |
| IPFS.io | ipfs.io | Fallback (official gateway) |
| Dweb.link | dweb.link | Fallback (Protocol Labs) |
| Pinata | gateway.pinata.cloud | Fallback (pinning service) |
Switch gateways in code:
import { getIpfsUrl } from '../lib/ipfs';
// Use different gateway
const url = getIpfsUrl('QmCID...', null, 'ipfsio');
// => 'https://ipfs.io/ipfs/QmCID...'
Or set default via environment variable:
IPFS_GATEWAY=https://ipfs.io
🔐 Content Verification
One of IPFS’s most powerful features is built-in verification. When you fetch content by CID, the gateway automatically verifies that the content matches the hash. This provides:
- Tamper-proof: Content can’t be silently modified
- Trust-minimized: Don’t need to trust the gateway
- Self-authenticating: CID proves content authenticity
Example:
// This CID always resolves to the exact same content
const cid = 'QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG';
// Even if served from different gateways, content is identical and verified
getIpfsUrl(cid, null, 'cloudflare'); // Verified
getIpfsUrl(cid, null, 'ipfsio'); // Verified
getIpfsUrl(cid, null, 'dweb'); // Verified
🌍 Use Cases
1. Archival Content
Historical articles, important documentation, and research papers benefit from IPFS’s permanence:
// Archive a blog post on IPFS
// Even if jpfchang.org goes down, content remains accessible via CID
const archivedPost = 'QmArchivePostCID...';
2. User-Generated Content
Accept content submissions with cryptographic proof:
// User uploads image, gets CID
// Can verify the exact content was used
const userSubmission = 'QmUserImageCID...';
3. Large Media Files
Distribute bandwidth load across IPFS network:
// High-resolution images, videos served from distributed nodes
const largeImage = 'QmHighResImageCID...';
4. Content Attestation
Prove you published content at a specific time by anchoring CID on blockchain or distributed ledger.
📊 Performance Considerations
Pros
- ✅ CDN-like performance: Cloudflare Gateway is globally distributed
- ✅ Caching: Popular content cached across IPFS nodes
- ✅ Reduced origin load: Content served from peers
- ✅ Resilience: Multiple gateways provide fallback
Cons
- ⚠️ First-fetch latency: Unpinned content may be slower on first request
- ⚠️ Gateway dependency: This implementation still relies on HTTP gateways
- ⚠️ Availability: Content needs at least one pinning node
Best Practices
- Pin important content: Use pinning services (Pinata, Web3.Storage, NFT.Storage)
- Warm the cache: Pre-fetch critical content after upload
- Use Cloudflare Gateway primarily: It’s fastest and most reliable
- Enable fallbacks: For critical images, use multiple gateways
- Lazy loading: Load IPFS images lazily to improve perceived performance
🔮 Future Enhancements
Planned improvements for IPFS integration:
1. Automated Pinning
Integrate with pinning services for automatic content upload:
// Upload to IPFS via API
const cid = await uploadToPinata(file, apiKey);
// Automatically update IPFS_CONTENT_MAP
2. Admin Panel
Web UI for managing IPFS content:
- Upload images to IPFS
- View all pinned content
- Update content mappings
- Monitor gateway health
3. IPNS (Mutable References)
Use IPNS for mutable content pointers:
// Point to latest version while keeping old versions
const latestVersion = 'ipns://k51qzi5uqu5...';
4. Direct IPFS Access
Add service worker for native IPFS protocol support:
// Access content directly via IPFS protocol (no gateway)
ipfs://QmCID...
5. Content Deduplication
Automatic detection of duplicate content:
// If image already exists on IPFS, reuse existing CID
const existingCid = await findExistingCid(fileHash);
🏗️ Technical Specifications
CID Format Support
CIDv0 (Legacy):
- Format: Base58-encoded multihash (46 characters)
- Example:
QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG - Regex:
/^Qm[1-9A-HJ-NP-Za-km-z]{44}$/
CIDv1 (Modern):
- Format: Multibase-encoded with explicit version, codec, hash
- Example:
bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi - Regex:
/^b[a-z2-7]{58}$/
API Reference
Core Functions (src/lib/ipfs.ts):
// Validate CID
isValidCid(cid: string): boolean
// Generate gateway URL
getIpfsUrl(cid: string, path?: string, gateway?: IpfsGateway): string
// Generate multiple gateway URLs
getIpfsUrls(cid: string, path?: string, gateways?: IpfsGateway[]): string[]
// Extract CID from URL
extractCidFromUrl(url: string): string | null
// Get asset URL (with IPFS fallback)
getAssetUrl(localPath: string, gateway?: IpfsGateway): string
// Check gateway health (browser only)
checkGatewayHealth(gateway?: IpfsGateway, timeout?: number): Promise<boolean>
// Pinning service endpoint
getPinningServiceEndpoint(service: IpfsPinningService): string
Environment Variables
Optional configuration via Cloudflare environment:
# Custom IPFS gateway (defaults to cloudflare-ipfs.com)
IPFS_GATEWAY=https://ipfs.io
# Pinning service configuration
IPFS_PINNING_SERVICE=pinata
IPFS_PINNING_API_KEY=your_api_key
IPFS_PINNING_API_SECRET=your_api_secret
🎓 Learning Resources
Want to learn more about IPFS?
- Official Docs: docs.ipfs.tech
- IPFS Whitepaper: IPFS - Content Addressed, Versioned, P2P File System
- Cloudflare IPFS Gateway: cloudflare.com/distributed-web-gateway
- Protocol Labs: protocol.ai
🤝 Community & Ecosystem
IPFS is backed by a vibrant ecosystem:
- Protocol Labs: Core development team
- Filecoin: Incentivized storage network built on IPFS
- Brave Browser: Native IPFS support
- Opera: Built-in IPFS resolver
- Cloudflare: Free public gateway
💭 Why This Matters
This integration aligns with core principles of the decentralized web:
- Resilience: Content survives server outages, domain seizures, hosting shutdowns
- Ownership: True content ownership through cryptographic verification
- Permanence: Important information remains accessible long-term
- Trust-minimization: Don’t need to trust a central authority
- Open Access: Anyone can run an IPFS node and serve content
As researchers and developers, we should embrace technologies that make knowledge more accessible, permanent, and censorship-resistant.
📝 Try It Yourself
Want to add IPFS content to jpfchang.org?
-
Upload your content to IPFS using a pinning service:
- Pinata (easiest, free tier)
- Web3.Storage (free, generous limits)
- NFT.Storage (free, focused on NFTs)
-
Get the CID from the upload response
-
Add to
IPFS_CONTENT_MAPor useIpfsImagecomponent directly -
Verify content loads from
https://cloudflare-ipfs.com/ipfs/YOUR_CID
🔗 Related Articles
This IPFS integration complements other decentralized features:
- [[Web3 Wallet Authentication]] - MetaMask/Brave Wallet/SafePal authentication
- [[Cryptocurrency Payment Integration]] - USDC payments via NOWPayments
- [[Building a Censorship-Resistant Blog]] - Technical architecture for resilience
- [[Major Site Redesign]] - Latest visual updates
✉️ Feedback & Contributions
Have ideas for IPFS features? Found a bug? Want to contribute?
- Email: [email protected]
- GitHub: @JohnThre
- Issues: github.com/JohnThre/jpfchang.org/issues
Let’s build a more decentralized, resilient web together! 🌐🚀
This integration is part of my commitment to Web3 and decentralized technologies. Check out my other articles on blockchain, cryptocurrency, and the decentralized web.