# Self-host an existing provider

Run a capability on your infrastructure and connect it to a hub.

Source: https://railgrid.ai/docs/self-hosting/providers/


A provider is a chart you install into a Kubernetes cluster you administer. It authenticates to the hub's kcp with a kubeconfig the hub mints for it, registers itself in the hub's catalog, and serves its API to the workspaces that enable it. The steps below are the same for every provider; the per-provider guides add the state, credentials, and settings each one needs.

## Prerequisites

- An existing hub you can reach, and permission to onboard a provider: a platform administrator (listed in the hub's `adminUsers`), or an organization administrator for an organization-owned provider.
- A Kubernetes runtime you administer, Helm, and kubectl.
- Network access from the provider pods to the hub and to every kcp shard's advertised virtual-workspace endpoint. Connectivity to the public console alone is not enough.
- The provider's own dependencies: a Postgres database, an S3 bucket, a Gateway. Each guide lists them.

Run the providers in the hub's cluster when you can. They then reach the hub at its in-cluster Service, which is what the hub bakes into their kubeconfigs when `hub.internalURL` is set, and the kcp shards through the same split-horizon names the hub uses.

## 1. Get the provider's kubeconfig

The hub mints one credential per provider: a ServiceAccount in a provider workspace of its own (`root:railgrid:providers:<name>`), cluster-admin there and nothing above it. Three ways to get it:

- **Console, organization-owned provider.** Open **Providers → Self-Hosting**, select the provider recipe, and follow the generated instructions. They include the chart version, the provider-specific values, and the command that creates the runtime Secret.
- **Console, platform provider.** A platform administrator onboards it in the admin area and downloads the kubeconfig there.
- **API, scripted.** Creating a `Provider` object in the hub's `root:railgrid:system:providers` workspace does exactly what the admin area does: the hub creates the provider workspace, the ServiceAccount, and writes the kubeconfig to Secret `<name>-kubeconfig` in that workspace's `default` namespace. Railgrid's own environments mint all six public providers this way from one idempotent script.

```bash
# With an admin kubeconfig for the hub's kcp (front proxy), create the Provider...
WS=https://kcp.example.com/clusters/root:railgrid:system:providers
curl --cert admin.crt --key admin.key -X POST -H 'Content-Type: application/json' \
  -d '{"apiVersion":"admin.railgrid.ai/v1alpha1","kind":"Provider","metadata":{"name":"code"},"spec":{"displayName":"code"}}' \
  "$WS/apis/admin.railgrid.ai/v1alpha1/providers"
# ...then read the minted kubeconfig once status.secretRef appears.
curl --cert admin.crt --key admin.key "$WS/api/v1/namespaces/default/secrets/code-kubeconfig" \
  | python3 -c 'import sys,json,base64; print(base64.b64decode(json.load(sys.stdin)["data"]["kubeconfig"]).decode())' \
  > code.kubeconfig
```

The kubeconfig's server is the hub (`hub.internalURL` when set, else `hub.hubExternalURL`), and its CA data is the hub's provider CA bundle. It is a credential; keep it out of version control and never use it as a Helm `--kube-context`.

## 2. Create the runtime Secret

In the cluster where the chart will run:

```bash
kubectl create namespace railgrid-provider-code
kubectl --namespace railgrid-provider-code create secret generic railgrid-provider-kubeconfig \
  --from-file=kubeconfig=./code.kubeconfig
```

The filename can differ, but the Secret data key must be `kubeconfig`; the charts mount that exact key. Every public provider defaults to Secret name `railgrid-provider-kubeconfig` (`providerKubeconfig.secretName`), except the infrastructure provider in operator mode, which reads `operator.providerKubeconfigSecret.name`. A Secret in the hub cluster is not visible from another cluster; create it where the pods run.

## 3. Set the hub values

Every public provider chart takes the same `hub` block:

```yaml
hub:
  # Where heartbeats go. In the hub's cluster, the hub Service.
  url: https://railgrid-hub.railgrid-system.svc.cluster.local:9443
  # Leave empty: heartbeats authenticate with the provider's own
  # ServiceAccount token. Naming a Secret that does not exist wedges the
  # pod in CreateContainerConfigError.
  tokenSecretRef:
    name: ""
catalogEntry:
  enabled: true     # the init container registers the provider with the hub
```

The provider verifies the hub's serving certificate against the system roots plus the CA bundle inside its own kubeconfig, which the hub minted from `hub.providerCASecretName`. A hub on a private CA therefore needs nothing more than the Secret from step 2; `hub.insecure` stays `false` and is only for development hubs with throwaway certificates. To trust a different bundle, set `RAILGRID_HUB_CA_FILE` (or `RAILGRID_HUB_CA_DATA`) in the pod's environment. Several providers also take a browser-facing hub origin (`hub.publicURL`, `hub.externalURL`, `hub.actionsExternalURL`) for redirects and agents; those must be the public console URL, not the Service.

## 4. Install the chart

The charts are published at `oci://ghcr.io/railgrid/charts/railgrid-<provider>-provider`. Each provider has its own version line; find the current one and pin it:

```bash
helm show chart oci://ghcr.io/railgrid/charts/railgrid-code-provider | grep -E '^(version|appVersion)'
helm upgrade --install code oci://ghcr.io/railgrid/charts/railgrid-code-provider \
  --version CHART_VERSION --namespace railgrid-provider-code --values code-values.yaml
```

Railgrid's environments follow `0.2.x` through Flux. Images for the public providers are public; a private provider needs an `imagePullSecrets` entry.

## 5. Verify

1. The pod is `Running`. The init container has applied the CatalogEntry, schemas, and APIExport into the provider workspace through the kubeconfig; if it fails, see the table below.
2. The provider appears in the console's provider list for the hub.
3. [Enable the provider](https://railgrid.ai/docs/use/workspaces/enable-provider/) in a test workspace and complete its quickstart. Only this proves the whole path: hub, kcp routing, and the provider's own backend.

### A fresh provider is UNREADY until a workspace binds it

Right after install, every provider reports `/healthz` 200 but `/readyz` 503 with `cannot reach the APIExport virtual workspace ... APIExportEndpointSlice <name>.providers.railgrid.ai publishes no endpoints yet`, and its CatalogEntry carries `BackendHealthy=False`. This is kcp, not a fault: a shard publishes a virtual-workspace endpoint only once a workspace on it has bound the export. Enabling the provider in one workspace makes it Ready. A Helm install with `--wait` on such a provider times out for the same reason.

### Diagnose an installation failure

| Symptom | Check | Fix |
|---|---|---|
| Init container: `x509: certificate signed by unknown authority` against the hub | The kubeconfig was minted before the hub had `providerCASecretName`, or the hub's serving certificate changed | Re-mint and [refresh the kubeconfig](#refresh-a-provider-kubeconfig) |
| Pod running but `Ready=False`, logs show `x509` against a shard hostname | The provider CA bundle lacks the kcp server CA | Append `root-server-ca` to the bundle, restart the hub, refresh the kubeconfig |
| `CreateContainerConfigError` | `hub.tokenSecretRef.name` or another `*SecretRef` names a Secret that does not exist | Create the Secret or leave the reference empty |
| `ImagePullBackOff` | Image tag and registry access | Pin `image.tag` to a published version; add a pull Secret for private images |
| Pod ready, provider missing from the console | Heartbeat and CatalogEntry conditions in the provider workspace | Check `hub.url` is reachable from the pod and the init container succeeded |
| `/readyz` 503, `publishes no endpoints yet` | Nothing has bound the export | Enable the provider in a workspace |

```bash
kubectl --namespace railgrid-provider-code get events --sort-by=.lastTimestamp
kubectl --namespace railgrid-provider-code logs -l app.kubernetes.io/instance=code --all-containers=true --tail=100
```

Redact credentials before sharing diagnostics.

## Refresh a provider kubeconfig

The hub rewrites each provider's kubeconfig Secret in the provider workspace when it reconciles, for example after the provider CA bundle or `hub.internalURL` changes. The copy in your runtime namespace does not follow. Re-read the Secret from the hub (step 1), re-create the runtime Secret (step 2), and restart the provider pods. Railgrid's environments keep this as one idempotent script run after every hub trust change.

## Remove a provider

Disable the provider in every workspace that uses it and follow the provider's cleanup instructions first, then `helm uninstall` the release. Deleting the `Provider` object on the hub tears down the provider workspace and strands tenant bindings; do not use it as a temporary disable. See [Provider access and lifecycle](https://railgrid.ai/docs/administration/providers/).

## Provider guides

- [App Studio](app-studio/)
- [AI agents](agents/)
- [Edges](edges/)
- [Infrastructure](infrastructure/)
- [Code](code/)
- [Kuery](kuery/)
- [Databricks](databricks/)


## In this section

- [Self-host AI agents](https://railgrid.ai/docs/self-hosting/providers/agents/): Deployment prerequisites, verification, and recovery for AI agents.
- [Self-host App Studio](https://railgrid.ai/docs/self-hosting/providers/app-studio/): Deployment prerequisites, verification, and recovery for App Studio.
- [Self-host Code](https://railgrid.ai/docs/self-hosting/providers/code/): Deployment prerequisites, verification, and recovery for Code.
- [Self-host Databricks](https://railgrid.ai/docs/self-hosting/providers/databricks/): Deployment prerequisites, verification, and recovery for Databricks.
- [Self-host Edges](https://railgrid.ai/docs/self-hosting/providers/edges/): Deployment prerequisites, verification, and recovery for Edges.
- [Self-host Infrastructure](https://railgrid.ai/docs/self-hosting/providers/infrastructure/): Deployment prerequisites, verification, and recovery for Infrastructure.
- [Self-host Kuery](https://railgrid.ai/docs/self-hosting/providers/kuery/): Deployment prerequisites, verification, and recovery for Kuery.