Rumour says that the Unifi Cloud Gateway Max finally supports BGP. A wiser man than I once quipped that automating ones router would be a fools errand. I wholeheartedly agree, but it does not change the fact that I also am a fool. And proud inventor of footguns everywhere.
Kubernetes controllers are fun. This controller will look for any LoadBalancer objects annotated with unifi-port-forward.fiskhe.st/mapping. A mapping is one or more key:value pairs (comma-separated) of the externally facing port mapped to the service that the port forward should forward the traffic to.
On first startup, the controller will check all services and then inspect the currently provisioned Port Forward rules on the Unifi router, either updating or ensuring that port forward rules match with the service object spec and annotation rule. Thereafter, it will periodically reconcile on a schedule ensuring router port forward rules weren't brought out of sync by some other means.
The controller does not delete other rules (as long as they don't use conflicting names) and has a small footprint.
- Real-time monitoring of kubernetes LoadBalancer services, automatically configuring corresponding port forward rules on a UniFi router.
- Pre-created rules not maintained by this controller stays untouched (as long as there are no conflicts). Only manages services with valid annotations.
- Support for multiple rules per service
- Periodic reconciliation for state drift detection
- Publishes kubernetes events for improved observability
- Can create port forwards using CRDs for services that are managed outside of kubernetes
- Configurable with environment variables
- Detailed error handling and logging on the controller pod
- Graceful service deletion with finalizer-based cleanup
- UniFi Cloud Gateway Max (the only one tested)
- Likely compatible with other UniFi routers (UDM, etc.), but YMMV.
- This was neither tested for, nor is there a bigger plan for adding support for other variants.
see examples/README.md for more info
just checkor individually
just fmt
just lint
just testUNIFI_ROUTER_IP: IP address of the router (default: 192.168.1.1)UNIFI_USERNAME: Router username (default: admin)UNIFI_PASSWORD: Router passwordUNIFI_API_KEY: API key instead of user/pass. Untested(!)UNIFI_SITE: UniFi site name (default: default)
For authenticating, it is recommended to create a dedicated service account. Use role Admin, with full control to the network.
Prerequisites
- A namespace (the default configured in these manifests:
unifi-port-forward) - A router with provisioned credentials
- A functional LoadBalancer implementation that assigns valid IP addresses to Service LoadBalancer objects
Deploy the annotation based Controller
Edit manifests/deployment.yaml and update the environment variables in the container spec.
kubectl apply -f manifests/deployment.yamlTest the controller by provisioning a test service
kubectl apply -f manifests/test-service.yamlIf everything works, you should see a new port forward rule added on the router:
- Name:
unifi-port-forward/test-service9090-80:http - WAN Port:
9090 - Forward Port:
80 - Forward IP: the IP allocated to the LoadBalancer service
Deploy CRDs
Optionally, one can install Custom Resource Definition (CRD)
portforwardrules.unifi-port-forward.fiskhe.st.
kubectl apply -f manifests/crdThere are two types of CRD-based port forward rules, serviceref and standalone. Serviceref makes a mapping to a running kubernetes service, while standalone can be used to create port forward for external services
kubectl apply -f examples/crds/portforwardrule-serviceref.yaml
kubectl apply -f examples/crds/portforwardrule-standalone.yamlThis project uses GitHub Actions for continuous integration and automated Docker image deployment to GitHub Container Registry (GHCR).
- Trigger: Automatic on push to
mainbranch - Registry:
ghcr.io/fiskhest/unifi-port-forward(public) - Tagging:
latest- Always points to the latest buildYYYY-MM-DD-commit- Unique tag per build (e.g.,2025-01-30-a1b2c3d)
# Using latest tag (recommended)
kubectl set image deployment/unifi-port-forward controller=ghcr.io/fiskhest/unifi-port-forward:latest
# Using specific date tag for rollback
kubectl set image deployment/unifi-port-forward controller=ghcr.io/fiskhest/unifi-port-forward:2025-01-30-a1b2c3dBuild and push locally using the justfile:
just buildIssues may be addressed, but no guarantees can be given. I am reluctant on increasing the feature complexity/scope of this project. PRs might get reviewed. Forking is welcome.
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Potential use cases that might be added in the future:
- add a configurable "policy" = sync / upsert-only / create-only?
- Support for Service NodePort Objects / no load balancer implemented
MIT License - see LICENSE file for details