Self-Hosting
Run Golden Path on your own infrastructure - inside your company network, on a private VM, or locally for evaluation. Everything ships as public Docker images, no external services required.
Looking for the hosted version? Sign up at Golden Path Studio - no setup needed.
Quick start
The minimal setup runs three containers: PostgreSQL, the Web UI, and the MCP server. With sensible defaults, you can start exploring in under 60 seconds.
- Copy the
docker-compose.ymlfrom below into an empty folder - Run
docker compose up -d - Open
http://localhost:3000 - Sign up for an account and start using it
The Web UI runs on port 3000, the MCP server on port 8080. Container images are pulled from goldenpath.azurecr.io (anonymous pull enabled, no Azure login required).
Terminal
mkdir golden-path && cd golden-path
# Copy the docker-compose.yml shown below
docker compose up -d
docker-compose.yml
Save this as docker-compose.yml in an empty folder, then run docker compose up -d. No .env file is required for a quick local test -- defaults will fill in.
docker-compose.yml
services:
postgres:
image: postgres:17
environment:
- POSTGRES_DB=golden_path
- POSTGRES_USER=golden_path
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-golden_path_dev}
volumes:
- pgdata:/var/lib/postgresql/data
restart: unless-stopped
web:
image: goldenpath.azurecr.io/golden-path-web:latest
environment:
- AUTH_SECRET=${AUTH_SECRET:-dev-secret-do-not-use-in-production}
- AUTH_URL=${AUTH_URL:-http://localhost:3000}
- AUTH_GITHUB_ID=${AUTH_GITHUB_ID:-}
- AUTH_GITHUB_SECRET=${AUTH_GITHUB_SECRET:-}
- AUTH_GOOGLE_ID=${AUTH_GOOGLE_ID:-}
- AUTH_GOOGLE_SECRET=${AUTH_GOOGLE_SECRET:-}
- DATABASE_URL=postgresql://golden_path:${POSTGRES_PASSWORD:-golden_path_dev}@postgres:5432/golden_path
- MCP_URL=${MCP_URL:-http://localhost:8080/mcp}
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
- OTEL_EXPORTER_OTLP_HEADERS=${OTEL_EXPORTER_OTLP_HEADERS:-}
ports:
- "3000:3000"
restart: unless-stopped
depends_on:
- postgres
mcp:
image: goldenpath.azurecr.io/golden-path-mcp:latest
environment:
- DATABASE_URL=postgresql://golden_path:${POSTGRES_PASSWORD:-golden_path_dev}@postgres:5432/golden_path
- MCP_TRANSPORT=http
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
- OTEL_EXPORTER_OTLP_HEADERS=${OTEL_EXPORTER_OTLP_HEADERS:-}
ports:
- "8080:8080"
restart: unless-stopped
depends_on:
- postgres
volumes:
pgdata:
For evaluation only: the default AUTH_SECRET is a placeholder. Before running this anywhere beyond your own machine, set a real secret (see Configuration below).
What you get
Three containers, no external services:
| Container | Port | Purpose |
|---|---|---|
postgres | -- | Database (architectures, skills, users, sessions) |
web | 3000 | Studio Web UI |
mcp | 8080 | MCP server (HTTP transport) |
The MCP server exposes architecture skills as tools to Claude Code, GitHub Copilot, Cursor, etc.
Configuration
All configuration is via environment variables. Create a .env file next to your docker-compose.yml:
Required for production
- Name
AUTH_SECRET- Type
- string
- Description
JWT signing secret. Must be changed from the default before any non-local use. Generate with
openssl rand -base64 32.
- Name
POSTGRES_PASSWORD- Type
- string
- Description
Postgres password. Default is
golden_path_dev-- safe for isolated networks but change for production.
.env
AUTH_SECRET=YOUR_GENERATED_SECRET_HERE
POSTGRES_PASSWORD=YOUR_STRONG_PASSWORD_HERE
URLs (when not running on localhost)
If you deploy behind a reverse proxy or on a remote server, override these:
- Name
AUTH_URL- Type
- string
- Description
Public URL of the Web UI. Default:
http://localhost:3000. Set tohttps://gp.mycompany.internalor similar.
- Name
MCP_URL- Type
- string
- Description
Public URL of the MCP server. Default:
http://localhost:8080/mcp. This is what gets written to the downloaded.mcp.jsonconfig -- it must be reachable from the developer's machine.
Optional: OAuth providers
If AUTH_GITHUB_ID and AUTH_GITHUB_SECRET are set, GitHub login appears on the sign-in page. Same for Google. If neither is set, only email/password login is shown.
- Name
AUTH_GITHUB_ID- Type
- string
- Description
GitHub OAuth App Client ID.
- Name
AUTH_GITHUB_SECRET- Type
- string
- Description
GitHub OAuth App Client Secret.
- Name
AUTH_GOOGLE_ID- Type
- string
- Description
Google OAuth Client ID.
- Name
AUTH_GOOGLE_SECRET- Type
- string
- Description
Google OAuth Client Secret.
To register OAuth apps:
- GitHub: Settings -> Developer settings -> OAuth Apps -> New OAuth App. Authorization callback URL:
${AUTH_URL}/api/auth/callback/github - Google: Cloud Console -> APIs & Services -> Credentials -> OAuth client ID. Authorized redirect URI:
${AUTH_URL}/api/auth/callback/google
Optional: OpenTelemetry
- Name
OTEL_EXPORTER_OTLP_ENDPOINT- Type
- string
- Description
OTLP collector endpoint (e.g.,
https://api.honeycomb.io).
- Name
OTEL_EXPORTER_OTLP_HEADERS- Type
- string
- Description
Headers for the OTLP exporter (e.g.,
x-honeycomb-team=YOUR_KEY).
Database migrations
Migrations run automatically on container startup. The Web container tracks applied migrations in the __drizzle_migrations table -- on first start everything is applied; on subsequent starts only new migrations run.
You don't need to run anything manually. Pull a new image, restart the container, and migrations apply.
Security considerations
Sign-up is open by default. Anyone who can reach the Web UI can create an account. There is no email verification, no admin approval, and no rate limiting on sign-up.
This is by design -- it keeps the setup simple. To secure it:
| Risk | Mitigation |
|---|---|
| Open sign-up | Run on internal network only, or put a reverse proxy with auth in front (e.g., Cloudflare Access, Tailscale, OAuth2 Proxy) |
Default AUTH_SECRET | Always set a real secret before exposing the UI to anything beyond your own machine |
| Default Postgres password | Change POSTGRES_PASSWORD -- the database is internal to the Docker network, but defense in depth matters |
| No password reset / email verification | Account recovery requires direct DB access. Acceptable for small teams, plan accordingly |
For company internal pilots, the typical setup is:
- Deploy on a private VM in your VNet
- Reach it via VPN or Tailscale -- no public internet exposure
- Use the default
AUTH_SECRETplaceholder just long enough to test, then rotate before sharing with the team
Updating
Pull and restart
docker compose pull
docker compose up -d
Migrations apply automatically. Active sessions stay valid (JWTs are not invalidated by container restarts as long as AUTH_SECRET doesn't change).
Backup
The only stateful component is Postgres. Back up the pgdata Docker volume:
Backup
docker compose exec postgres \
pg_dump -U golden_path golden_path > backup.sql
Restore
docker compose exec -T postgres \
psql -U golden_path golden_path < backup.sql
Troubleshooting
docker compose pull fails with unauthorized
The goldenpath.azurecr.io registry allows anonymous pulls. If you see auth errors, run docker logout goldenpath.azurecr.io first to clear stale credentials.
Web container exits with relation "users" does not exist
The migration step failed. Check docker compose logs web for the actual error -- usually a connection issue to Postgres. Make sure Postgres is healthy: docker compose logs postgres.
Sign-out redirects to 0.0.0.0:3000
AUTH_URL is not set or doesn't match the URL you're accessing. Set AUTH_URL=http://localhost:3000 (or whatever your actual URL is) in .env and restart.
MCP tools don't appear in Claude/Copilot/Cursor
Verify your .mcp.json points to the correct URL (download a fresh one from the Web UI -- it uses MCP_URL). If you're on a different machine than the host, replace localhost with the actual hostname.
What's next?
- MCP Setup -- Connect your IDE to the MCP server
- Concepts -- Understand architectures, skills, and templates
- Quickstart -- Generate your first solution end-to-end