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.

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.

  1. Copy the docker-compose.yml from below into an empty folder
  2. Run docker compose up -d
  3. Open http://localhost:3000
  4. 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:

What you get

Three containers, no external services:

ContainerPortPurpose
postgres--Database (architectures, skills, users, sessions)
web3000Studio Web UI
mcp8080MCP 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 to https://gp.mycompany.internal or 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.json config -- 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

This is by design -- it keeps the setup simple. To secure it:

RiskMitigation
Open sign-upRun on internal network only, or put a reverse proxy with auth in front (e.g., Cloudflare Access, Tailscale, OAuth2 Proxy)
Default AUTH_SECRETAlways set a real secret before exposing the UI to anything beyond your own machine
Default Postgres passwordChange POSTGRES_PASSWORD -- the database is internal to the Docker network, but defense in depth matters
No password reset / email verificationAccount 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_SECRET placeholder 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

Was this page helpful?