Xây dựng Crypto Paste - Pastebin hiện đại với Cloudflare
Hành trình tạo ra một dịch vụ pastebin tự host sử dụng React, TypeScript, Cloudflare Workers và end-to-end encryption. Từ ý tưởng đến triển khai production.

Gần đây mình đã hoàn thành một project khá thú vị - Crypto Paste, một dịch vụ pastebin được xây dựng hoàn toàn trên hệ sinh thái Cloudflare với focus mạnh vào bảo mật và hiệu năng. Trong bài viết này, mình sẽ chia sẻ về quá trình thiết kế, development và những bài học rút ra từ project này.
🎯 Tại sao lại cần một Pastebin khác?
Có rất nhiều dịch vụ pastebin như Pastebin.com, GitHub Gist, hay Hastebin. Tuy nhiên, mình muốn:
- End-to-End Security: Mã hóa AES-256-GCM hoàn toàn client-side
- Modern Tech Stack: React 18 + TypeScript + Vite để có trải nghiệm dev tốt nhất
- Zero-Knowledge Architecture: Server không bao giờ thấy được nội dung gốc
- Performance cao: Tận dụng CDN toàn cầu của Cloudflare
- Chi phí thấp: Sử dụng Cloudflare’s generous free tier
- Privacy-First: Burn after read, auto-expiring, không tracking
🏗️ Architecture Overview
Project được thiết kế theo kiến trúc serverless hiện đại với focus vào security:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ React 18 + │ │ Cloudflare │ │ Cloudflare │
│ TypeScript │────│ Workers + │────│ KV Store │
│ (Frontend) │ │ Hono API │ │ (Encrypted) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
│ │ │
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Web Crypto API │ │ AES-256-GCM │ │ TTL Support │
│ (Encryption) │ │ (Client-side) │ │ (Auto-expire) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Frontend (React + TypeScript)
- Modern framework: React 18 với TypeScript cho type safety
- Build tool: Vite cho development experience tốt nhất
- Styling: Tailwind CSS cho rapid prototyping
- Client-side encryption: Web Crypto API với AES-256-GCM
- Responsive design: Mobile-first approach
Backend (Cloudflare Workers + Hono)
- Framework: Hono cho type-safe API development
- Edge computing: Chạy gần user nhất có thể
- Zero cold starts: Always-on performance
- Built-in security: DDoS protection, rate limiting
- CORS handling: Secure cross-origin requests
Database (Cloudflare KV)
- Encrypted storage: Chỉ lưu encrypted data
- Global replication: Low latency reads worldwide
- TTL support: Automatic paste expiration
- Key-value design: Perfect cho paste data structure
📁 Project Structure
crypto-paste/
├── src/ # React application source
│ ├── components/ # React components
│ ├── hooks/ # Custom React hooks
│ ├── lib/ # Utility libraries
│ ├── types/ # TypeScript type definitions
│ └── worker.ts # Cloudflare Worker với Hono
├── public/ # Static assets
├── index.html # Entry point
├── package.json # Dependencies & scripts
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite build configuration
├── tailwind.config.js # Tailwind CSS config
├── wrangler.toml # Worker deployment config
├── wrangler.toml.example # Template cho setup
└── DEPLOYMENT.md # Deployment instructions
🔧 Key Features
1. End-to-End Encryption
Mã hóa AES-256-GCM hoàn toàn client-side, encryption key không bao giờ leave browser:
// Generate encryption key từ URL fragment
const generateKey = async (): Promise<CryptoKey> => {
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
return key;
};
// Encrypt content trước khi gửi lên server
const encryptContent = async (content: string, key: CryptoKey): Promise<string> => {
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(content);
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
key,
encoded
);
return btoa(JSON.stringify({
iv: Array.from(iv),
data: Array.from(new Uint8Array(encrypted))
}));
};
2. Burn After Read
Pastes có thể tự destruct sau khi được đọc một lần:
interface PasteOptions {
burnAfterRead: boolean;
expiration: '10m' | '1h' | '1d' | '1w';
}
// Server sẽ delete paste ngay sau first read
const createBurnAfterReadPaste = async (content: string, options: PasteOptions) => {
const response = await fetch('/api/pastes', {
method: 'POST',
body: JSON.stringify({
content: await encryptContent(content, key),
burnAfterRead: options.burnAfterRead,
expiration: options.expiration
})
});
};
3. Modern UI với Dark/Light Theme
React components với Tailwind CSS và theme switching:
// Theme context với React
const ThemeContext = createContext<{
theme: 'light' | 'dark';
toggleTheme: () => void;
}>({
theme: 'light',
toggleTheme: () => {}
});
// Tailwind classes cho responsive design
<div className="min-h-screen bg-white dark:bg-gray-900 transition-colors">
<div className="max-w-4xl mx-auto px-4 py-8">
<textarea className="w-full h-96 p-4 border border-gray-300 dark:border-gray-600
bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100
rounded-lg resize-none focus:ring-2 focus:ring-blue-500" />
</div>
</div>
4. Syntax Highlighting
Automatic language detection với Prism.js cho 200+ ngôn ngữ:
import Prism from 'prismjs';
import 'prismjs/themes/prism-tomorrow.css';
const highlightCode = (code: string, language: string): string => {
if (Prism.languages[language]) {
return Prism.highlight(code, Prism.languages[language], language);
}
return code;
};
// Auto-detect language từ content
const detectLanguage = (content: string): string => {
// Logic để detect ngôn ngữ programming
if (content.includes('function') && content.includes('{')) return 'javascript';
if (content.includes('def ') && content.includes(':')) return 'python';
if (content.includes('#include') && content.includes('int main')) return 'c';
return 'text';
};
⚡ Cloudflare Workers với Hono Framework
Type-Safe API với Hono
import { Hono } from 'hono';
import { cors } from 'hono/cors';
type Bindings = {
PASTES_KV: KVNamespace;
ENVIRONMENT: string;
};
const app = new Hono<{ Bindings: Bindings }>();
// CORS middleware
app.use('*', cors({
origin: ['https://crypto-paste.pages.dev', 'http://localhost:5173'],
allowMethods: ['GET', 'POST', 'DELETE'],
allowHeaders: ['Content-Type'],
}));
// API Routes
app.post('/api/pastes', async (c) => {
return createPaste(c);
});
app.get('/api/pastes/:id', async (c) => {
return getPaste(c);
});
app.delete('/api/pastes/:id', async (c) => {
return deletePaste(c);
});
export default app;
Create Paste với Encryption Support
interface PasteData {
content: string; // Encrypted content
burnAfterRead: boolean;
expiration: string;
created: number;
}
async function createPaste(c: Context) {
try {
const { content, burnAfterRead, expiration } = await c.req.json();
// Generate unique ID (URL-safe)
const id = generateSecureId();
// Calculate expiration timestamp
const expirationMs = getExpirationMs(expiration);
const ttl = expirationMs ? Math.floor(expirationMs / 1000) : undefined;
const pasteData: PasteData = {
content, // Already encrypted client-side
burnAfterRead,
expiration,
created: Date.now()
};
// Store in KV với TTL
await c.env.PASTES_KV.put(id, JSON.stringify(pasteData), {
expirationTtl: ttl
});
return c.json({ id }, 201);
} catch (error) {
console.error('Error creating paste:', error);
return c.json({ error: 'Failed to create paste' }, 500);
}
}
function generateSecureId(): string {
const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
let result = '';
for (let i = 0; i < 16; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
Get Paste với Burn After Read
async function getPaste(c: Context) {
try {
const id = c.req.param('id');
if (!id || id.length !== 16) {
return c.json({ error: 'Invalid paste ID' }, 400);
}
const data = await c.env.PASTES_KV.get(id);
if (!data) {
return c.json({ error: 'Paste not found or expired' }, 404);
}
const paste: PasteData = JSON.parse(data);
// Nếu là burn after read, delete ngay lập tức
if (paste.burnAfterRead) {
await c.env.PASTES_KV.delete(id);
}
return c.json({
content: paste.content, // Encrypted content
burnAfterRead: paste.burnAfterRead,
created: paste.created
});
} catch (error) {
console.error('Error getting paste:', error);
return c.json({ error: 'Failed to retrieve paste' }, 500);
}
}
🚀 Development & Deployment
Prerequisites & Setup
# Clone repository
git clone https://github.com/musicsms/crypto-paste.git
cd crypto-paste
# Install dependencies
npm install
# Login to Cloudflare
npx wrangler login
# Create KV namespaces
npx wrangler kv namespace create "PASTES_KV"
npx wrangler kv namespace create "PASTES_KV" --preview
Local Development
# Start Worker (backend)
npm run worker:dev
# Start Frontend (trong terminal khác)
npm run dev
# Access at http://localhost:5173
Production Deployment
# Deploy Worker first
npm run worker:deploy
# Deploy Frontend to Cloudflare Pages
npm run deploy
# Setup custom domain trong Cloudflare Dashboard
Configuration
Copy wrangler.toml.example
và update với KV namespace IDs:
name = "crypto-paste-worker"
main = "src/worker.ts"
compatibility_date = "2023-12-01"
[[kv_namespaces]]
binding = "PASTES_KV"
id = "your-production-kv-namespace-id"
preview_id = "your-preview-kv-namespace-id"
[vars]
ENVIRONMENT = "production"
📊 Performance & Security Metrics
Edge Performance
- Global latency: <50ms response time from 330+ locations
- Cold start: Zero với Cloudflare Workers
- Uptime: 99.99% (Cloudflare SLA)
- Bandwidth: Unlimited với global CDN
Security Features
// Rate limiting với KV
const rateLimit = async (clientIP: string, limit: number = 10): Promise<boolean> => {
const key = `rate_limit:${clientIP}`;
const current = await env.PASTES_KV.get(key);
if (current && parseInt(current) >= limit) {
return false; // Rate limited
}
await env.PASTES_KV.put(key, String((parseInt(current || '0') + 1)), {
expirationTtl: 3600 // 1 hour window
});
return true;
};
// Content validation
const validatePasteContent = (content: string): boolean => {
return content.length > 0 && content.length <= 1000000; // 1MB limit
};
🔒 Zero-Knowledge Security Architecture
1. Client-Side Encryption Flow
// Encryption key generation và management
class CryptoManager {
private key: CryptoKey | null = null;
async generateKey(): Promise<string> {
this.key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// Export key để đưa vào URL fragment
const keyData = await crypto.subtle.exportKey('raw', this.key);
return btoa(String.fromCharCode(...new Uint8Array(keyData)));
}
async encrypt(content: string): Promise<string> {
if (!this.key) throw new Error('Key not generated');
const iv = crypto.getRandomValues(new Uint8Array(12));
const encoded = new TextEncoder().encode(content);
const encrypted = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv },
this.key,
encoded
);
return btoa(JSON.stringify({
iv: Array.from(iv),
data: Array.from(new Uint8Array(encrypted))
}));
}
async decrypt(encryptedData: string, keyString: string): Promise<string> {
const keyData = Uint8Array.from(atob(keyString), c => c.charCodeAt(0));
const key = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'AES-GCM' },
false,
['decrypt']
);
const { iv, data } = JSON.parse(atob(encryptedData));
const decrypted = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: new Uint8Array(iv) },
key,
new Uint8Array(data)
);
return new TextDecoder().decode(decrypted);
}
}
2. Privacy-First Design
- No plaintext storage: Server chỉ nhận encrypted data
- URL-based keys: Encryption key nằm trong URL fragment (#)
- No server logs: Không log content hoặc keys
- Automatic cleanup: TTL-based deletion
- Burn after read: One-time access pastes
3. Data Retention Policies
const EXPIRATION_OPTIONS = {
'10m': 10 * 60, // 10 minutes
'1h': 60 * 60, // 1 hour
'1d': 24 * 60 * 60, // 1 day
'1w': 7 * 24 * 60 * 60, // 1 week
} as const;
// Automatic cleanup với KV TTL
const setExpiration = (duration: keyof typeof EXPIRATION_OPTIONS) => {
return EXPIRATION_OPTIONS[duration];
};
💰 Cost Analysis
Với Cloudflare’s free tier, project này hoàn toàn miễn phí cho moderate usage:
- Workers: 100,000 requests/day
- KV: 100,000 reads, 1,000 writes/day
- Pages: Unlimited static hosting
- Bandwidth: Unlimited
Chỉ pay khi exceed limits, rất cost-effective cho personal projects.
🎯 Current Features & Future Roadmap
✅ Completed Features
- End-to-End Encryption: AES-256-GCM client-side encryption
- Modern UI: React 18 + TypeScript + Tailwind CSS
- Dark/Light Theme: Automatic system preference detection
- Responsive Design: Mobile-first approach
- Burn After Read: One-time access functionality
- Auto-Expiring: Configurable TTL (10m to 1w)
- Syntax Highlighting: 200+ languages với Prism.js
- Fast & Scalable: Cloudflare Workers edge computing
🔮 Future Enhancements
Security & Privacy
- Password protection: Additional layer của authentication
- Anonymous uploads: Không cần browser fingerprinting
- Zero-knowledge recovery: Backup/restore encrypted keys
Developer Experience
- API endpoints: Programmatic paste creation
- CLI tool: Command-line interface
- Browser extension: Quick paste từ any webpage
- Webhook support: Integration với external services
Advanced Features
- File uploads: Binary file support với encryption
- Collaborative editing: Real-time multi-user editing
- Version history: Track paste changes over time
- Custom domains: White-label deployments
🚀 Try It Out!
Project hiện đang được host và có thể access tại domain của các bạn sau khi deploy.
Source code hoàn chỉnh tại: GitHub - musicsms/crypto-paste
🎓 Key Takeaways
1. Modern React Development
- TypeScript benefits: Type safety giúp catch bugs sớm
- Vite performance: Lightning-fast development server
- Component composition: Reusable UI components
- Hook patterns: Custom hooks cho logic sharing
2. Serverless Architecture
- Zero cold starts: Cloudflare Workers performance
- Global distribution: Edge computing benefits
- Cost efficiency: Pay-per-request model
- Scalability: Auto-scaling without configuration
3. Security-First Design
- Client-side encryption: Zero-knowledge architecture
- Privacy by design: Minimal data collection
- Burn after read: Ephemeral content sharing
- URL-based keys: No server-side key storage
4. Developer Experience
- Type safety: TypeScript + Hono cho API consistency
- Modern tooling: Vite, ESLint, Prettier integration
- Git integration: Automatic deployments với Cloudflare Pages
- Documentation: Clear setup instructions và examples
🔗 Resources & Documentation
Framework & Tools
- React 18 Documentation - Modern React patterns
- TypeScript Handbook - Type safety best practices
- Vite Guide - Next-gen frontend tooling
- Tailwind CSS - Utility-first CSS framework
Cloudflare Platform
- Cloudflare Workers - Serverless compute platform
- Cloudflare Pages - Static site hosting
- KV Storage - Global key-value store
- Hono Framework - Fast web framework cho Workers
Security & Crypto
- Web Crypto API - Browser cryptography
- AES-GCM Encryption - Authenticated encryption
Kết luận: Crypto Paste showcase modern approach để build secure, privacy-focused web applications với serverless architecture. Việc kết hợp React + TypeScript + Cloudflare Workers tạo ra một stack rất powerful cho nhiều loại projects.
Project này demonstrate được rằng bạn có thể build production-ready applications với zero server management, strong security, và excellent performance - tất cả với chi phí rất thấp hoặc miễn phí.
Nếu các bạn quan tâm đến privacy-first applications hoặc serverless development, đây là một great starting point! 🚀
Bình luận
Đang tải bình luận...