I manage a few Unifi deployments on the side, and part of this is hosting a Unifi controller. For the past year, I have been hosting this controller on a DigitalOcean Kubernetes cluster – which has worked really well. DOKS is a good service (great if you’re a cheapskate like me and don’t want to pay for your controlplane). I have no complaints about their offerings whatsoever.
Given that I recently build a nice shiny new homelab, I wanted to put it to use. I also could reduce my cloud bill by hosting things locally instead. However, one hurdle remained to be overcome – granting public access to the Unifi install from behind my NAT.
I knew about frp from previous research on this topic, but I recently came across https://github.com/b4fun/frpcontroller. User bcho had done the legwork to build a k8s controller to run frp and create tunnels from within Kubernetes. Their code was a bit old though, and needed some updating. I forked their project and re-implemented it onto kubebuilder v3, along with upgrading to Go v1.17. You can check it out at https://github.com/ebauman/frpcontroller.
Here’s the steps I followed to put together these pieces and host Unifi behind NAT.
- Spin up a t2.micro instance on EC2
- Acquire an elastic IP and associate it with the instance
- On this micro instance, download the latest frp release and
/etc/frp/frps.iniwith the following content:
[common] bind_port = 7000 bind_addr = [PRIVATE IPV4 ADDR] token = [YOUR TOKEN]
- Create a new unit file for the
frpsservice. This file should be
/etc/systemd/system/frps.serviceand should have the following content:
[Unit] Description=fast reverse proxy [Service] ExecStart=/usr/local/bin/frps -c /etc/frp/frps.ini [Install] WantedBy=multi-user.target
systemctl daemon-reload, followed by
systemctl enable frps --now
FRP Client on Private K8s Cluster
Setting up the private k8s cluster is outside of the scope of this guide.
With the cluster setup, install frpcontroller by calling
kubectl apply -f https://raw.githubusercontent.com/ebauman/frpcontroller/main/release/v0.0.2/install.yaml (check for a more recent version in github.com/ebauman/frpcontroller/tree/main/release and use that instead)
Installing frpcontroller also installs two CRDs into your cluster –
Endpoint is the client-side reference for an FRP server. In this case, we’ll make one to point to our newly-created t2.micro instance.
First, create the namespace into which you will eventually install the Unifi controller.
kubectl create namespace unifi
Next, create a new file called
endpoint.yaml and place into it the following contents:
apiVersion: frp.1eb100.net/v1 kind: Endpoint metadata: name: unifi namespace: unifi spec: addr: '184.108.40.206' # your elastic ip. include the quotes port: 7000 token: yourtoken
Create this endpoint by calling
kubectl apply -f endpoint.yaml.
Next, you’ll need to install the Unifi controller. There is plenty of documentation on how to accomplish this – I use https://artifacthub.io/packages/helm/k8s-at-home/unifi to do this.
Once Unifi is installed, there are various ports you will need to connect using FRP. Most commonly, these are:
|tcp/8080||device and app communication|
|tcp/8443||controller web ui|
|tcp/6789||unifi mobile speed test|
|udp/5514||remote syslog capture|
service.yaml with the following content:
apiVersion: frp.1eb100.net/v1 kind: Service metadata: name: unifi namespace: unifi spec: endpoint: unifi ports: - name: tcp-8080 localPort: 8080 remotePort: 8080 protocol: TCP - name: udp-10001 localPort: 10001 remotePort: 10001 protocol: UDP - name: tcp-8443 localPort: 8443 remotePort: 8443 protocol: TCP - name: tcp-6789 localPort: 6789 remotePort: 6789 protocol: TCP - name: udp-3478 localPort: 3478 remotePort: 3478 protocol: UDP - name: udp-5514 localPort: 5514 remotePort: 5514 protocol: UDP selector: [dependent upon your setup, see notes below]
spec.selector field here works just like it does on a regular k8s
service. The values here are dependent upon how you installed Unifi. For instance, my selector(s) are:
selector: app.kubernetes.io/name: unifi
Yours may differ. Typically the Unifi chart deploys services for you so you will see selectors implemented on those services – you can copy those.
Create the service in k8s by calling
kubectl apply -f service.yaml.
If all goes successfully, you should see a pod created in the
unifi namespace that runs the
frpc software. Looking at the logs of this pod should show the connection being established to your
That’s it! Now you can browse to https://your-elastic-ip:8443/ and get to the Unifi page.