Skip to main content
This guide walks you through setting up a local Vibe Kanban Cloud instance for development and testing.

Prerequisites

Before you begin, ensure you have:
  • Docker and Docker Compose installed
  • Git to clone the repository
  • Node.js 20+ and pnpm (for running the desktop client)
  • A GitHub or Google OAuth application

Step 1: Clone the Repository

git clone https://github.com/BloopAI/vibe-kanban.git
cd vibe-kanban

Step 2: Create OAuth Application

You need at least one OAuth provider. Choose GitHub, Google, or both.
  1. Go to GitHub Developer Settings
  2. Click New OAuth App
  3. Fill in the details:
    • Application name: Vibe Kanban Local
    • Homepage URL: http://localhost:3000
    • Authorization callback URL: http://localhost:3000/v1/oauth/github/callback
  4. Click Register application
  5. Copy the Client ID
  6. Click Generate a new client secret and copy it

Step 3: Configure Environment

Create a .env.remote file in crates/remote/:
# Generate a secure JWT secret
openssl rand -base64 48
Copy the output and create your .env.remote:
.env.remote
# Required - JWT secret for authentication
VIBEKANBAN_REMOTE_JWT_SECRET=<paste_your_generated_secret_here>

# Optional - Password for ElectricSQL database role (electric_sync user)
ELECTRIC_ROLE_PASSWORD=

# OAuth — configure at least one provider. Leave the other empty or remove it.
GITHUB_OAUTH_CLIENT_ID=your_github_client_id
GITHUB_OAUTH_CLIENT_SECRET=your_github_client_secret

# Google OAuth (leave empty if not using Google login)
GOOGLE_OAUTH_CLIENT_ID=
GOOGLE_OAUTH_CLIENT_SECRET=

# Relay (required for relay/tunnel features)
# For plain HTTP local dev:
VITE_RELAY_API_BASE_URL=http://localhost:8082

# Email invitations (optional — leave empty to disable)
LOOPS_EMAIL_API_KEY=

# Loops transactional email template IDs (optional — defaults are the upstream templates).
# Override these with your own Loops account template IDs if using a custom Loops account.
LOOPS_INVITE_TEMPLATE_ID=cmhvy2wgs3s13z70i1pxakij9
LOOPS_REVIEW_READY_TEMPLATE_ID=cmj47k5ge16990iylued9by17
LOOPS_REVIEW_FAILED_TEMPLATE_ID=cmj49ougk1c8s0iznavijdqpo
For production or self-hosting on a server, add PUBLIC_BASE_URL (your public URL, e.g. https://kanban.example.com) and REMOTE_SERVER_PORTS=0.0.0.0:3000:8081 so the server is reachable from other hosts. Defaults keep local dev unchanged.
Never commit .env.remote to version control. It’s already in .gitignore.

Step 4: Start the Stack

From the crates/remote directory, start all services:
cd crates/remote
docker compose --env-file .env.remote -f docker-compose.yml up --build
Or from the repo root:
pnpm run remote:dev
This starts:
  • PostgreSQL on port 5433 (external) / 5432 (internal)
  • ElectricSQL on port 3000 (internal only, used by Remote Server for real-time sync)
  • Remote Server on port 3000 (external) / 8081 (internal)
  • Relay Server on port 8082 (external and internal)
The remote server binds to 127.0.0.1:3000 only - it’s not accessible from other machines. For production, use a reverse proxy.
Wait until you see health checks passing:
remote-server-1  | INFO remote: Server listening on 0.0.0.0:8081

Step 5: Access the Web Interface

Open http://localhost:3000 in your browser. You should see the Vibe Kanban Cloud login page. Sign in with your configured OAuth provider (GitHub or Google).

Step 6: Connect the Desktop Client (Optional)

To use the desktop client with your local server:
# In a new terminal, from the repository root
export VK_SHARED_API_BASE=http://localhost:3000

pnpm install
pnpm run dev
The desktop client will now connect to your local Cloud instance instead of the hosted version. To test relay/tunnel mode end-to-end, add:
export VK_SHARED_API_BASE=https://localhost:3001
export VK_SHARED_RELAY_API_BASE=https://relay.localhost:3001
export VK_TUNNEL=1
This mode requires local HTTPS + Caddy routing (next step).

Step 7: Optional Local HTTPS + Caddy (required for tunnel-mode testing)

Use the checked-in Caddyfile.example in the repository root. It routes:
  • localhost:3001 -> remote server (127.0.0.1:3000)
  • relay.localhost:3001 and *.relay.localhost:3001 -> relay server (127.0.0.1:8082)
caddy run --config Caddyfile.example
If you use this HTTPS setup, update OAuth callback URLs to:
  • GitHub: https://localhost:3001/v1/oauth/github/callback
  • Google: https://localhost:3001/v1/oauth/google/callback

Stopping the Stack

To stop all services:
docker compose down
To stop and remove all data (fresh start):
docker compose down -v

Troubleshooting

Ensure the database is healthy before the server starts:
# Check database status
docker compose ps

# View database logs
docker compose logs remote-db
Verify your OAuth callback URLs match exactly for your setup:
  • HTTP local stack:
    • GitHub: http://localhost:3000/v1/oauth/github/callback
    • Google: http://localhost:3000/v1/oauth/google/callback
  • HTTPS + Caddy:
    • GitHub: https://localhost:3001/v1/oauth/github/callback
    • Google: https://localhost:3001/v1/oauth/google/callback
ElectricSQL requires the electric_sync database user, which is created automatically by the Remote Server on first startup. If ElectricSQL fails to connect:
  1. Ensure the Remote Server has started successfully and run its migrations
  2. Check that ELECTRIC_ROLE_PASSWORD is set in your .env.remote
  3. Restart the stack — ElectricSQL will retry the connection
docker compose --env-file .env.remote -f docker-compose.yml restart electric
If port 3000 is in use, you can change it in docker-compose.yml:
ports:
  - "127.0.0.1:3001:8081"  # Change 3001 to your preferred port
Update your OAuth callback URLs accordingly.
Problem: curl -sk https://relay.localhost:3001/health returns HTML, and relay/tunnel fails.Cause: Caddy routed relay hostnames to the remote app (:3000) instead of relay server (:8082).Solution:
  1. Use host-specific routing for relay.localhost and *.relay.localhost
  2. Verify:
    • curl -sk https://relay.localhost:3001/health returns {"status":"ok"}
    • curl -sk https://localhost:3001/v1/health returns remote server health JSON

Next Steps

Once you have local development working, you can:
  • Deploy to Fly.io for production (coming soon)
  • Deploy with Docker Compose on your own server (coming soon)