# clawhost
**Repository Path**: toolan/clawhost
## Basic Information
- **Project Name**: clawhost
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: Production
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-04-16
- **Last Updated**: 2026-04-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
Deploy OpenClaw on your own VPS with one click.
Full privacy, dedicated resources, no shared infrastructure.
Website ·
Blog ·
Self-Host Guide
---
## What is ClawHost?
ClawHost is an open-source, self-hostable cloud hosting platform that lets anyone deploy [OpenClaw](https://openclaw.dev) on a dedicated VPS in under a minute. It handles server provisioning, DNS, SSL, firewall configuration, and OpenClaw installation automatically — so you can focus on using AI, not managing infrastructure.
### Key Highlights
- **One-Click Deploy** — Pick a plan, pay, and OpenClaw is live within minutes
- **Hetzner Cloud** — Reliable, high-performance VPS provisioning powered by Hetzner
- **Dedicated VPS** — Real servers with full root access, not shared containers
- **Browser Terminal** — Full SSH terminal access directly from the dashboard via WebSocket
- **Diagnostics & Logs** — Monitor server health, view logs, and repair instances
- **File Management** — Edit configuration files remotely
- **Version Management** — View installed OpenClaw version, browse available versions, and upgrade
- **Automatic SSL** — HTTPS via Let's Encrypt, configured automatically
- **DNS Management** — Automatic subdomain creation via Cloudflare
- **SSH Key Management** — Store and assign keys for passwordless access
- **Persistent Storage** — Attach additional volumes to any instance
- **Multi-Auth** — Sign in with OTP email, Google, or GitHub
- **Billing Built-In** — Polar.sh integration for subscriptions, invoicing, and billing portal
- **Export & Backup** — Export claw configurations for backup and migration
- **Cross-Platform** — Web, mobile (iOS/Android), and desktop (macOS/Linux) apps
- **Fully Open Source** — MIT licensed, self-host the entire platform yourself
## Architecture
ClawHost is a TypeScript monorepo built with [Turborepo](https://turbo.build) and managed with [pnpm](https://pnpm.io).
```
clawhost/
├── apps/
│ ├── api/ # Hono.js backend API
│ ├── web/ # React + Vite frontend
│ ├── mobile/ # React Native + Expo mobile app
│ └── clawhostgo/ # Electron desktop app
├── packages/
│ ├── shared/ # @openclaw/shared — HTTP client utility
│ └── i18n/ # @openclaw/i18n — Internationalization
├── scripts/
│ ├── cloud-init.yaml # Server initialization template
│ └── configure-polar-portal.ts # Polar portal configuration
├── turbo.json # Turborepo build orchestration
└── pnpm-workspace.yaml # Workspace definition
```
### Tech Stack
| Layer | Technology |
| ----------------------- | --------------------------------------------------------------------------------------------------------------- |
| **API Framework** | [Hono](https://hono.dev) on Node.js |
| **Database** | PostgreSQL ([Neon](https://neon.tech)) with [Drizzle ORM](https://orm.drizzle.team) |
| **Authentication** | [Firebase](https://firebase.google.com) (OTP email, Google, GitHub) |
| **Server Provisioning** | [Hetzner Cloud](https://docs.hetzner.cloud) |
| **Remote Management** | SSH2 for remote command execution, file management, and diagnostics |
| **Browser Terminal** | [xterm.js](https://xtermjs.org) with WebSocket proxy over SSH2 |
| **DNS** | [Cloudflare API](https://developers.cloudflare.com/api) |
| **Billing** | [Polar.sh](https://polar.sh) |
| **Email** | [Resend](https://resend.com) with React Email |
| **Frontend** | [React 18](https://react.dev) + [Vite](https://vitejs.dev) |
| **UI Components** | [shadcn/ui](https://ui.shadcn.com) + [Radix UI](https://radix-ui.com) + [Tailwind CSS](https://tailwindcss.com) |
| **Visual Canvas** | [React Flow](https://reactflow.dev) with [Dagre](https://github.com/dagrejs/dagre) layout |
| **Code Editor** | [CodeMirror](https://codemirror.net) via @uiw/react-codemirror |
| **State Management** | [Zustand](https://zustand-demo.pmnd.rs) |
| **Data Fetching** | [TanStack React Query](https://tanstack.com/query) |
| **Icons** | [Phosphor Icons](https://phosphoricons.com) |
| **Animations** | [Framer Motion](https://www.framer.com/motion) |
| **Blog** | MDX with frontmatter |
| **Mobile** | [React Native](https://reactnative.dev) + [Expo](https://expo.dev) |
| **Desktop** | [Electron](https://www.electronjs.org) with Electron Forge |
| **Monorepo** | [Turborepo](https://turbo.build) + [pnpm](https://pnpm.io) |
### Database Schema
| Table | Purpose |
| -------------- | --------------------------------------------------------------------- |
| `users` | Firebase-authenticated users with Polar customer IDs and auth methods |
| `claws` | Cloud server instances (status, IP, subdomain, etc) |
| `pendingClaws` | Temporary storage for in-progress checkout sessions |
| `sshKeys` | SSH public keys with Hetzner key IDs |
| `volumes` | Persistent storage volumes attached to claws |
| `otpCodes` | OTP authentication codes with expiration and attempt tracking |
| `rateLimits` | Rate limiting for authentication endpoints |
## Self-Hosting
### Prerequisites
- **Node.js** 20+
- **pnpm** 9.14+
- **PostgreSQL** database (Neon, Supabase, or self-hosted)
### External Services
| Service | Purpose | What You Need |
| ----------------------------------------------- | ----------------------- | ------------------------------------- |
| [Hetzner Cloud](https://console.hetzner.cloud) | Server provisioning | API Token (Read & Write) |
| [Firebase](https://console.firebase.google.com) | Authentication | Project credentials + Service account |
| [Cloudflare](https://dash.cloudflare.com) | DNS management | API Token + Zone ID |
| [Polar.sh](https://polar.sh) | Billing & subscriptions | API credentials + Webhook secret |
| [Resend](https://resend.com) | Transactional email | API Key |
A Hetzner Cloud API token is required for server provisioning.
### 1. Clone & Install
```bash
git clone https://github.com/bfzli/clawhost.git
cd clawhost
pnpm install
```
### 2. Configure Environment Variables
**API** — create `apps/api/.env`:
```bash
# Database
DATABASE_URL=postgresql://user:password@host:5432/database?sslmode=require
# Firebase Admin SDK
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=firebase-adminsdk-xxxxx@your-project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
# Hetzner Cloud
HETZNER_API_TOKEN=your-hetzner-api-token
# Cloudflare DNS
CLOUDFLARE_API_TOKEN=your-cloudflare-api-token
CLOUDFLARE_ZONE_ID=your-zone-id
# Polar (payments)
POLAR_ACCESS_TOKEN=your-polar-access-token
POLAR_ORGANIZATION_ID=your-polar-org-id
POLAR_WEBHOOK_SECRET=your-polar-webhook-secret
# Resend (email)
RESEND_API_KEY=your-resend-api-key
FROM_EMAIL=OpenClaw
# Server
PORT=2222
WS_PORT=2223
CLIENT=localhost:1111
```
**Web** — create `apps/web/.env`:
```bash
# API
VITE_API_URL=/api
VITE_API_PORT=2222
VITE_WS_PORT=2223
VITE_PORT=1111
# Firebase Client SDK
VITE_FIREBASE_API_KEY=AIza...
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-project-id
VITE_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=123456789
VITE_FIREBASE_APP_ID=1:123456789:web:abc123
```
### 3. Set Up External Services
Hetzner Cloud
1. Go to [Hetzner Cloud Console](https://console.hetzner.cloud)
2. Create a new project or select an existing one
3. Navigate to **Security** > **API Tokens**
4. Generate a token with **Read & Write** permissions
5. Copy to `HETZNER_API_TOKEN`
Firebase
1. Go to [Firebase Console](https://console.firebase.google.com)
2. Create a new project
3. Enable **Authentication** > **Sign-in method** > **Email/Password** (required for OTP login)
4. Add your domain to **Authorized domains**
5. For the web app: **Project Settings** > **General** > **Your apps** > Add a web app and copy config
6. For the API: **Project Settings** > **Service accounts** > Generate a new private key
**Google Sign-In:**
1. In **Authentication** > **Sign-in method**, enable **Google**
2. Set a project support email
**GitHub Sign-In:**
1. Create an OAuth App on [GitHub Developer Settings](https://github.com/settings/developers)
2. Set the **Authorization callback URL** to your Firebase callback URL (found in Firebase Console under the GitHub provider setup)
3. In **Authentication** > **Sign-in method**, enable **GitHub** and paste the Client ID and Client Secret from your GitHub OAuth App
All three sign-in methods (OTP, Google, GitHub) are always displayed in the UI, so all three must be configured in Firebase for a working setup. Users can also link/unlink Google and GitHub accounts from their Account settings page.
Cloudflare
1. Go to [Cloudflare Dashboard](https://dash.cloudflare.com)
2. Add your domain or select an existing one
3. Copy the **Zone ID** from the domain overview page
4. Create an API token with **Zone:DNS:Edit** permission
5. Copy Zone ID and API Token to your `.env`
Polar.sh
1. Go to [Polar.sh](https://polar.sh)
2. Create an organization and set up your products/subscriptions
3. Generate an access token and copy to `POLAR_ACCESS_TOKEN`
4. Copy your organization ID to `POLAR_ORGANIZATION_ID`
5. Configure webhook to point to your API's `/api/webhooks/polar` endpoint
6. Copy the webhook secret to `POLAR_WEBHOOK_SECRET`
### 4. Initialize Database
```bash
pnpm --filter api db:migrate
```
### 5. Start Development
```bash
pnpm dev
```
This starts both apps:
| App | URL |
| --------- | --------------------- |
| Web | http://localhost:1111 |
| API | http://localhost:2222 |
| WebSocket | ws://localhost:2223 |
The web dev server proxies `/api` requests to the API and `/ws` requests to the WebSocket server automatically.
## Scripts
### Root Commands
| Command | Description |
| ------------------- | ----------------------------------------------- |
| `pnpm dev` | Start all apps in development mode |
| `pnpm dev:web` | Start web app only |
| `pnpm dev:api` | Start API only |
| `pnpm dev:mobile` | Start mobile app (Expo) |
| `pnpm dev:desktop` | Start desktop app (Electron) |
| `pnpm build` | Build all apps for production |
| `pnpm lint` | Run ESLint across the monorepo |
| `pnpm lint:fix` | Auto-fix ESLint issues |
| `pnpm format` | Format all files with Prettier |
| `pnpm format:check` | Check formatting without writing |
| `pnpm check` | Run TypeScript type-check + ESLint for all apps |
### Database Commands
| Command | Description |
| ------------------------------- | --------------------------------------------- |
| `pnpm --filter api db:generate` | Generate a new migration after schema changes |
| `pnpm --filter api db:migrate` | Apply pending migrations |
| `pnpm --filter api db:studio` | Open Drizzle Studio (database GUI) |
### Email Development
```bash
pnpm --filter api email:dev # Preview email templates at localhost:3333
```
## API Reference
### Public Endpoints
| Method | Endpoint | Description |
| ------ | --------------------------- | --------------------------------- |
| `POST` | `/api/auth/send-otp` | Send OTP code via email |
| `POST` | `/api/auth/verify-otp` | Verify OTP and get Firebase token |
| `GET` | `/api/plans` | List available server plans |
| `GET` | `/api/plans/locations` | List available regions |
| `GET` | `/api/plans/volume-pricing` | Get volume pricing |
| `GET` | `/api/plans/availability` | Check plan availability |
### Protected Endpoints (Bearer token required)
**Claws (Server Instances)**
| Method | Endpoint | Description |
| -------- | --------------------------------- | ------------------------------ |
| `GET` | `/api/agents` | List user's claws |
| `GET` | `/api/agents/:id` | Get a specific claw |
| `POST` | `/api/agents` | Create a claw (direct) |
| `POST` | `/api/agents/purchase` | Initiate paid claw purchase |
| `DELETE` | `/api/agents/pending/:id` | Cancel a pending claw |
| `POST` | `/api/agents/:id/sync` | Sync claw with cloud provider |
| `POST` | `/api/agents/:id/start` | Start a claw |
| `POST` | `/api/agents/:id/stop` | Stop a claw |
| `POST` | `/api/agents/:id/restart` | Restart a claw |
| `PATCH` | `/api/agents/:id` | Rename a claw |
| `POST` | `/api/agents/:id/cancel-deletion` | Cancel scheduled deletion |
| `DELETE` | `/api/agents/:id` | Delete a claw |
| `GET` | `/api/agents/:id/export` | Export claw configuration |
| `POST` | `/api/agents/:id/credentials` | Get claw credentials |
| `POST` | `/api/agents/:id/version` | Get installed OpenClaw version |
| `POST` | `/api/agents/:id/versions` | List available versions |
**Claw Diagnostics**
| Method | Endpoint | Description |
| ------ | ------------------------------------ | ---------------------- |
| `POST` | `/api/agents/:id/diagnostics/status` | Get server diagnostics |
| `POST` | `/api/agents/:id/diagnostics/logs` | Get server logs |
**Claw Files**
| Method | Endpoint | Description |
| ------ | ---------------------------- | ---------------------- |
| `POST` | `/api/agents/:id/files` | List files on instance |
| `POST` | `/api/agents/:id/files/read` | Read a file |
| `PUT` | `/api/agents/:id/files` | Update a file |
**Admin Endpoints**
| Method | Endpoint | Description |
| ------ | ------------------------------------ | ------------------------------------- |
| `GET` | `/api/agents/admin` | List all claws (admin only) |
| `POST` | `/api/agents/:id/hard-delete` | Permanently delete (admin only) |
| `POST` | `/api/agents/:id/diagnostics/repair` | Repair instance (admin only) |
| `POST` | `/api/agents/:id/reinstall` | Reinstall OS (admin only) |
| `POST` | `/api/agents/:id/install-version` | Install specific version (admin only) |
**SSH Keys**
| Method | Endpoint | Description |
| -------- | ------------------- | ----------------- |
| `GET` | `/api/ssh-keys` | List SSH keys |
| `POST` | `/api/ssh-keys` | Add an SSH key |
| `DELETE` | `/api/ssh-keys/:id` | Delete an SSH key |
**Users**
| Method | Endpoint | Description |
| -------- | ---------------------------------------- | ----------------------------------- |
| `GET` | `/api/users/me` | Get current user profile |
| `PUT` | `/api/users/me` | Update profile |
| `GET` | `/api/users/me/stats` | Get user stats |
| `GET` | `/api/users/me/billing` | Get billing history |
| `GET` | `/api/users/me/billing/:orderId/invoice` | Get invoice for an order |
| `POST` | `/api/users/me/billing/portal` | Open Polar billing portal |
| `POST` | `/api/users/me/auth/:method` | Connect auth method (Google/GitHub) |
| `DELETE` | `/api/users/me/auth/:method` | Disconnect auth method |
**WebSocket**
| Protocol | Endpoint | Description |
| ----------- | -------------------------------- | ------------------------- |
| `WebSocket` | `/ws/agents/:id/terminal?token=` | Live SSH terminal session |
### Webhooks
| Method | Endpoint | Description |
| ------ | --------------------- | --------------------- |
| `POST` | `/api/webhooks/polar` | Polar payment webhook |
## Deployment
### Web App
The web app builds to `apps/web/dist/` as a static SPA with pre-rendered pages and a generated sitemap. Deploy to any static hosting provider:
- **Cloudflare Pages** (includes `_redirects` and `functions/` for SPA rewrites)
- Netlify
- Nginx / Apache
```bash
pnpm build
```
### API
The API runs as a Hono.js application on Node.js with a separate WebSocket server for terminal access:
```bash
cd apps/api
pnpm build
pnpm start # HTTP on PORT (default 2222), WebSocket on WS_PORT (default 2223)
```
## How It Works
When a user deploys a new claw, the platform:
1. **Creates a checkout** — Initiates a Polar.sh subscription for the selected plan
2. **Provisions a server** — Spins up a VPS on Hetzner Cloud
3. **Runs cloud-init** — Automatically installs Node.js, OpenClaw, Nginx, SSL, and firewall
4. **Configures DNS** — Creates a Cloudflare subdomain pointing to the server IP
5. **Delivers access** — User gets a subdomain URL, root password, and SSH access
The `scripts/cloud-init.yaml` template configures every new instance with:
- Node.js 22 runtime
- OpenClaw (installed globally via npm)
- Nginx reverse proxy with WebSocket support
- Let's Encrypt SSL certificates
- UFW firewall (ports 22, 80, 443)
- systemd service for automatic OpenClaw startup
Once provisioned, users can manage their claws through the dashboard — configuring files remotely via SSH. A browser-based terminal provides direct shell access via WebSocket.
## Customization
### Subdomain Pattern
Instances get subdomains like `abc1234.yourdomain.com`. To use your own domain, update the Cloudflare zone configuration and the cloud-init template.
### Pricing Markup
The default pricing markup on cloud provider base prices is configurable in the plans controller.
### Cloud-Init
Modify `scripts/cloud-init.yaml` to customize what gets installed on new instances — add packages, change Node.js version, or configure additional services.
### Internationalization
All UI text is managed through `@openclaw/i18n`. Translation strings live in `packages/i18n/src/langs/en.ts`, organized by category (`common`, `nav`, `auth`, `dashboard`, `landing`, etc.).
## Troubleshooting
SSL certificates not working
Instances may take 1-2 minutes for SSL certificates to provision after the server boots. The cloud-init script includes retry logic for certificate generation. Ensure ports 80 and 443 are open.
DNS not resolving
New subdomains may take 1-5 minutes to propagate through Cloudflare. Check that your Cloudflare API token has Zone:DNS:Edit permission and the Zone ID is correct.
Firebase auth not working
1. Verify your domain is listed in Firebase **Authorized domains**
2. Confirm Email/Password sign-in is enabled under **Authentication** > **Sign-in method**
3. If using Google/GitHub auth, ensure those providers are configured
4. Double-check that all `VITE_FIREBASE_*` values match your Firebase project
Database connection errors
1. Verify `DATABASE_URL` is correct and includes `?sslmode=require` for hosted databases
2. Run `pnpm --filter api db:migrate` to apply any pending migrations
3. Use `pnpm --filter api db:studio` to inspect the database directly
## Contributing
Contributions are welcome! Please open an issue first to discuss what you'd like to change.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/my-feature`)
3. Make your changes following the project's code conventions
4. Run `pnpm check` to verify TypeScript and linting pass
5. Run `pnpm format` to ensure formatting is correct
6. Commit and push your changes
7. Open a pull request
## License
MIT License — see [LICENSE](LICENSE) for details.