Setting up a UniFi Security Gateway for an On Demand iOS VPN

[UPDATE – 18 May 2020] In some recent iOS update (not sure which), certificates are no longer required to have an on demand VPN work. So I switched to using the built in L2TP VPN in the USG which requires very little configuration. My VPN profile has also changed and can be found here. This profile does on demand like before, but also automatically connects if something on my phone tries to access certain internal resources (I have AdGuard setup to handle DNS on my network). I use this for connecting to Home Assistant without port forwarding or anything like that.

[UPDATE – 06 Feb 2019] With the latest release of the OpenVPN app, the identifier has changed from net.openvpn.OpenVPN-Connect.vpnplugin to net.openvpn.connect.app. Without this change, the VPN profile will NOT work.

Following up on my widely popular post about Setting up an EdgeRouter Lite for an On Demand iOS VPN, I’ve decided to write about the same procedure, but on a Ubiquiti UniFi Security Gateway. Much of the procedure is the same, but for completeness I’ll include all the steps here.

An on demand VPN will automatically fire up when you’re on certain WiFi networks and under certain circumstances. This is quite useful if you use unknown WiFi networks and are concerned about security (you should be!).

This is a really long setup, but it is straightforward. If you’re intimidated by command lines and editing text files, this process is not for you!

Certificate Setup

  1. SSH into the USG. You’ll use the same username and password for connecting to the UniFi Controller.
  2. Setup a new certificate authority that will be used to create new client certificates for the VPN. Issue the following commands, one per line. Follow the prompts when you run the commands.
    configure
    sudo su
    cd /usr/lib/ssl/misc/
    ./CA.sh -newca
    
  3. Create a new server certificate and sign it. Follow the prompts when you run the commands; you’ll need to enter a password for the new request. We’ll remove it in another step.
    ./CA.sh -newreq
    ./CA.sh -sign
    
  4. Copy the certificate authority key and certificate to an area of the router that will survive a firmware upgrade.
    cp demoCA/cacert.pem demoCA/private/cakey.pem /config/auth/
    
  5. Also copy the server certificate to the same place.
    mv newcert.pem /config/auth/server.pem
    
  6. Display the certificate authority certificate using cat /config/auth/cacert.pem and then copy it into BBEdit or another text editor on your local computer; save it to your hard drive.

  7. Remove the password on the private key for the server so that the VPN server can start automatically.

    openssl pkcs8 -in newkey.pem -out /config/auth/server-pem.key
    
  8. Generate the Diffie-Hellman Paramters; this takes a long time.
    openssl dhparam -out /config/auth/dhp.pem -2 1024
    
  9. The next part is generating the client certificates. The recommendation is to have 1 client certificate per client. However, this would require me to have 1 for my iPad and 1 for my iPhone complicating setup. While having 1 certificate for both may not be recommended, it is the route I chose. When prompted, enter a password for the new key and then the last line will remove it. Don’t enter a challenge password.
    ./CA.sh -newreq
    ./CA.sh -sign
    mv newcert.pem client-cert.pem
    openssl pkcs8 -in newkey.pem -out client-key.pem
    
  10. Display the certificate using cat client-cert.pem and past it into BBEdit and then saved it.

  11. Do the same thing with the key using cat client-key.pem and saved it to my Mac.
  12. On my Mac, do the following in Terminal (make sure you’re in the same directory as where you saved the certificate and key). When exporting, set a password that you’ll use later.

    openssl pkcs12 -export -out client1.p12 -inkey client-key.pem  -in client-cert.pem
    

Note that the /config directory survives firmware upgrades. If you need to add client certificates later and the certificate authority you created is gone, you may have to start the setup over.

