EDIT - 8/12/2023 - There is a better (less manual) solution to this problem now, check this post out
Hey! I couldn’t find this documented anywhere else, so I created a shell script that I could call to automate port forwarding based upon presence detection. I had a couple use cases that I specifically wanted to account for, but the one I was most interested in was how I could enable/disable port forwarding for wireguard VPN when anybody in my family is away or home.
I achieved this by created a shell script that takes a number of variables (things like int/ext port to be forwarded, int IP, service name, etc) and makes calls to Unifi via their (sorta) documented rest API. Something cool about this method is it enables me to reuse the same shell script for multiple different port forwarding rules, and whether I’m enabling/disabling them.
First up, create the shell script. In my case, I created this here: /config/scripts/unifi.sh
#!/bin/sh
cookie=$(mktemp)
curl_cmd="curl --tlsv1 --silent --cookie ${cookie} --cookie-jar ${cookie} --insecure"
portfwd() {
# authenticate against unifi controller
${curl_cmd} -d "{\"username\":\"$1\", \"password\":\"$2\"}" https://${3}:8443/api/login
# enable/disable firewall rule
${curl_cmd} -k -X PUT https://${3}:8443/api/s/default/rest/portforward/${10} -H "Content-Type: application/json" -d @- <<EOF
{
"name":"$4",
"enabled":$5,
"src":"any",
"dst_port":"$6",
"fwd":"$7",
"fwd_port":"$8",
"proto":"$9",
"log":false,
"_id":"$10",
"site_id":"$11"
}
EOF
}
"$@"
Next, I create an entry in configuration.yaml
for referencing the shell command:
shell_command:
unifi_portfwd: /bin/bash /config/scripts/unifi.sh portfwd {{ username }} {{ password }} {{ baseurl }} {{ name }} {{ enabled }} {{ dst_port }} {{ ip }} {{ fwd_port }} {{ proto }} {{ id }} {{ unifi_site }}
All of these variables need to be referenced in your secrets.yaml
like so:
unifi_usr: unifi_username
unifi_pwd: unifi_password
unifi_ip: internal_cloud_key_ip
unifi_site: unifi_site_id
wireguard_name: port_forward_name
wireguard_port: port_number
wireguard_proto: udp_or_tcp
wireguard_id: id_from_unifi_ui
Finally, create a couple automations to disable/enable the port forwarding based upon presence:
- alias: away - enable wireguard portfwd
trigger:
- platform: state
entity_id: binary_sensor.anybody_home
to: "off"
action:
- service: shell_command.unifi_portfwd
data:
username: !secret unifi_usr
password: !secret unifi_pwd
baseurl: !secret unifi_ip
name: !secret wireguard_name
enabled: 'true'
dst_port: !secret wireguard_port
ip: !secret hass_ip
fwd_port: !secret wireguard_port
proto: !secret wireguard_proto
id: !secret wireguard_id
unifi_site: !secret unifi_site
- alias: home - disable wireguard portfwd
trigger:
- platform: state
entity_id: binary_sensor.anybody_home
to: "on"
action:
- service: shell_command.unifi_portfwd
data:
username: !secret unifi_usr
password: !secret unifi_pwd
baseurl: !secret unifi_ip
name: !secret wireguard_name
enabled: 'false'
dst_port: !secret wireguard_port
ip: !secret hass_ip
fwd_port: !secret wireguard_port
proto: !secret wireguard_proto
id: !secret wireguard_id
unifi_site: !secret unifi_site
Hope this helps somebody else out and happy automating!
Here’s a link to my HA configuration for other cool automation ideas
EDIT - 2/11/2021
If you’ve upgraded unifi and the above isn’t working, check out this post for a fix. The tl;dr is that ubiquiti changed to port 443 and goofed around with a header that is required for auth.
EDIT - 1/12/2022
Looks like Ubiquiti changed the case sensitivity of a csrf token with a recent update, see this post for a fix.