Self-Hosting 9Remote
Deploy your own private 9Remote signaling and web infrastructure on Cloudflare Workers and D1.
Why Self-Host?
By default, 9Remote provides free hosted signaling at https://9remote.theaux.dev. While all data is encrypted and traffic flows peer-to-peer over WebRTC, self-hosting gives you:
- 100% Data Sovereignty: Device approval records, session tokens, and connection metadata live exclusively in your own Cloudflare D1 database.
- Custom Branding & Domains: Host the web app on your own company domain (e.g.
remote.yourcompany.com). - Zero Third-Party Dependency: Completely independent of our hosted servers.
Architecture Overview
The self-hosted backend runs entirely on Cloudflare's serverless edge:
- Next.js Web App: Packaged via OpenNext and deployed to Cloudflare Workers with static asset binding.
- Signaling Broker: Cloudflare Durable Objects for WebRTC session coordination.
- Database: Cloudflare D1 (serverless SQLite) storing user sessions and approved device records.
Prerequisites
- A Cloudflare Account (Free tier is sufficient)
- Node.js 20+ and
npm - Wrangler CLI:
npm install -g wranglerauthenticated viawrangler login
Deployment Steps
Step 1: Clone the Repository
git clone https://github.com/yourusername/9remote.git
cd 9remote
npm install
Step 2: Create Cloudflare D1 Database
Create the database for device management and sessions:
npx wrangler d1 create nineremote-db
Copy the generated database_id and paste it into web/wrangler.toml under [[d1_databases]]:
[[d1_databases]]
binding = "DB"
database_name = "nineremote-db"
database_id = "YOUR_GENERATED_DATABASE_ID"
Step 3: Run Database Migrations
Apply the base schema and every numbered migration in order:
npx wrangler d1 migrations apply nineremote-db --remote
web/migrations/000_base_schema.sql creates the sessions / temp_keys tables the
numbered migrations ALTER; without it a fresh database fails at 001.
Step 4: Configure Secrets
Create web/.dev.vars with your secret keys:
ADMIN_JWT_SECRET="your-random-32-byte-secret"
TOKEN_SECRET="your-random-32-byte-secret"
TURN_KEY_SECRET="your-turn-secret"
Sync these secrets to your Cloudflare production environment:
npm run secrets:sync -- --env=production
Step 5: Deploy the Web Backend
Deploy the full-stack web application to Cloudflare Workers:
npm run web:deploy
Once deployment finishes, Wrangler will output your live URL (e.g., https://9remote-web.yoursubdomain.workers.dev or your custom domain).
Connecting the Host CLI to Your Backend
On your host computer (where you run terminal/desktop access), configure the 9Remote CLI to communicate with your custom backend:
Option 1: Environment Variable
export NINEREMOTE_WORKER_URL="https://remote.yourcompany.com"
9remote start
Option 2: Global Configuration
Edit ~/.9remote/config.json (or %USERPROFILE%\.9remote\config.json on Windows):
{
"workerUrl": "https://remote.yourcompany.com"
}
Now, when you run 9remote start, it will register its Cloudflare tunnel and broker WebRTC connections entirely through your own private infrastructure.
Next Steps
- Explore Architecture & Transport
- Return to Getting Started