chore: change default ports to avoid common conflicts (#681)

This commit is contained in:
Carlos Florêncio
2026-04-23 18:09:53 +01:00
committed by GitHub
parent c078438621
commit 7076a40805
26 changed files with 79 additions and 69 deletions
+5 -3
View File
@@ -5,7 +5,7 @@
# docker build -t kandev:latest .
#
# Run:
# docker run -p 8080:8080 -v kandev-data:/data kandev:latest
# docker run -p 38429:38429 -v kandev-data:/data kandev:latest
# ---------------------------------------------------------------------------
# Stage 1: Go builder — compile kandev + agentctl binaries
@@ -114,8 +114,10 @@ RUN chown -R kandev:kandev /app /data
WORKDIR /app
EXPOSE 8080
# Only the backend port is exposed — it reverse-proxies the Next.js frontend
# (which listens on 37429 internally), so users hit a single port.
EXPOSE 38429
# tini as PID 1 for signal handling; entrypoint handles privilege drop
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
CMD ["kandev", "start", "--backend-port", "8080", "--web-port", "37429", "--verbose"]
CMD ["kandev", "start", "--backend-port", "38429", "--web-port", "37429", "--verbose"]
+2 -2
View File
@@ -54,7 +54,7 @@ help:
@echo ""
@echo "Development Commands:"
@echo " dev Run backend + web via CLI (auto ports)"
@echo " dev-backend Run backend in development mode (port 8080)"
@echo " dev-backend Run backend in development mode (port 38429)"
@echo " dev-web Run web app in development mode (port 37429)"
@echo " dev Note: Uses apps/cli launcher (auto ports)"
@echo ""
@@ -114,7 +114,7 @@ endif
.PHONY: dev-backend
dev-backend:
@echo "Starting backend on http://localhost:8080"
@echo "Starting backend on http://localhost:38429"
@trap 'stty sane 2>/dev/null || true' EXIT INT TERM; \
$(MAKE) -C $(BACKEND_DIR) run; \
stty sane 2>/dev/null || true
+1 -1
View File
@@ -144,7 +144,7 @@ apps/
make dev
# Or run separately
make dev-backend # Backend on :8080
make dev-backend # Backend on :38429
make dev-web # Frontend on :37429
```
+10 -5
View File
@@ -59,9 +59,14 @@ import (
"github.com/kandev/kandev/internal/db"
)
// defaultServerPort is the fallback HTTP port when neither the CLI flag nor
// the config file / env var sets one. Kept in sync with the viper default in
// internal/common/config.setDefaults.
const defaultServerPort = 38429
// Command-line flags
var (
flagPort = flag.Int("port", 0, "HTTP server port (default: 8080)")
flagPort = flag.Int("port", 0, fmt.Sprintf("HTTP server port (default: %d)", defaultServerPort))
flagLogLevel = flag.String("log-level", "", "Log level: debug, info, warn, error")
flagHelp = flag.Bool("help", false, "Show help message")
flagVersion = flag.Bool("version", false, "Show version information")
@@ -74,8 +79,8 @@ func init() {
fmt.Fprintf(os.Stderr, "Options:\n")
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\nExamples:\n")
fmt.Fprintf(os.Stderr, " kandev # Start with default settings\n")
fmt.Fprintf(os.Stderr, " kandev -port=9000 -log-level=debug # Custom port and log level\n")
fmt.Fprintf(os.Stderr, " kandev # Start with default settings\n")
fmt.Fprintf(os.Stderr, " kandev -port=18080 -log-level=debug # Custom port and log level\n")
}
}
@@ -418,7 +423,7 @@ func startGatewayAndServe(
port := cfg.Server.Port
if port == 0 {
port = 8080
port = defaultServerPort
}
go func() {
log.Info("WebSocket server listening", zap.Int("port", port))
@@ -489,7 +494,7 @@ func buildHTTPServer(
port := cfg.Server.Port
if port == 0 {
port = 8080
port = defaultServerPort
}
return &http.Server{
Addr: fmt.Sprintf(":%d", port),
+2 -2
View File
@@ -53,12 +53,12 @@ WORKDIR /workspace
# OPENAI_API_KEY - OpenAI API key for Codex
#
# agentctl configuration:
# AGENTCTL_PORT - HTTP API port (default: 9999)
# AGENTCTL_PORT - HTTP API port (default: 39429)
# AGENTCTL_AGENT_COMMAND - Command to run (e.g., "auggie --acp" or "codex app-server")
# AGENTCTL_AUTO_START - Auto-start agent on startup (default: false)
# Expose agentctl HTTP API port
EXPOSE 9999
EXPOSE 39429
# Run agentctl HTTP server
ENTRYPOINT ["/agent/entrypoint.sh"]
+1 -1
View File
@@ -16,6 +16,6 @@ if ! command -v codex &> /dev/null; then
fi
# Run agentctl HTTP server
echo "Starting agentctl on port ${AGENTCTL_PORT:-9999}..."
echo "Starting agentctl on port ${AGENTCTL_PORT:-39429}..."
exec /usr/local/bin/agentctl
@@ -17,8 +17,9 @@ import (
"go.opentelemetry.io/otel/trace"
)
// Default agentctl port
const AgentCtlPort = 9999
// Default agentctl port. Clustered near the web port (37429) to avoid
// collisions with commonly used ports (8080, 9090, 9999, etc.).
const AgentCtlPort = 39429
// AgentExecution represents a running agent execution
type AgentExecution struct {
@@ -51,7 +51,7 @@ type Launcher struct {
type Config struct {
BinaryPath string // Path to agentctl binary (auto-detected if empty)
Host string // Host to bind to (default: localhost)
Port int // Control port (default: 9999)
Port int // Control port (default: 39429)
}
// New creates a new Launcher.
@@ -60,7 +60,7 @@ func New(cfg Config, log *logger.Logger) *Launcher {
cfg.Host = "localhost"
}
if cfg.Port == 0 {
cfg.Port = 9999
cfg.Port = 39429
}
if cfg.BinaryPath == "" {
cfg.BinaryPath = findAgentctlBinary()
@@ -196,10 +196,10 @@ type InstanceConfig struct {
// Load loads the configuration from environment variables.
func Load() *Config {
cfg := &Config{
Port: getEnvInt("AGENTCTL_PORT", 9999),
Port: getEnvInt("AGENTCTL_PORT", 39429),
Ports: PortConfig{
Base: getEnvInt("AGENTCTL_INSTANCE_PORT_BASE", 10001),
Max: getEnvInt("AGENTCTL_INSTANCE_PORT_MAX", 10100),
Base: getEnvInt("AGENTCTL_INSTANCE_PORT_BASE", 41001),
Max: getEnvInt("AGENTCTL_INSTANCE_PORT_MAX", 41100),
},
Defaults: InstanceDefaults{
Protocol: agent.Protocol(getEnv("AGENTCTL_PROTOCOL", string(agent.ProtocolACP))),
@@ -177,7 +177,7 @@ type AgentConfig struct {
// StandaloneHost is the host where standalone agentctl is running (default: localhost)
StandaloneHost string `mapstructure:"standaloneHost"`
// StandalonePort is the control port for standalone agentctl (default: 9999)
// StandalonePort is the control port for standalone agentctl (default: 39429)
StandalonePort int `mapstructure:"standalonePort"`
// StandaloneAuthToken is the per-launch auth token retrieved via handshake.
@@ -189,7 +189,7 @@ type AgentConfig struct {
// This setting is only for running a separate standalone MCP server process.
McpServerEnabled bool `mapstructure:"mcpServerEnabled"`
// McpServerPort is the port for the standalone MCP server (default: 9090)
// McpServerPort is the port for the standalone MCP server (default: 40429)
McpServerPort int `mapstructure:"mcpServerPort"`
// McpServerURL is the URL of the Kandev MCP server for task management
@@ -235,7 +235,7 @@ func detectDefaultLogFormat() string {
func setDefaults(v *viper.Viper) {
// Server defaults
v.SetDefault("server.host", "0.0.0.0")
v.SetDefault("server.port", 8080)
v.SetDefault("server.port", 38429)
v.SetDefault("server.readTimeout", 30)
v.SetDefault("server.writeTimeout", 30)
v.SetDefault("server.webInternalUrl", "")
@@ -274,9 +274,9 @@ func setDefaults(v *viper.Viper) {
// Agent defaults (runtime selection is now per-task based on executor type)
v.SetDefault("agent.standaloneHost", "localhost")
v.SetDefault("agent.standalonePort", 9999)
v.SetDefault("agent.standalonePort", 39429)
v.SetDefault("agent.mcpServerEnabled", false) // MCP is now embedded in agentctl
v.SetDefault("agent.mcpServerPort", 9090)
v.SetDefault("agent.mcpServerPort", 40429)
v.SetDefault("agent.mcpServerUrl", "")
// Auth defaults
+5 -3
View File
@@ -2,10 +2,12 @@ import os from "node:os";
import path from "node:path";
// Default service ports (will auto-fallback if busy).
export const DEFAULT_BACKEND_PORT = 8080;
// Clustered near the web port (37429) to avoid collisions with commonly used
// ports (8080, 9090, 9999, etc.) while keeping the numbers memorable.
export const DEFAULT_BACKEND_PORT = 38429;
export const DEFAULT_WEB_PORT = 37429;
export const DEFAULT_AGENTCTL_PORT = 9999;
export const DEFAULT_MCP_PORT = 9090;
export const DEFAULT_AGENTCTL_PORT = 39429;
export const DEFAULT_MCP_PORT = 40429;
// Random fallback range for port selection.
export const RANDOM_PORT_MIN = 10000;
+2 -2
View File
@@ -13,9 +13,9 @@ vi.mock("./constants", () => ({
return mockCacheDir.value;
},
DATA_DIR: "/tmp/kandev-test-data",
DEFAULT_BACKEND_PORT: 8080,
DEFAULT_BACKEND_PORT: 38429,
DEFAULT_WEB_PORT: 37429,
DEFAULT_AGENTCTL_PORT: 9999,
DEFAULT_AGENTCTL_PORT: 39429,
HEALTH_TIMEOUT_MS_RELEASE: 15000,
RANDOM_PORT_MIN: 10000,
RANDOM_PORT_MAX: 60000,
@@ -390,7 +390,7 @@ function BackendConnectionCard() {
value={displayBackendUrl}
readOnly
disabled
placeholder="http://localhost:8080"
placeholder="http://localhost:38429"
className="cursor-default"
/>
<p className="text-xs text-muted-foreground">
@@ -57,7 +57,7 @@ function useTerminalRefs() {
};
}
const WS_BASE_URL_FALLBACK = "ws://localhost:8080";
const WS_BASE_URL_FALLBACK = "ws://localhost:38429";
function useWsBaseUrl() {
return useMemo(() => {
try {
+1 -1
View File
@@ -184,7 +184,7 @@ export const backendFixture = base.extend<object, { backend: BackendContext }>({
);
// Give each worker its own agentctl port range, offset from the default
// range (10001-10100) to avoid conflicts with a running dev instance.
// range (41001-41100) to avoid conflicts with a running dev instance.
const agentctlPortBase = 30001 + E2E_PORT_OFFSET * 1000 + workerInfo.workerIndex * 50;
const agentctlPortMax = agentctlPortBase + 49;
+2 -2
View File
@@ -3,7 +3,7 @@ export type AppConfig = {
};
// Server-side default (used during SSR - always localhost since SSR runs on same machine)
const DEFAULT_API_BASE_URL = "http://localhost:8080";
const DEFAULT_API_BASE_URL = "http://localhost:38429";
export const DEBUG_UI =
process.env.NEXT_PUBLIC_KANDEV_DEBUG === "true" ||
@@ -18,7 +18,7 @@ export function getBackendConfig(): AppConfig {
}
// Client-side URL resolution:
// 1. Port-based URL via __KANDEV_API_PORT (dev mode: browser on :3000, API on :8080)
// 1. Port-based URL via __KANDEV_API_PORT (dev mode: browser on :37429, API on :38429)
// 2. Same-origin (production: Go reverse-proxies Next.js on single port)
// Works for any hosting scenario: localhost, custom domain, Tailscale, etc.
if (window.__KANDEV_API_PORT) {
+1 -1
View File
@@ -181,7 +181,7 @@ export function getWsBaseUrl(): string {
const protocol = url.protocol === "https:" ? "wss:" : "ws:";
return `${protocol}//${url.host}`;
} catch {
return "ws://localhost:8080";
return "ws://localhost:38429";
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ export const STORAGE_KEYS = {
LAST_EXECUTOR_PROFILE_ID: "kandev.dialog.lastExecutorProfileId",
} as const;
export const DEFAULT_BACKEND_URL = "http://localhost:8080";
export const DEFAULT_BACKEND_URL = "http://localhost:38429";
// Kanban Preview Panel Settings
export const PREVIEW_PANEL = {
+1 -1
View File
@@ -1,6 +1,6 @@
/**
* Convert HTTP URL to WebSocket URL.
* http://localhost:8080 → ws://localhost:8080/ws
* http://localhost:38429 → ws://localhost:38429/ws
* https://api.example.com → wss://api.example.com/ws
*/
export function httpToWebSocketUrl(baseUrl: string): string {
+1 -1
View File
@@ -26,7 +26,7 @@ Kandev uses an event-driven architecture with **Agent Communication Protocol (AC
```mermaid
flowchart TB
subgraph Binary["Kandev Binary (Port 8080)"]
subgraph Binary["Kandev Binary (Port 38429)"]
Task["Task Service"]
Agent["Agent Manager"]
Orch["Orchestrator Service"]
+3 -3
View File
@@ -6,7 +6,7 @@ This document provides a complete reference for all WebSocket API actions, their
Kandev uses a **single WebSocket connection** for all API operations and real-time streaming. This eliminates the need for separate REST endpoints and enables full-duplex communication.
**Endpoint**: `ws://localhost:8080/ws`
**Endpoint**: `ws://localhost:38429/ws`
### Message Envelope
@@ -70,7 +70,7 @@ flowchart LR
### Typical Workflow
1. **Connect** to `ws://localhost:8080/ws`
1. **Connect** to `ws://localhost:38429/ws`
2. **Create Board** → `board.create`
3. **Create Column** → `column.create`
4. **Create Task** → `task.create`
@@ -2282,7 +2282,7 @@ These are push notifications from the server to subscribed clients. They have `t
## Complete Usage Example
```javascript
const ws = new WebSocket('ws://localhost:8080/ws');
const ws = new WebSocket('ws://localhost:38429/ws');
const pending = new Map();
// Handle incoming messages
+7 -7
View File
@@ -112,8 +112,8 @@ npx kandev start
| Option | Description | Example |
|--------|-------------|---------|
| `--version <tag>` | Use a specific release version | `--version v0.1.0` |
| `--backend-port <port>` | Override backend port | `--backend-port 8080` |
| `--web-port <port>` | Override web port | `--web-port 37429` |
| `--backend-port <port>` | Override backend port | `--backend-port 18080` |
| `--web-port <port>` | Override web port | `--web-port 13000` |
| `--help`, `-h` | Show help | `--help` |
### Examples
@@ -126,7 +126,7 @@ npx kandev --version v0.1.0
npx kandev --backend-port 18080 --web-port 13000
# Dev mode with custom ports
npx kandev dev --backend-port 8080 --web-port 13000
npx kandev dev --backend-port 18080 --web-port 13000
```
## Port Selection
@@ -135,10 +135,10 @@ By default, the CLI automatically finds available ports:
| Service | Default Port | Fallback |
|---------|--------------|----------|
| Backend | 8080 | Auto-selects from 10000-60000 |
| Backend | 38429 | Auto-selects from 10000-60000 |
| Web | 37429 | Auto-selects from 10000-60000 |
| AgentCtl | 9999 | Auto-selects from 10000-60000 |
| MCP Server | 9090 | Auto-selects from 10000-60000 |
| AgentCtl | 39429 | Auto-selects from 10000-60000 |
| MCP Server | 40429 | Auto-selects from 10000-60000 |
If the default port is in use, the CLI finds the next available port automatically.
@@ -186,7 +186,7 @@ See `make help` for all available commands.
The CLI automatically finds available ports. If you need a specific port:
```bash
npx kandev --backend-port 8080 --web-port 37429
npx kandev --backend-port 18080 --web-port 13000
```
### Backend Takes Too Long to Start
+12 -12
View File
@@ -5,10 +5,10 @@ Run Kandev in a Docker container. For Kubernetes deployment, see [k8s.md](k8s.md
## Quick Start
```bash
docker run -p 8080:8080 -v kandev-data:/data ghcr.io/kdlbs/kandev:latest
docker run -p 38429:38429 -v kandev-data:/data ghcr.io/kdlbs/kandev:latest
```
Open `http://localhost:8080` in your browser.
Open `http://localhost:38429` in your browser.
## Using the Pre-built Image
@@ -53,7 +53,7 @@ Without a volume, data is lost when the container is removed.
Configuration is done via `KANDEV_`-prefixed environment variables:
```bash
docker run -p 8080:8080 \
docker run -p 38429:38429 \
-v kandev-data:/data \
-e KANDEV_LOG_LEVEL=debug \
ghcr.io/kdlbs/kandev:latest
@@ -77,7 +77,7 @@ docker run -p 8080:8080 \
To use PostgreSQL instead of SQLite:
```bash
docker run -p 8080:8080 \
docker run -p 38429:38429 \
-e KANDEV_DATABASE_DRIVER=postgres \
-e KANDEV_DATABASE_HOST=host.docker.internal \
-e KANDEV_DATABASE_PORT=5432 \
@@ -93,7 +93,7 @@ Kandev exposes a single port. The Go backend serves the API, WebSocket, and reve
| Port | Service |
|------|---------|
| `8080` | API + WebSocket + Web UI |
| `38429` | API + WebSocket + Web UI |
Override the port:
@@ -113,7 +113,7 @@ services:
kandev:
image: ghcr.io/kdlbs/kandev:latest
ports:
- "8080:8080"
- "38429:38429"
volumes:
- kandev-data:/data
restart: unless-stopped
@@ -133,7 +133,7 @@ services:
kandev:
image: ghcr.io/kdlbs/kandev:latest
ports:
- "8080:8080"
- "38429:38429"
volumes:
- kandev-data:/data
environment:
@@ -170,7 +170,7 @@ volumes:
## Reverse Proxy
Since Kandev serves everything on a single port, a reverse proxy only needs to forward all traffic to port 8080. No extra environment variables are needed — the frontend automatically uses `window.location.origin` to reach the API.
Since Kandev serves everything on a single port, a reverse proxy only needs to forward all traffic to port 38429. No extra environment variables are needed — the frontend automatically uses `window.location.origin` to reach the API.
### Docker Compose with Caddy
@@ -201,7 +201,7 @@ Example `Caddyfile`:
```
kandev.example.com {
reverse_proxy kandev:8080
reverse_proxy kandev:38429
}
```
@@ -210,7 +210,7 @@ kandev.example.com {
By default, `KANDEV_DOCKER_ENABLED=false` inside the container. To enable Docker-based agent execution, mount the Docker socket:
```bash
docker run -p 8080:8080 \
docker run -p 38429:38429 \
-v kandev-data:/data \
-v /var/run/docker.sock:/var/run/docker.sock \
-e KANDEV_DOCKER_ENABLED=true \
@@ -224,14 +224,14 @@ docker run -p 8080:8080 \
The backend exposes a `/health` endpoint:
```bash
curl http://localhost:8080/health
curl http://localhost:38429/health
```
For Docker health checks in compose:
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
test: ["CMD", "curl", "-f", "http://localhost:38429/health"]
interval: 30s
timeout: 5s
retries: 3
+5 -5
View File
@@ -56,7 +56,7 @@ kubectl logs -l app=kandev -f
| Resource | File | Purpose |
|----------|------|---------|
| Deployment | `deployment.yaml` | Single-replica pod running backend + web |
| Service | `service.yaml` | ClusterIP exposing port 8080 |
| Service | `service.yaml` | ClusterIP exposing port 38429 |
| ConfigMap | `configmap.yaml` | Non-sensitive environment configuration |
| PVC | `pvc.yaml` | 10Gi persistent volume for SQLite + worktrees |
| Ingress | `ingress.yaml` | Example ingress with WebSocket support |
@@ -66,11 +66,11 @@ kubectl logs -l app=kandev -f
**Port-forward** (quickest for testing):
```bash
kubectl port-forward svc/kandev 8080:8080
# Open http://localhost:8080
kubectl port-forward svc/kandev 38429:38429
# Open http://localhost:38429
```
**Ingress**: Edit `k8s/ingress.yaml` to set your domain, then apply. The ingress routes all traffic to the backend on port 8080 (the Go backend reverse-proxies the Next.js frontend internally).
**Ingress**: Edit `k8s/ingress.yaml` to set your domain, then apply. The ingress routes all traffic to the backend on port 38429 (the Go backend reverse-proxies the Next.js frontend internally).
### Custom Domain / Reverse Proxy
@@ -84,7 +84,7 @@ Kandev reads configuration via `KANDEV_`-prefixed environment variables (Viper).
| Env Var | Default | Description |
|---------|---------|-------------|
| `KANDEV_SERVER_PORT` | `8080` | Server port (API + WebSocket + Web UI) |
| `KANDEV_SERVER_PORT` | `38429` | Server port (API + WebSocket + Web UI) |
| `KANDEV_HOME_DIR` | `/data` | Kandev home directory — contains `data/` (DB), `tasks/`, `worktrees/`, `repos/`, `sessions/`, and `lsp-servers/` |
| `KANDEV_DATABASE_DRIVER` | `sqlite` | Database driver (`sqlite` or `postgres`) |
| `KANDEV_DATABASE_PATH` | `$KANDEV_HOME_DIR/data/kandev.db` | SQLite database file path (override) |
+1 -1
View File
@@ -22,7 +22,7 @@ spec:
image: kandev:latest
ports:
- name: backend
containerPort: 8080
containerPort: 38429
protocol: TCP
envFrom:
- configMapRef:
+1 -1
View File
@@ -10,6 +10,6 @@ spec:
app: kandev
ports:
- name: http
port: 8080
port: 38429
targetPort: backend
protocol: TCP