Self-Hosting
Deploy your own MyClaude marketplace instance with Firebase, Stripe Connect, Cloudflare R2, and Vercel or a standalone Node.js server.
Deploy your own MyClaude marketplace instance. This guide covers every service dependency, environment variable, and verification step.
Architecture overview
Browser --> Next.js 16 (Vercel / Node.js)
| | |
v v v
Firebase Stripe Cloudflare R2
(Auth + Connect (product files)
Firestore + (payments)
Storage)| Service | Role |
|---|---|
| Firebase Auth | User authentication (email/password, Google OAuth) |
| Cloud Firestore | Primary database (products, users, orders, reviews) |
| Firebase Storage | Avatar and thumbnail uploads |
| Stripe Connect Express | Payment processing, seller payouts, 8% platform fee |
| Cloudflare R2 | Product file storage (Skills, Agents, etc.) with presigned URLs |
| Vercel (recommended) or Node.js host | Application server |
Prerequisites
Before you begin, create accounts and projects for:
- Firebase -- Create a project at console.firebase.google.com
- Stripe -- Create an account at dashboard.stripe.com with Connect enabled
- Cloudflare -- Create an R2 bucket at dash.cloudflare.com
- Vercel (recommended) or a server running Node.js 20+
Environment variables
Your deployment requires 17 environment variables. Never commit actual values to version control.
Firebase Client (exposed to browser)
| Variable | Description |
|---|---|
NEXT_PUBLIC_FIREBASE_API_KEY | Firebase Web API key from project settings |
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN | {project-id}.firebaseapp.com |
NEXT_PUBLIC_FIREBASE_PROJECT_ID | Firebase project ID |
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET | {project-id}.firebasestorage.app |
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID | Sender ID from project settings |
NEXT_PUBLIC_FIREBASE_APP_ID | App ID from project settings |
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID | Google Analytics measurement ID (optional) |
Firebase Admin (server-only)
| Variable | Description |
|---|---|
FIREBASE_SERVICE_ACCOUNT_KEY | Full JSON string of the service account key downloaded from Firebase Console > Project Settings > Service Accounts. Must be a single-line JSON string. |
Stripe
| Variable | Description |
|---|---|
STRIPE_SECRET_KEY | Stripe secret key. Use sk_test_* for testing, sk_live_* for production. |
STRIPE_WEBHOOK_SECRET | Webhook signing secret from Stripe Dashboard > Webhooks |
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | Stripe publishable key (exposed to browser) |
Cloudflare R2
| Variable | Description |
|---|---|
CLOUDFLARE_ACCOUNT_ID | Your Cloudflare account ID (found in the dashboard URL) |
R2_ACCESS_KEY_ID | R2 API token access key |
R2_SECRET_ACCESS_KEY | R2 API token secret key |
R2_BUCKET_NAME | Name of the R2 bucket for product files |
Platform
| Variable | Description |
|---|---|
NEXT_PUBLIC_PLATFORM_FEE_PERCENT | Platform fee percentage (default: 8) |
NEXT_PUBLIC_APP_URL | Your deployment URL (e.g., https://marketplace.example.com). Used for CSRF origin validation and Stripe redirect URLs. |
Firebase setup
1. Enable authentication
In Firebase Console > Authentication > Sign-in method, enable:
- Email/Password
- Google (recommended)
2. Create Firestore database
Create a Cloud Firestore database in production mode. Deploy the security rules:
$ npx firebase deploy --only firestore:rulesThe rules file (firestore.rules) ships with the repository. It enforces:
- Authenticated reads for most collections
- Server-only writes for
orders(webhook creates these) - Owner-only writes for user profiles
3. Deploy storage rules
$ npx firebase deploy --only storageThe storage rules (storage.rules) enforce:
allow read: if falsefor product files (signed URLs bypass rules)- Authenticated uploads for avatars and thumbnails with size limits
4. Create Firestore indexes
Composite indexes are required for queries. Deploy them:
$ npx firebase deploy --only firestore:indexesStripe Connect setup
1. Enable Connect
In Stripe Dashboard > Connect > Settings:
- Account type: Express
- Platform profile: Marketplace
2. Configure webhook
Create a webhook endpoint pointing to your deployment:
https://your-domain.com/api/stripe/webhooksSubscribe to these events:
checkout.session.completed-- creates orders after paymentcharge.refunded-- processes refunds, updates statsaccount.updated-- tracks seller onboarding status
Copy the webhook signing secret to STRIPE_WEBHOOK_SECRET.
3. Platform fee
The platform fee is hardcoded at 8% on the server side (in the webhook handler). The NEXT_PUBLIC_PLATFORM_FEE_PERCENT variable controls the display value shown to users. To change the actual fee, modify the PLATFORM_FEE_PERCENT constant in src/app/api/stripe/webhooks/route.ts.
R2 storage setup
1. Create a bucket
In Cloudflare Dashboard > R2 > Create bucket. Name it (e.g., myclaude-marketplace).
2. Create API token
In R2 > Manage R2 API Tokens > Create API token:
- Permissions: Object Read & Write
- Scope: Apply to the specific bucket
Copy the Access Key ID and Secret Access Key.
3. Configure CORS (if needed)
If your deployment domain differs from the R2 endpoint, add a CORS policy to the bucket:
[
{
"AllowedOrigins": ["https://your-domain.com"],
"AllowedMethods": ["GET", "PUT"],
"AllowedHeaders": ["*"],
"MaxAgeSeconds": 3600
}
]Deploying
Option A: Vercel (recommended)
$ npm install -g vercel
$ vercel --prodAdd all 17 environment variables in Vercel Dashboard > Settings > Environment Variables. The next.config.ts and build scripts are pre-configured for Vercel.
Key Vercel settings:
- Framework Preset: Next.js
- Node.js Version: 20.x
- Build Command:
npm run build(runs prebuild script automatically) - Output Directory:
.next
Option B: Self-hosted Node.js
$ npm install
$ npm run build
$ npm startThe server starts on port 3000 by default. Use a reverse proxy (nginx, Caddy) for TLS termination. Ensure all 17 environment variables are set in the process environment.
Minimum server requirements:
- Node.js 20+
- 1 GB RAM
- Outbound HTTPS access to Firebase, Stripe, and Cloudflare APIs
Post-deploy verification
Run through this checklist after your first deployment.
| Step | How to verify | Expected result |
|---|---|---|
| Health check | GET /api/health | { "status": "ok" } |
| Auth | Register a new account | User appears in Firebase Console > Authentication |
| Product creation | Publish a free product | Product visible on /explore |
| File upload | Upload a .zip to R2 via the publish flow | File stored in your R2 bucket |
| Stripe Connect | Click "Connect Stripe" in seller settings | Redirected to Stripe onboarding |
| Checkout | Purchase a paid product (test mode) | Order created in Firestore orders collection |
| Download | Download a purchased product | Signed URL generated, file downloads |
| Webhook | Check Stripe Dashboard > Webhooks > Recent events | Events show 200 responses |
| CSRF | curl -X POST /api/products/like -H "Origin: https://evil.com" | 403 Forbidden |
Related pages
- Contributing -- Local development setup
- Security Model -- Security architecture details
- Webhooks & Integration -- Webhook events and rate limits
- API Overview -- Endpoint groups and authentication
Contributing
Set up a local MyClaude development environment, understand the codebase conventions, and submit your first pull request.
Webhooks & Integration
Reference for Stripe webhook events, payload handling, idempotency, rate limits across all 26 API routes, and integration points for CLI and MCP.