Omada Controller Helm Chart
September 9, 2026 · View on GitHub
Helm chart for deploying the TP-Link Omada SDN Controller on Kubernetes.
Prerequisites
- Kubernetes 1.19+
- Helm 3.0+
- PV provisioner support in the underlying infrastructure (for persistent storage)
Chart Versions
The Helm chart releases do not correspond to the controller version so below is a guide to help you find the appropriate Chart version for the version of the controller you wish to run:
| Controller Version | Chart Version | Change Notes |
|---|---|---|
6.3.0.44 | 1.5.3 | Fix Logs Persistent Volume Claim |
6.3.0.44 | 1.5.2 | Update to version 6.3.0.45 |
6.3.0.44 | 1.5.1 | Fix port name upgrade-es-https exceeding Kubernetes' 15 character limit |
6.3.0.44 | 1.5.0 | Update to version 6.3.0.44 |
6.2.14.11 | 1.4.2 | Added env var for UPGRADE_ES_HTTPS_PORT |
6.2.14.11 | 1.4.1 | Update to version 6.2.14.11 |
6.2.10.17 | 1.4.0 | Update to version 6.2.10.17 |
6.2.0.17 | 1.3.0 | Add javaMaxHeapSize and javaMinHeapSize config options |
6.2.0.17 | 1.2.0 | Update to version 6.2.0.17 |
6.1.0.19 | 1.1.6 | Add upgradeHttps port to service if it doesn't equal the manageHttps port |
6.1.0.19 | 1.1.5 | Add webConfigOverride option to force re-read of port configuration |
6.1.0.19 | 1.1.4 | Improve secret handling and external MongoDB support |
6.1.0.19 | 1.1.3 | Adds the ability to configure an initcontainer |
6.1.0.19 | 1.1.2 | Fix #721; duplicate port in values.yaml |
6.1.0.19 | 1.1.1 | Auto set MONGO_EXTERNAL=true when MongoDBUrl is set |
6.1.0.19 | 1.1.0 | Updated to version 6.1.0.19 |
6.0.0.25 | 1.0.2 | Added env var for UPGRADE_HTTPS_PORT |
6.0.0.25 | 1.0.1 | Updated to version 6.0.0.25 |
6.0.0.24 | 1.0.0 | Initial version |
Installation
Install the chart from OCI registry
helm install omada-controller oci://registry-1.docker.io/mbentley/omada-controller-helm
Install with custom values
helm install omada-controller oci://registry-1.docker.io/mbentley/omada-controller-helm -f custom-values.yaml
Install a specific version
helm install omada-controller oci://registry-1.docker.io/mbentley/omada-controller-helm --version 1.0.0
Uninstallation
helm uninstall omada-controller
Configuration
The following table lists the configurable parameters of the Omada Controller chart and their default values.
Image Configuration
| Parameter | Description | Default |
|---|---|---|
image.repository | Omada Controller image repository | mbentley/omada-controller |
image.pullPolicy | Image pull policy | Always |
image.tag | Image tag (defaults to chart appVersion if empty) | "" |
imagePullSecrets | Image pull secrets for private registries | [] |
Service Account
| Parameter | Description | Default |
|---|---|---|
serviceAccount.create | Create a service account | true |
serviceAccount.automount | Automount service account token | true |
serviceAccount.annotations | Annotations for service account | {} |
serviceAccount.name | Service account name (generated if empty) | "" |
Omada Controller Configuration
| Parameter | Description | Default |
|---|---|---|
config.ports.manageHttp | Management portal HTTP port | 8088 |
config.ports.manageHttps | Management portal HTTPS port | 8043 |
config.ports.portalHttp | Captive portal HTTP port | 8088 |
config.ports.portalHttps | Captive portal HTTPS port | 8843 |
config.ports.upgradeHttps | Dedicated HTTPS port for upgrades | 8043 |
config.ports.appDiscovery | UDP port for Omada App discovery | 27001 |
config.ports.adoptV1 | Device adoption port (v1) | 29812 |
config.ports.upgradeV1 | Device upgrade port (v1) | 29813 |
config.ports.managerV1 | Device management port (v1) | 29811 |
config.ports.managerV2 | Device management port (v2) | 29814 |
config.ports.discovery | UDP device discovery port | 29810 |
config.ports.udpManagement | UDP device management port | 19810 |
config.ports.transferV2 | Device transfer port (v2) | 29815 |
config.ports.rtty | RTTY connection port | 29816 |
config.ports.deviceMonitor | Device monitoring port (Omada 6+) | 29817 |
config.webConfigOverride | Force re-read of port configuration from properties on startup | false |
config.rootless | Run controller in rootless mode | true |
config.showMongoDBLogs | Display MongoDB logs (auto-disabled with external MongoDB) | false |
config.showServerLogs | Display server logs in container output | true |
config.sslCertName | SSL certificate filename | tls.crt |
config.sslKeyName | SSL key filename | tls.key |
config.tlsSecretName | Kubernetes TLS secret name to auto-mount | "" |
config.tls1Enabled | Re-enable TLS 1.0 & 1.1 | false |
config.timezone | Controller timezone | Etc/UTC |
config.externalMongoDBUrl | External MongoDB URL (mutually exclusive with secret) | "" |
config.externalMongoDBUrlSecret.name | Secret name containing MongoDB URI (mutually exclusive with URL) | "" |
config.externalMongoDBUrlSecret.key | Secret key containing MongoDB URI | "" |
config.javaMaxHeapSize | Replaces the hardcoded -Xmx in the default CMD (e.g. 512m, 1g); leave empty to use image default of 1024m | "" |
config.javaMinHeapSize | Replaces the hardcoded -Xms in the default CMD (e.g. 64m, 128m); leave empty to use image default of 128m | "" |
Service Configuration
| Parameter | Description | Default |
|---|---|---|
service.type | Kubernetes service type | LoadBalancer |
service.labels | Additional service labels | {} |
service.annotations | Additional service annotations | {} |
Ingress Configuration
| Parameter | Description | Default |
|---|---|---|
ingress.enabled | Enable ingress controller | false |
ingress.className | Ingress class name | "" |
ingress.annotations | Ingress annotations | {} |
ingress.managementHosts | Hosts for management portal | [] |
ingress.portalHosts | Hosts for captive portal | [] |
ingress.tls | TLS configuration | [] |
Persistence Configuration
| Parameter | Description | Default |
|---|---|---|
persistence.data.enabled | Enable data persistence | true |
persistence.data.storageClassName | Storage class for data volume | "" |
persistence.data.accessModes | Access modes for data volume | [ReadWriteOnce] |
persistence.data.size | Size of data volume | 1Gi |
persistence.logs.enabled | Enable logs persistence | true |
persistence.logs.storageClassName | Storage class for logs volume | "" |
persistence.logs.accessModes | Access modes for logs volume | [ReadWriteOnce] |
persistence.logs.size | Size of logs volume | 1Gi |
persistence.extraVolumes | Additional volumes to mount | [] |
persistence.extraVolumeMounts | Additional volume mounts | [] |
Resource Management
| Parameter | Description | Default |
|---|---|---|
resources | CPU/Memory resource requests/limits | {} |
nodeSelector | Node selector for pod assignment | {} |
tolerations | Tolerations for pod assignment | [] |
affinity | Affinity rules for pod assignment | {} |
Health Checks
| Parameter | Description | Default |
|---|---|---|
livenessProbe | Liveness probe configuration | {} |
readinessProbe | Readiness probe configuration | See values.yaml |
startupProbe | Startup probe configuration | See values.yaml |
Additional Configuration
| Parameter | Description | Default |
|---|---|---|
podAnnotations | Pod annotations | {} |
podLabels | Pod labels | {} |
initContainers | Init containers to add to the pod | [] |
extraEnvVars | Additional environment variables | {} |
extraManifests | Additional Kubernetes manifests | [] |
Example Configurations
Basic Installation with LoadBalancer
service:
type: LoadBalancer
annotations:
metallb.io/loadBalancerIPs: 192.168.1.20
persistence:
data:
size: 5Gi
logs:
size: 2Gi
Installation with Ingress and TLS
service:
type: ClusterIP
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
managementHosts:
- host: omada.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: omada-tls-secret
hosts:
- omada.example.com
Installation with External MongoDB
config:
externalMongoDBUrl: "mongodb://user:password@mongodb.example.com:27017/omada"
persistence:
data:
enabled: true # Data storage still required for backups and firmware with external MongoDB
size: 2Gi
logs:
enabled: true
size: 2Gi
Installation with External MongoDB Using Secret
For better security, store the MongoDB URI in a Kubernetes secret:
# Create a secret with the MongoDB URI
kubectl create secret generic mongodb-uri \
--from-literal=uri='mongodb://user:password@mongodb.example.com:27017/omada'
config:
externalMongoDBUrlSecret:
name: mongodb-uri
key: uri
persistence:
data:
enabled: true # Data storage still required for backups and firmware with external MongoDB
size: 2Gi
logs:
enabled: true
size: 2Gi
Important
externalMongoDBUrlSecret and externalMongoDBUrl are mutually exclusive. Setting both will result in a validation error during deployment.
Installation with Custom TLS Certificates
Using a Kubernetes TLS secret (e.g., from cert-manager):
config:
tlsSecretName: omada-tls-secret
Or with custom certificate/key filenames:
config:
tlsSecretName: omada-custom-tls
sslCertName: custom.crt
sslKeyName: custom.key
Note
The secret must be of type kubernetes.io/tls or contain keys matching sslCertName and sslKeyName.
Resource-Constrained Installation
config:
# Reduce the JVM heap from the default 1024m to fit within the pod memory limit.
# The replacement is visible in `ps` output alongside the Kubernetes resource limits.
javaMaxHeapSize: "512m"
javaMinHeapSize: "128m"
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 500m
memory: 1Gi
persistence:
data:
size: 2Gi
logs:
size: 500Mi
Note
MONGOD_EXTRA_ARGS (for tuning the embedded MongoDB WiredTiger cache) is not applicable for the standard Helm chart deployment, which uses external MongoDB and runs in rootless mode. If you are running a non-rootless deployment with embedded MongoDB, you can pass it via extraEnvVars.
Port Requirements
The Omada Controller requires several ports to be accessible for proper operation:
- 8043/TCP - HTTPS management portal and Device Firmware Upgrades (primary interface)
- 8088/TCP - HTTP management portal
- 8843/TCP - HTTPS captive portal
- 27001/UDP - Omada app discovery
- 29810/UDP - Device discovery
- 29811-29817/TCP - Device management, adoption, and monitoring
When using a LoadBalancer service, ensure your load balancer supports both TCP and UDP protocols.
Upgrading
To a newer chart version
helm upgrade omada-controller oci://registry-1.docker.io/mbentley/omada-controller-helm --version 1.2.0
Upgrading the Application Version
When upgrading to a new version of the Omada Controller application, update the image.tag value:
helm upgrade omada-controller oci://registry-1.docker.io/mbentley/omada-controller-helm \
--set image.tag=6.0.0.25 \
--reuse-values
Troubleshooting
Controller Takes Long Time to Start
The Omada Controller can take several minutes to start, especially on first run. The startupProbe is configured with a 5-minute timeout (30 failures × 10 seconds) to accommodate this.
Device Discovery Not Working
Ensure UDP ports 27001, 29810, and 19810 are accessible from your network. If using a LoadBalancer, verify it supports UDP protocols.
TLS/Certificate Issues
If using an Ingress controller, ensure your Ingress controller is configured to communicate with the backend using HTTPS. Example for nginx-ingress:
ingress:
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
MongoDB Connection Issues
Check the logs for MongoDB connection errors. If using external MongoDB, verify the connection URL and credentials.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
Support
See the Getting Help & Reporting Issues section of the main README for details on how to get support.