Automating unifi port forwarding based upon presence detection

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.

9 Likes

This is amazing! Why this has not widely spread around the community since you’ve posted this is beyond me.

It’s not exactly what I need but this opened my eyes and am planning to do something like this to open/close port 80 for when the Nginx Proxy Manager add-on needs to renew its certificates.

Thanks for sharing your work @jon102034050

awesome, if it even helps one person I’m happy - I’ve received so much help from super smart people on the forums here, figured its nice to be able to contribute back :smiley:

This is great, thanks! I’d like to use this to create a simple switch to turn on or off a specific port forward rule. This should do the trick fine. Thanks.

1 Like

Hey @jon102034050,

Love what you’ve done here.

I’m hoping to do the same thing but for my Remote Desktop port, forwarding to a specific client IP.

I’ve tried to give the api a bit of a look but I’m not positive how it translates.
Do you think you could help me modify the above?

Also, how do you get the last secret - id_from_unifi?
Is there a way to debug this?

I’m using a UDM and it’s my only site (I’m brand spanking new to Unifi) so I assume the site id is ‘default’?

Thank you

Linton

If you only have a single site, the site name should probably be default. You can get the ID of the port forwarding item by clicking edit on the port forward that you want to toggle. It’ll be at the end of the URL

So I got it working and it was amazing! Thank you.

But, I had to update to use my new U6-Lite AP and now it won’t :frowning:

Seems it was a large update to the unifi controller.
The config URL port changed to 443 (well, there is no longer a port so I assume 443)

I’ve tried changing the string in the script to :443 and removing it completely.

I’ve also tried putting in raw data instead of secrets.

Unifi controller ver is now 6.0.43
UDM firmware 1.8.6.2969

Can this be debugged?

Thank you

Linton

Here’s a link to my commit where I fix the issue you’re describing. I probably should update my OP with this as well: https://github.com/JonGilmore/ha-personal/commit/65b99934b10bbd138d98539e62d7785adcf12631

the tl;dr of it is the X-CSRF-Token was breaking stuff, and it seems unifi changed the behavior of this.

WORKING!!! :smiley: :smiley:

thanks mate

nice! I spent WAY too long trying to figure out what the hell broke when I updated as well, hopefully I saved you some time, hah!

Seems to be a common theme in the Unifi world :stuck_out_tongue:

@jon102034050 thanks for the workaround.

I have created a feature request to make controlling Port Forwarding part of the Unifi integration: Unifi Integration: Ability to control Port Forwarding . Feel free to vote for it to get some attention to this feature.

1 Like

@jon102034050

Hey mate, still can’t thank you enough for these port forwarding switches. You wouldn’t happen to have a solution for triggering a reboot for a UDM device?

Sad reality is that these still need semi-regular reboots to keep them working at their best and I’d love to schedule this rather than cut the power in times of need.

Cheers :slight_smile:

Linton

glad you’ve found it useful! I personally use a UXG and haven’t really had too many issues with it that require a reboot (totally glossing over the fact that it’s missing a LOT of features that are in older hardware). As I find time, I’ll see if I can work something up though. As a workaround in the meantime, you could always just put it on a smart plug and cycle that via automation

Yeah I’ve got one of those dumb power timers I used to do a similar thing with for my old router. Ubiquiti equipment just feels a bit more delicate to be doing that all the time.

apparently in an SSH terminal you would simply type ‘reboot’ to execute what i’m doing if that helps.

Alrighty, did a little testing and here’s what I came up with:

I’m not entirely sure this will work perfectly for you though as I don’t personally own a UDM device. This works for rebooting an AP for me, so hopefully it’ll just be plug-n-play for a UDM as well.
Let me know how it goes!

Just noticed that with the latest unifi update, they must have changed the case of the x-csrf-token which busted this script :frowning:
This commit fixes that though: fix(unifi): csrf case sensitivity · JonGilmore/ha-personal@76c17a1 · GitHub

Can you explain what the “id from unifi ui” bit means? Pretty sure I have the rest of this sorted, but I’m not sure where to get that. I’m looking at my ui, under “port forwarding”, and I don’t see any id?

Thanks!

Sorry, thats not super clear :smiley: It’s the ID in the URL when you click on edit for the port forward

1 Like

That was my guess, but better safe than sorry. Thank you so much for the speedy reply!!

1 Like