OpenVPN Server Setup

  1. Create a file called config.gateway.json and place it in the data directory for your UniFi Controller. I run my controller on a Mac and the path is ~/Library/Application Support/UniFi/data/sites/default. It should basically be as shown below. You’ll want to configure the OpenVPN network (10.0.5.0/24) if you use a different numbering scheme; this cannot be a network defined in the UniFi Controller. You should also change the DNS to servers you use. I don’t know if the push-route commands are absolutely necessary, but I put them in anyway as they appear to work.
    {
      "firewall": {
        "group": {
          "network-group": {
            "open_vpn_network": {
              "description": "OpenVPN Network",
              "network": [
                "10.0.5.0/24"
              ]
            }
          }
        }
      },
      "interfaces": {
        "openvpn": {
          "vtun0": {
            "local-port": "1194",
            "mode": "server",
            "openvpn-option": [
              "--comp-lzo",
              "--push redirect-gateway",
              "--push dhcp-option DNS 10.0.1.2",
              "--push dhcp-option DNS 10.0.1.1",
              "--duplicate-cn"
            ],
            "server": {
              "push-route": [
                "10.0.1.0/24",
                "10.0.5.0/24",
                "10.0.0.0/16"
              ],
              "subnet": "10.0.5.0/24"
            },
            "tls": {
              "ca-cert-file": "/config/auth/cacert.pem",
              "cert-file": "/config/auth/server.pem",
              "dh-file": "/config/auth/dhp.pem",
              "key-file": "/config/auth/server-pem.key"
            }
          }
        }
      },
      "service": {
        "nat": {
          "rule": {
            "7000": {
              "description": "OpenVPN to WAN",
              "log": "disable",
              "outbound-interface": "eth0",
              "protocol": "all",
              "source": {
                "group": {
                  "network-group": "open_vpn_network"
                }
              },
              "type": "masquerade"
            }
          }
        }
      }
    }
    
  2. Force a reprovision of the USG by selecting the USG, then clicking on the Config tab.

    Reprovision

  3. On the UniFi Controller, click on Settings and then Routing & Firewall.
  4. Click on Firewall at the top.
  5. Click Groups and add an OpenVPN port group.

    Screen Shot 2018 02 09 at 1 18 49 PM
  6. Switch over to Rules and setup an OpenVPN rule.

    OpenVPN Firewall
    Good work if you’ve followed along this far! Next up is the client setup which has a bunch of steps as well.

