Configure a VPN connection to your robot via SSH

This guide will demonstrate how to setup a VPN tunnel (tun0) over SSH to your robot using Formant's port-forwarding capabilities over our peer-to-peer communication channel. Before starting with this guide, make sure you have setup a device with the agent, and have setup on your client machine fctl and configured ssh. This guide is based on the existing SSH VPN community guide.

Prerequisites

Install the Formant agent

Your device must have the Formant agent installed. For more information, see Getting Started: Setting up your device.

Configure fctl and SSH

Your device must have fctl installed and SSH configured. For more information, see fctl overview and installation and SSH to your robot via fctl.

Step 1: Device configuration

Using an editor, open /etc/ssh/sshd_config and change the PermitRootLogin line and add the PermitTunnel line, resulting in the following:

PermitRootLogin without-password
PermitTunnel yes

Allow Network Address Translation (NAT)

  1. These commands will enable NAT without the need to reboot (NAT will be persistent). This may already be enabled on your system.
sudo sysctl -w net.ipv4.ip_forward=1
  1. To set as default, using an editor, open /etc/sysctl.conf and add the following line:
# Needed to add for forwarding
net.ipv4.ip_forward = 1
  1. Create the tun0 network interface by adding a network interface. Create the file /etc/network/interfaces.d/tun0 containing the following:
 iface tun0 inet static
        pre-up sleep 5
        address 10.0.0.100
        pointopoint 10.0.0.200
        netmask 255.255.255.0
        up arp -sD 10.0.0.200 eth0 pub
  1. The Formant agent runs with its own user and group (formant:formant). By default, it has very limited permissions. To enable the agent to create a tunnel interface, we need to add it to the device's sudo group:
sudo usermod -aG sudo formant
sudo systemctl restart formant-agent

📘

Note: the Formant user has no shell or login by design.

Step 2: Client configuration

  1. Generate an SSH key. Here we'll call it formant-vpn:
ssh-keygen -f formant-vpn -b 4096
  1. Put the private key formant-vpn in /root/.ssh and set permissions:
# create this directory if it doesn't exist
sudo mkdir -p /root/.ssh
sudo cp formant-vpn /root/.ssh/formant-vpn
sudo chown root:root /root/.ssh/formant-vpn
sudo chmod 400 /root/.ssh/formant-vpn
  1. Copy the public key formant-vpn.pub onto the device. Once there add it to the authorized keys (Run this ON the device):
# if the root ssh folder doesn't exist, create it
sudo mkdir -p /root/.ssh
sudo bash -c "cat formant-vpn.pub >> /root/.ssh/authorized_keys"
  1. Set up the root user ssh_config by adding this snippet to /root/.ssh/config:
Host *.formant
ProxyCommand fctl port-forward $(echo %h | sed "s/\.formant$//") -r 127.0.0.1 -p %p

Step 3: SSH commands on client

  1. Open a new terminal and run this command to stand up the tunnel:
sudo ssh -i /root/.ssh/formant-vpn -Cf -w 0:0 nano.001.formant 'ifdown tun0; ifup tun0'

This is running SSH with tunneling (-w) as well as using compression on the channel (-C) and forking it to the background (-f). Additionally, it tells our device to run ifdown tun0; ifup tun0.

📘

You may see RTNETLINK answers: Cannot assign requested address which can happen if you run this command twice, or the device already has its addresses configured.

  1. Next we need to setup tun0 on our client machine:
sudo ip link set tun0 up
sudo ip addr add 10.0.0.200/32 peer 10.0.0.100 dev tun0
sudo ip route add 10.0.0.0/24 via 10.0.0.200

This configures tun0 on the client machine and routes traffic on 10.0.0.0/24 back to our device.

Step 4: Verify your work

  1. You can check the tunnel is established with the following command:
ifconfig

You should see something like the following on the client machine:

tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        inet 10.0.0.200  netmask 255.255.255.255  destination 10.0.0.100
        inet6 fe80::45f3:9856:2ef0:9b50  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 4  bytes 192 (192.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 48 (48.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

and on the device:

tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        inet 10.0.0.100  netmask 255.255.255.255  destination 10.0.0.200
        inet6 fe80::1fc:7f5f:6948:9e8d  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 500  (UNSPEC)
        RX packets 80  bytes 12604 (12.6 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 90  bytes 13785 (13.7 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  1. Try pinging the device from your client machine:
ping 10.0.0.100

Closing a VPN connection

  1. Get the process ID (PID) of the SSH command:
ps aux | grep ssh
  1. Kill the PID:
sudo kill -9 $pid

Client automation script

The following is a short script to automate the client process. It accepts one input parameter which is the name of the device you are connecting to:

#! /bin/bash -e

device=$1

echo "setting up ssh tunnel..."

sudo ssh -i /root/.ssh/formant-vpn -Cf -w 0:0 $device.formant 'ifdown tun0; ifup tun0'

echo "ssh tunnel setup."

sudo ip link set tun0 up
sudo ip addr add 10.0.0.200/32 peer 10.0.0.100 dev tun0
sudo ip route add 10.0.0.0/24 via 10.0.0.200

echo "tun0 configured"

sleep infinity

Exiting the script will also tear down the SSH tunnel.

Long-term SSH tunnels to your device: best practices

If you plan on keeping long-running SSH tunnels to your devices, you may want to also set the following in your ssh config:

Host *
  ServerAliveInterval 120
  ServerAliveCountMax 10

The ServerAliveInterval will send a ping every 120 seconds if there is no activity on the tunnel. The ServerAliveCountMax defines how many consecutive pings are sent before disconnecting.

👋

If you notice an issue with this page or need help, please reach out to us! Use the 'Did this page help you?' buttons below, or get in contact with our Customer Success team via the Intercom messenger in the bottom-right corner of this page, or at [email protected].