> ## Documentation Index
> Fetch the complete documentation index at: https://docs.routr.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy Routr to Civo with Helm

> Create a Civo Kubernetes cluster, install the routr-connect chart with a public SIP address, and verify it with rctl.

## What you'll build

You create a k3s cluster on Civo with the `civo` CLI, install the `routr-connect` Helm chart, and expose EdgePort through a cloud load balancer so SIP clients on the internet can reach it. You finish by connecting `rctl` to the API and registering a softphone.

## Prerequisites

* A [Civo](https://www.civo.com) account and an API key
* The `civo` CLI, logged in with your API key (`civo apikey add` and `civo apikey current`)
* `kubectl` and Helm 3
* Node.js and npm, to install `rctl`
* A SIP softphone

## Steps

**1. Create the cluster**

Create a Kubernetes cluster named `routr` and wait until it's ready.

```bash theme={null}
civo kubernetes create routr --wait
```

This uses your account's default region, node size, and node count. Add `--nodes`, `--size`, or `--region` to change them.

> [!NOTE]
>
> Civo's flags and defaults change over time. Run `civo kubernetes create --help` to see the options your CLI version supports.

**2. Point kubectl at the cluster**

Save the cluster's kubeconfig into your local configuration.

```bash theme={null}
civo kubernetes config routr --save
```

Switch to the new context if the CLI didn't do it for you, then check the nodes.

```bash theme={null}
kubectl config use-context routr
kubectl get nodes
```

> [!TIP]
>
> `kubectl get nodes` lists your Civo nodes with status `Ready`.

**3. Add the Helm repository and a namespace**

Add the Routr chart repository, refresh it, and create a namespace for the release.

```bash theme={null}
helm repo add routr https://routr.io/charts
helm repo update
kubectl create namespace routr
```

**4. Install the chart with a public EdgePort**

Create a `values.yaml` file that exposes EdgePort's UDP Service through a load balancer. Leave `externalAddrs` empty for now, because you don't know the public address yet.

Filename: `values.yaml`

```yaml theme={null}
apiserver:
  tlsOn: false

edgeport:
  serviceTypeUDP: LoadBalancer
```

Install the chart as a release named `routr`.

```bash theme={null}
helm install routr routr/routr-connect --namespace routr -f values.yaml
```

Civo creates a load balancer for the `routr-routr-edgeport-udp` Service. Wait until it has an external IP.

```bash theme={null}
kubectl get svc -n routr routr-routr-edgeport-udp --watch
```

```text theme={null}
NAME                       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
routr-routr-edgeport-udp   LoadBalancer   10.43.112.205   74.220.20.115   5060:31744/UDP   2m
```

> [!NOTE]
>
> The chart only sets the Service type; the cloud provider creates the load balancer. Confirm in the Civo dashboard that the load balancer forwards UDP port `5060`. If your region or plan doesn't support UDP load balancing, keep the default `NodePort` type and point clients at a node's public IP and the assigned node port instead.

**5. Set the external address**

Add the load balancer's IP to `values.yaml` so EdgePort advertises it in SIP headers.

Filename: `values.yaml`

```yaml theme={null}
apiserver:
  tlsOn: false

edgeport:
  serviceTypeUDP: LoadBalancer
  externalAddrs: [74.220.20.115]
```

Apply the change.

```bash theme={null}
helm upgrade routr routr/routr-connect --namespace routr -f values.yaml
```

Check that every pod is running.

```bash theme={null}
kubectl get pods -n routr
```

> [!TIP]
>
> All pods show `Running`, including two EdgePort pods (`routr-routr-edgeport-0` and `routr-routr-edgeport-1`).

**6. Verify with rctl**

Install `rctl`.

```bash theme={null}
npm install --location=global @routr/ctl
```

The API Server stays private. Forward its port in a separate terminal.

```bash theme={null}
kubectl -n routr port-forward svc/routr-routr-apiserver 51908
```

Create a Domain, credentials, and an Agent. Answer the prompts as you did in the [intercom tutorial](/tutorials/intercom-on-kubernetes).

```bash theme={null}
rctl domains create --insecure
rctl credentials create --insecure
rctl agents create --insecure
```

List the Agents to confirm the API works end to end.

```bash theme={null}
rctl agents get --insecure
```

```text theme={null}
Name       Username   Domain      Max Contacts   Privacy   Enabled
John Doe   1001       sip.local                  None      Yes
```

**7. Register a softphone**

Configure a softphone with the Agent's username and password, `sip.local` as the domain, and the load balancer IP (for example, `74.220.20.115:5060`) as the outbound proxy over UDP.

> [!TIP]
>
> The softphone shows the account as registered. Register a second Agent on another device and call between them to confirm signaling works over the internet.

Routr carries signaling only. If your softphones sit behind different NATs and you hear no audio, add RTPEngine and enable RTPRelay. See [Enable WebRTC](/guides/enable-webrtc) for the `rtprelay` values.

> [!WARNING]
>
> This setup has TLS turned off on the API and accepts SIP over plain UDP. Before you put real users on it, follow [Secure the server](/guides/secure-the-server).

## Clean up

Delete the release, then the cluster. Deleting the cluster also removes its load balancer.

```bash theme={null}
helm uninstall routr --namespace routr
civo kubernetes remove routr
```

## Next steps

> **[Deploy on Kubernetes](/guides/deploy-on-kubernetes)**
>
> Production settings for the Helm chart.

> **[Helm values](/reference/helm-values)**
>
> Every value the chart accepts.

> **[Secure the server](/guides/secure-the-server)**
>
> Turn on TLS for the API and the signaling.

> **[Deployment topologies](/concepts/deployment-topologies)**
>
> When to choose routr-one or routr-connect.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.