iOS Client Setup

  1. Locate the p12 file that you created on your Mac.
  2. Download Apple Configurator from the Mac App Store.
  3. Select New Profile from the File menu.

    New Profile

  4. Fill out the General information for the profile. You can leave the Identifier as is.
    General

  5. Click on Certificates and then press Configure. Select the .p12 file you created way back in the first part of the instructions.
    Select Certificate
  6. Give the certificate a name and enter the password you used when exporting the p12 file.
    Certificate Selected
  7. Select the VPN section and click Configure.
    Configure VPN

  8. Enter a name for the connection.

  9. Select Custom SSL for the Connection Type.
  10. Enter net.openvpn.connect.app for Identifier.
  11. Enter the hostname for the Server. I recommend your Dynamic DNS hostname here.
  12. Enter some username for the account; it won’t be used.
  13. Enter a placeholder key/value pair. You’ll edit this by hand later.
  14. Select Certificate for User Authentication and then pick the certificate you added earlier.
  15. Enable VPN On Demand. You’ll hand edit this later as well.
  16. Select a Disconnect on Idle value; I selected Never.
  17. Save the profile to your Desktop (or somewhere else). Don’t sign it as signing it will prevent you from editing it by hand which is needed to properly setup the VPN On Demand. Configurator doesn’t handle all the options present in current iOS versions.
    VPN Setup
  18. Open the .mobileconfig file in BBEdit. BTW, if you haven’t bought BBEdit, you should definitely buy it. While the current version offers basic functionality for free, this is a tool that should always remain in your tool belt.
  19. Look at the section called VPN. Mine is basically below. You’ll need to change a few entries.

        <key>VPN</key>
        <dict>
            <key>AuthName</key>
            <string>scott</string>
            <key>AuthenticationMethod</key>
            <string>Certificate</string>
            <key>DisconnectOnIdle</key>
            <integer>0</integer>
            <key>OnDemandEnabled</key>
            <integer>1</integer>
            <key>OnDemandRules</key>
            <array>
                <dict>
                    <key>Action</key>
                    <string>Disconnect</string>
                    <key>SSIDMatch</key>
                    <array>
                        <string>My Network 5 GHz</string>
                        <string>My Network</string>
                    </array>
                </dict>
                <dict>
                    <key>Action</key>
                    <string>Disconnect</string>
                    <key>InterfaceTypeMatch</key>
                    <string>Cellular</string>
                </dict>
                <dict>
                    <key>Action</key>
                    <string>Connect</string>
                    <key>InterfaceTypeMatch</key>
                    <string>WiFi</string>
                </dict>
                <dict>
                    <key>Action</key>
                    <string>Ignore</string>
                </dict>
            </array>
            <key>PayloadCertificateUUID</key>
            <string>SOME_IDENTIFER</string>
            <key>RemoteAddress</key>
            <string>vpn.example.com</string>
        </dict>
        <key>VPNSubType</key>
        <string>net.openvpn.OpenVPN-Connect.vpnplugin</string>
        <key>VPNType</key>
        <string>VPN</string>
        <key>VendorConfig</key>
        <dict>
            <key>dev</key>
            <string>tun</string>
            <key>proto</key>
            <string>udp</string>
            <key>remote</key>
            <string>vpn.example.com 1194</string>
            <key>cipher</key>
            <string>BF-CBC</string>
            <key>resolv-retry</key>
            <string>infinite</string>
            <key>nobind</key>
            <string>NOARGS</string>
            <key>persist-key</key>
            <string>NOARGS</string>
            <key>persist-tun</key>
            <string>NOARGS</string>
            <key>comp-lzo</key>
            <string>NOARGS</string>
            <key>link-mtu</key>
            <string>1542</string>
            <key>ca</key>
            <string>-----BEGIN CERTIFICATE-----\nMIID...bAqZZCQYgHwAh9bW\n-----END CERTIFICATE-----\n</string>
        </dict>
    </dict>
    
  20. Change the vpn.example.com references to your VPN address.

  21. For the section that starts with BEGIN CERTIFICATE for the ca, find the cacert.pem that you saved to your hard drive. Open that in BBEdit and remove all the returns in the file. After the first line replace the return with \n. Before the last line put a \n and then another one after the line. You should end up with a big long line!
  22. The OnDemandRules are described in Apple’s documentation. My setup basically says that if I’m on a trusted network, disconnect the VPN. When on cellular, also disconnect the VPN (I trust the cellular network for now). If I’m on any other network, connect the VPN. The last item just falls through, but I suspect it will never get there. In my example, change the names of the trusted SSIDs.
  23. The VendorConfig section are the OpenVPN options that should match the server.
  24. Save the file.
  25. Transfer the .mobileconfig file to your iOS device. I drop the file on AirDrop to my devices. If the formatting of the file is correct, the iOS device will ask you to install the file.
  26. In the VPN section in iOS Settings, Connect and cross your fingers. That’s it! Now when you wonder onto an unknown WiFi network, the VPN should automatically connect. It may take a few seconds for the connection to come up.

If you’ve made it this far, congratulations! I spent a few days working on this and hopefully I captured all the steps. Please send me corrections or feedback.

Notes

  1. I’ve noticed that sometimes iOS connects to my VPN even when it is on my network. The On Demand connection is evaluated when the network changes and I suspect iOS gets confused and starts evaluating the On Demand rules prior to getting an SSID.
  2. The default certificates are good for 1 year. So you’ll need to renew then after a year. I’ll cross that bridge when I come to it.
  3. If the certificate is compromised, I don’t know how to do certificate revocations.
  4. Treat the certificate and keys just as if they were passwords. This goes for the .mobileconfig file as well. The mobileconfig file has the password to the p12 file in clear text and anyone with that file can connect to your VPN and access your network.
  5. The OnDemand rules are evaluated when the device changes networks and may take a few seconds to bring up the VPN. I always wait for the VPN icon to come up before doing anything on my device.
  6. OpenVPN runs on UDP port 1194 by default. You can configure it for TCP 443, but I won’t go into that because it seems like a pain and requires more changes.
  7. In the latest iOS version (11.2.x), if your VPN is on demand, you cannot manually connect with it. You have to go into iOS Settings->General->VPN, tap the Info button next to the VPN and turn off “Connect On Demand”.
  8. Savvy readers will notice that I put the client certificate as a p12 file in the mobileconfig file and put it in the OpenVPN specific settings. There appears to have been a change to the OpenVPN client on iOS where the p12 certificate no longer works. You may be able to remove the certificate from the configuration, but I left it.

