> For the complete documentation index, see [llms.txt](https://docs.kiloiot.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kiloiot.io/kilo-mioty-service-center/getting-started/installation-kubernetes-helm.md).

# Installation: Kubernetes (Helm)

Deploy KiloCenter to Kubernetes with Helm — chart, prerequisites (k8s 1.25+, PostgreSQL 14+, Redis 7+), and ingress.

Use the current installation examples only in an isolated evaluation environment with test data. Published credentials, signing-key defaults and network exposure need correction before customer use. Changing only the administrator password is insufficient. Read the [installation safety notice](/kilo-mioty-service-center/security/installation-safety.md) before running commands.

Deploy KiloCenter Community Edition into your Kubernetes environment with the supplied Helm chart. This route fits teams that already operate a cluster and want the open-source MIOTY network services managed through that deployment workflow.

### What does this guide achieve?

Deploy KiloCenter to a Kubernetes cluster using the Helm chart included in this repository.

### Prerequisites

| Requirement         | Minimum version |
| ------------------- | --------------- |
| Kubernetes cluster  | 1.25+           |
| Helm                | 3.x             |
| External PostgreSQL | 14+             |
| External Redis      | 7+              |

PostgreSQL and Redis are **not** deployed by this chart. Provision them separately (managed services, operators, or standalone) and supply connection details in your values override.

### Architecture

```
                  Internet
                     |
               [ Ingress ] (optional)
                /         \
         kc-web:80    kc-gateway:9090
                          |
                    kc-core:50051 ---- kc-identity:50052
                    /      |      \
             bssci:5000  scaci:5001  mosquitto:1883
                                         |
                                    [MQTT clients]
```

The chart deploys four services and one MQTT broker, plus two hook jobs:

| Component     | Port(s)                                                 | Description                                                        |
| ------------- | ------------------------------------------------------- | ------------------------------------------------------------------ |
| `kc-core`     | 50051 (gRPC), 5000 (BSSCI), 5001 (SCACI), 8086 (health) | Service center engine                                              |
| `kc-gateway`  | 9090 (gRPC-web), 8087 (health)                          | External API ingress                                               |
| `kc-identity` | 50052 (gRPC), 8088 (health)                             | Identity, users, organizations                                     |
| `kc-web`      | 80                                                      | Web management interface (nginx)                                   |
| `mosquitto`   | 1883, 9001 (WebSocket)                                  | MQTT broker                                                        |
| `certgen`     | —                                                       | Pre-install hook that generates TLS certificates                   |
| `rekey`       | —                                                       | Pre-upgrade hook that converts stored key material (see Upgrading) |

### Step 1: Create a Values Override

Generate the key-material master key first. The chart refuses to render without it, and KC-Core and KC-Identity encrypt every endpoint, session, message and TLS key at rest under it:

```bash
openssl rand -hex 32
```

At minimum, override the database, Redis, and secret settings, with the master key as `secrets.masterKey` and a second value from the same command as `secrets.internalPeerSecret`:

```yaml
# my-values.yaml
postgresql:
  host: my-postgres.default.svc.cluster.local
  password: "a-strong-password"
  sslMode: "require"

redis:
  host: my-redis.default.svc.cluster.local

secrets:
  masterKey: "<the 64 hex characters from openssl rand -hex 32>"
  internalPeerSecret: "<another 64 hex characters from openssl rand -hex 32>"
  authHmacSecret: "replace-with-a-random-string-at-least-32-bytes"
  mqttAdminPassword: "strong-mqtt-admin-pw"
  mqttClientPassword: "strong-mqtt-client-pw"

certgen:
  serverName: "kilocenter.example.com"
```

> **Important:** The `authHmacSecret` is used to sign and verify JWT tokens across KC-Gateway and KC-Identity. It must be at least 32 characters.

> **Internal peer secret.** KC-Gateway, KC-Core and KC-Identity reach each other over the cluster network and trust each other's identity headers only from a peer presenting `secrets.internalPeerSecret`. The chart refuses to render without it, and the services refuse to start with one shorter than 32 characters.

> **Keep the master key.** Store `secrets.masterKey` with your other deployment secrets and pass the same value to every `helm upgrade`. If it is lost, the stored keys cannot be decrypted and every endpoint and base station has to be provisioned again.

### Step 2: Install

```bash
helm install kilocenter ./helm/kilocenter -f my-values.yaml
```

On first install, a pre-install hook Job runs the `certgen` binary to generate a self-signed CA and server certificate into a shared PVC. Subsequent upgrades skip generation if certificates already exist.

### Step 3: Validate

```bash
# Check all pods are running
kubectl get pods -l app.kubernetes.io/instance=kilocenter

# Check service health
kubectl exec deploy/kilocenter-kc-core -- wget -qO- http://localhost:8086/health/ping
kubectl exec deploy/kilocenter-kc-identity -- wget -qO- http://localhost:8088/health
kubectl exec deploy/kilocenter-kc-gateway -- wget -qO- http://localhost:8087/health
```

### Step 4: Access the UI

Without ingress, use port-forwarding:

```bash
kubectl port-forward svc/kilocenter-kc-web 8080:80
```

Then open <http://localhost:8080/> in your browser.

### What Is the Default Admin Login?

On first startup, a default admin user is created via database migration:

|              |                          |
| ------------ | ------------------------ |
| **Email**    | `admin@kilocenter.local` |
| **Password** | `admin123!`              |

Sign in with this account first and change its password straight away under **Change Password** in the user menu, the same way you would set your own password on a new router or gateway. Choosing and keeping the installation's credentials is part of installing it. The account holds every role (see [User Roles and Permissions](/kilo-mioty-service-center/security/users-and-roles.md)); use it to create accounts for the people who work with the installation and give each of them the roles they need.

### Ingress

Enable standard Kubernetes Ingress in your values override:

```yaml
ingress:
  enabled: true
  className: nginx
  hosts:
    - host: kilocenter.example.com
      paths:
        - path: /
          pathType: Prefix
          service: kc-web
          port: 80
        - path: /kilocenter.api
          pathType: Prefix
          service: kc-gateway
          port: 9090
  tls:
    - secretName: kilocenter-tls
      hosts:
        - kilocenter.example.com
```

When using ingress, add your domain to the CORS allowed origins:

```yaml
kcGateway:
  config:
    corsOrigins:
      - "https://kilocenter.example.com"
```

### BSSCI/SCACI Protocol Access

Base stations connect directly to KC-Core over TCP+TLS on ports 5000 (BSSCI) and 5001 (SCACI). These are raw TCP connections, not HTTP. To expose them externally, create a LoadBalancer service:

```yaml
apiVersion: v1
kind: Service
metadata:
  name: kilocenter-bssci
spec:
  type: LoadBalancer
  selector:
    app.kubernetes.io/name: kc-core
    app.kubernetes.io/instance: kilocenter
  ports:
    - name: bssci
      port: 5000
      targetPort: 5000
    - name: scaci
      port: 5001
      targetPort: 5001
```

### TLS Certificates

The `certgen` hook generates a self-signed CA and server certificate on first install. For production, replace these with certificates signed by a trusted CA by mounting your own secret or PVC at `/app/certificates` in the kc-core pod.

### Configuration Reference

For the full list of configurable parameters, see the [Helm chart README](https://github.com/Kiloiot/kilo-service-center/blob/main/helm/kilocenter/README.md).

### Upgrading

```bash
helm upgrade kilocenter ./helm/kilocenter -f my-values.yaml
```

Every upgrade runs the `rekey` pre-upgrade hook before the new pods start: it migrates the schema to `000143` and converts key material written by earlier releases to the authenticated envelope format. An installation from v1.3.0 or earlier has no `secrets.masterKey` yet; generate one as in Step 1 and add it to your values before upgrading. Add `secrets.internalPeerSecret` the same way if your values do not set it yet. See [Key material migration](/kilo-mioty-service-center/operations/key-material-migration.md) for the hook's options, including where it exports retired `endpoint_keys` rows.

An explicit tag selects a named release but can move; it is not an immutable digest or proof of a safe release. The published July release used `v1.3.0`, including the `v` prefix:

```yaml
global:
  imageTag: "v2.0.0"
```

### Troubleshooting

| Symptom                           | Likely Cause                                                                          | Fix                                                                                                                                                                                                                     |
| --------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Pods in `ImagePullBackOff`        | Wrong repository/tag, registry access or connectivity                                 | Check the exact image name against the release first, then registry access; do not assume credentials alone will fix a wrong path                                                                                       |
| KC-Core readiness probe 503       | PostgreSQL unreachable or the gRPC server not serving yet                             | `/health/ready` answers only for PostgreSQL and the internal gRPC server; check PostgreSQL connectivity and the KC-Core log. `/health` lists every component, including KC-Identity, MQTT and the BSSCI/SCACI listeners |
| `invalid_token` after login       | HMAC secret mismatch                                                                  | Ensure `secrets.authHmacSecret` is set (same for gateway and identity)                                                                                                                                                  |
| BSSCI connection refused          | No external service                                                                   | Create a LoadBalancer service for ports 5000/5001                                                                                                                                                                       |
| gRPC-web errors in browser        | CORS or ingress misconfigured                                                         | Check `kcGateway.config.corsOrigins` and ingress paths                                                                                                                                                                  |
| Upgrade fails in the `rekey` hook | Legacy rows under another passphrase, or `endpoint_keys` rows with no export location | Read the hook log (`kubectl logs job/kilocenter-rekey`) and follow [Key material migration](/kilo-mioty-service-center/operations/key-material-migration.md)                                                            |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.kiloiot.io/kilo-mioty-service-center/getting-started/installation-kubernetes-helm.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