16 Replies to “Setting up a UniFi Security Gateway for an On Demand iOS VPN”

  1. HI,

    I followed your instructions. My mobileprofile can be installed on the iphone but you cannot activate it. I have already deactivated on demand button.

    I suspect that my mobileconfig is not correct.
    Would you possibly put your configuration completely online and only comment out user, password and certificates?

    Or you can send it on my Email.

    br
    vitala

    1. Unfortunately I don’t have an answer on why your mobile configuration isn’t working. I’ve actually changed how I’m doing my VPN, so I don’t have the profile handy. I’m using something that is more akin to this. Maybe you can use that as a basis.

    1. I’m using the L2TP VPN built into the USG. This is much easier to setup. With a change to iOS, an on demand VPN can be created without having to use certificates.

      I’ll update the article with some additional information.

  2. I know this is a bit cheeky, Scott, but you seem to know a good bit about the UniFi USG. I have a Pro 4. I am using it as an openvpn Client for one VLAN on my network, which I have working fine.
    However when the vtun0 interface is active, all the other VLANs and the LAN have no internet access. They can access the LAN OK. My LAN is on eth0 and the WAN on eth2
    Would you be willing to have a look at my command line rules, or tell me how I can route the LAN and other VLANs out to my WAN with the vtun0 VPN interface active?
    Regards….

    1. Hi Francis,

      Unfortunately I wouldn’t even know where to start for you. I have a number of VLANs and have my USG setup as a VPN server, but haven’t set it up as a VPN client. You might try the Ubiquiti Community Forums as there are people there that know a ton more than I do; I’ve been moving away from custom configurations and only doing stuff with the GUI as my goal is to move to a UDM Pro at some point in the future and the less custom stuff I have, the easier it will be to move.

      I’m sorry I’m not much help.

  3. Hi there not sure if you still are reading this but im having some serious isssues with connecting an ipad and accessing my RDP over VPN to my UDM Pro.

    I can connect over VPN and access any device on my network. Unless im using an IOS device. In that case i can connect, but cannot see any devices on my network.

    a search of whats my ip shows that i am properly connected to the VPN.

    Thoughts

  4. Hi Scott,

    Many thanks so much for doing this tutorial, I’m using the L2TP on my USG 3 and wanted to check a couple of things with you.

    1) exactly what within your new ‘on demand vpn’ iOS profile do I need to update?
    2) as I have a dynamic IP address provided by my ISP, do you know of anyway I can have thr VPN IP dynamically updated, maybe via something like shortcuts?

    Huge thanks !

    1. Hi Chris,

      For your dynamic IP address, the USG can handle various dynamic DNS providers. Select one and use that. For what you need to change in the VPN profile, look for things like “My Network”, someinternalDNS, Base64EncodedSharedSecret, example.com, etc. You can also follow the full instructions on the article and instead of using the certificates, use Configurator to set it up and then modify the on demand rules.

      1. Hi Scott,

        I’m not 100% sure where to start with this, I have my L2TP vpn set up, and know the settings, but I’m nervous about screwing up my internet connection and the custom gateway.config file it uses.

        Would you consider at some point doing a specific focussed guide on how you created the Test On Demand VPN.mobileconfig file for a L2TP VPN set up and where you put it etc? (Not being a Mac user, I don’t have the configurator app)

        Many thanks

  5. Thanks for posting this! It works great to automatically connect to my internal Home Assistant (similar to your 2020 setup). What I haven’t figured out is how to automatically disconnect (I have DisconnectOnIdle, the timeout and a default action of “Disconnect”).

    1. I figure that Home Assistant connects fairly often (location updates and such), so maybe it isn’t idle long enough to connect. I just don’t worry about it and let the VPN run most of the time.

  6. Hi Scott, I have mine On Demand VPN working just fine. I do however run into an issue occasionally if my Internet connection goes down or there is a power outage at my home. What happens is that, my phone seems to try to continuously re-connect to my VPN server and since it can’t it also block all other data traffic on my IOS device. This only happens when the VPN server goes down, but wondering if you knew a way to fix this behavior?

    1. Hi!

      I actually no longer use an on-demand VPN. I was using it for Home Assistant, but now rely more on HomeKit (through Home Assistant) which uses my AppleTV as a hub. HomeKit does some magic to handle routing back to my home network.

      If I want to use the Home Assistant app, then I’ll flip on the VPN.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.