Improve this doc
Network Setup on

Networking on balenaOS 2.x

Introduction

With balenaOS 2.0, connectivity management changed from ConnMan to NetworkManager. NetworkManager allows balenaOS more flexibility when configuring the network setup, and, in conjunction with ModemManager, allows balenaOS to offer first class GSM/Cellular support.

All of the network configuration for balenaOS can be done though files in the boot partition of your device. If you have a freshly downloaded balenaOS .img, you can mount it and inspect the resin-boot or resin-flash (for devices that boot from eMMC) partition. In the boot partition you will find a directory called system-connections.

The system-connections directory consists of a set of connection files—one file per connection. If you added a WiFi connection from the dashboard when you downloaded your image, you should see two connection files: resin-wifi and resin-sample.ignore. Both of these files specify a wifi connection type, but resin-sample.ignore is just a template or example file which you can copy to create new connections. You will notice that there is no file for ethernet. this is because NetworkManager will always set up a default ethernet connection. Most of the allowed options for these connection files can be found in the NetworkManager settings reference

WiFi Setup

If you entered your WiFi SSID and passphrase when you downloaded balenaOS from the dashboard, you should have a file called resin-wifi in the folder /system-connections/ (as mentioned above, this is found in the boot partition of your image).

[connection]
id=balena-wifi
type=wifi

[wifi]
hidden=true
mode=infrastructure
ssid=My Awesome WiFi Ssid

[ipv4]
method=auto

[ipv6]
addr-gen-mode=stable-privacy
method=auto

[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=super_secret_wifi_password

This file sets up a simple WiFi connection to a network named My Awesome WiFi Ssid with a WiFi password (psk) of super_secret_wifi_password. If you want to add multiple different WiFi credentials, then simply make a copy of resin-wifi or resin-sample.ignore and change the SSID and psk key values. You can also add the autoconnect-priority integer values in each file to define the priority of each connection when the device has multiple WiFi connections it can connect to.

To set WiFi as the default route to the internet, you need to force eth0 to have a low route metric and set the never-default option. The following ethernet configuration file can be put in the /system-connections/ folder to accomplish this:

[connection]
id=my-ethernet
type=ethernet
interface-name=eth0
permissions=
secondaries=

[ethernet]
mac-address-blacklist=

[ipv4]
never-default=true
route-metric=2000
dns-search=

ignore-auto-routes=true
method=auto

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

Note: Depending on the device, the interface name may not be eth0. To check the correct name, you can run ifconfig from the web terminal found on the device dashboard.

The connection file also defines what kind of security the network expects. If you want to set up a network with more elaborate security requirements, checkout the NetworkManager settings reference page. If you want to connect to an unsecured WiFi network, simply remove the [wifi-security] section.

As an example the below config sets up a WPA2-enterprise WiFi connection:

[connection]
id=balena-wifi
type=wifi

[wifi]
ssid=PLACE_SSID_HERE
mode=infrastructure
security=802-11-wireless-security

[wifi-security]
key-mgmt=wpa-eap

[802-1x]
eap=peap
identity=PLACE_YOUR_ID_HERE
phase2-auth=mschapv2
password=PLACE_YOUR_PASSWORD_HERE

[ipv4]
method=auto

[ipv6]
method=auto

Regulatory Domain

By default, the WiFi regulatory domain for your device is not set until it is connected to a network. If you need your device to connect at first boot to channels that may be restricted in some countries, you can specify the regulatory domain in the config.json file (like the above WiFi settings, this is found in the boot partition). Regulatory domain is set using the country field.

As an example, if you are deploying your device in Great Britain and need it to connect to channel 12 or 13, you would set "country":"GB".

Setting a Static IP

Setting a static IP is possible by adding a few fields to the [ipv4] section of your connection file.

[connection]
id=my-ethernet
type=ethernet
interface-name=eth0
permissions=
secondaries=

[ethernet]
mac-address-blacklist=

[ipv4]
address1=192.168.1.111/24,192.168.1.1
dns=8.8.8.8;8.8.4.4;
dns-search=
method=manual

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

The important bits to take note of here are interface-name=eth0 which indicates which network interface to use and the address1=192.168.1.111/24,192.168.1.1 line which shows we have a static IP of 192.168.1.111 and the network gateway is 192.168.1.1. The final piece is to add the dns=8.8.8.8;8.8.4.4; line, which tell the device to use Google DNS. The set up for a WiFi connection is very much the same, as can be seen in the below example.

[connection]
id=balena-wifi
type=wifi

[wifi]
hidden=true
mode=infrastructure
ssid=PLACE_SSID_HERE

[ipv4]
address1=192.168.1.127/24,192.168.1.1
dns=8.8.8.8;8.8.4.4;
dns-search=
method=manual

[ipv6]
addr-gen-mode=stable-privacy
method=auto

[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=PLACE_YOUR_PASSWORD_HERE

Creating a Hotspot

With NetworkManager, setting up your device as a hotspot is as simple as creating a balena-hotspot file in /system-connections/:

[connection]
id=balena-hotspot
uuid=36060c57-aebd-4ccf-aba4-ef75121b5f77
type=wifi
autoconnect=false
interface-name=wlan0
permissions=
secondaries=

[wifi]
band=bg
mac-address-blacklist=
mac-address-randomization=0
mode=ap
seen-bssids=
ssid=PLACE_SSID_HERE

[wifi-security]
group=
key-mgmt=wpa-psk
pairwise=
proto=rsn
psk=PLACE_YOUR_PASSWORD_HERE

[ipv4]
dns-search=
method=shared

[ipv6]
addr-gen-mode=stable-privacy
dns-search=
method=auto

This will create a WPA2/rsn hotspot, in case you need WPA protocol replace proto=rsn with proto= in section [wifi-security].

Cellular Modem Setup

For cellular or GSM based connections, balenaOS makes use of ModemManager and is configured in much the same way as WiFi connections are configured. Currently, it is only possible to add a cellular configuration by adding a connection file to /resin-boot/system-connections in the downloaded OS .img file, but in the future cellular connections will be configurable from the dashboard at download time.

To set up a cellular connection with your device, just drop the below example configuration into a file in the /resin-boot/system-connections/ directory in the .img or on SD card (if you have it flashed with the OS already) and name it something like cellular. Replace the apn= and number= values with your mobile providers APN and PPP dialing number. If your mobile carrier requires a password and username, you will need to add those as well. For a more in depth look at available settings options for GSM, have a look at Table 91. gsm setting in the NetworkManager settings reference.

[connection]
id=balena-cellular
type=gsm
autoconnect=true

[gsm]
apn=giffgaff.com
number=*99#
password=password
username=giffgaff

[serial]
baud=115200

[ipv4]
method=auto

[ipv6]
addr-gen-mode=stable-privacy
method=auto

Known Tested Modems:

We currently test as part of our release process and provide explicit support for the following modems:

  • USB modems (tested on Raspberry Pi 3, Balena Fin, Intel NUC and Nvidia TX2)
    • Huawei MS2131i-8
    • Huawei MS2372
  • mPCI modems (tested on Balena Fin and Nvidia TX2 Spacely carrier)
    • Quectel EC20
    • SIM7100E

Note: If your are powering your USB modem from a Raspberry Pi, it is a good idea to enable the full 1.2A current throughput for the USB ports, you can see how to do this here

With some of the modems listed in the ModemManager Supported Devices list you may find they struggle to connect, this is most likely due to usb_modeswitch not knowing how to automatically switch the device to modem mode. In these cases you will need to have a look at your modem's data sheet and figure out how to force it to stay in modem mode.

Changing the Network at Runtime

Warning: Making changes to the networking of a device is extremely dangerous and can lead to a device being unrecoverable, so exercise caution with any of the following.

Often there are times where the WiFi network that the device will be provisioned into is not known before hand. In these cases the device needs a mechanism to be able to add its own WiFi credentials during some kind of setup stage. For this reason we built the WiFi Connect project.

WiFi Connect enables the device to create a wireless access point called WiFi Connect (also customisable) which serves a captive portal. This allows your end user to connect to the device and add their WiFi credentials. The device will then automatically leave the setup mode and connect to the specified user network.

Under the hood, WiFi Connect is interacting with NetworkManager via its DBUS API. The DBUS API is a useful way to interact with the balenaOS host NetworkManager, and there are DBUS bindings for most languages. Below is a minimal Python example from the NetworkManager examples, which creates a new NetworkManager connection file that can be used to enable connecting to a new WiFi access point.

Note: You will need to install the dbus module in order to run this example (apt-get install python-dbus) and make sure DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket is exported in the environment. This ensures that DBUS calls are directed to the system bus that the host OS is listening on rather than the DBUS bus in your container. If you are using our Python base images, then you do not have to install the dbus module, since it is already included there.

#!/usr/bin/env python
import dbus, uuid

## Change these values
SSID="<SSID>"
PASSWORD="<PASSWORD>"
##

s_con = dbus.Dictionary({
    'type': '802-11-wireless',
    'uuid': str(uuid.uuid4()),
    'id': SSID,
})

s_wifi = dbus.Dictionary({
    'ssid': dbus.ByteArray(SSID),
    'mode': 'infrastructure',
    'hidden': dbus.Boolean(True),
})

s_wsec = dbus.Dictionary({
    'key-mgmt': 'wpa-psk',
    'auth-alg': 'open',
    'psk': PASSWORD,
})

s_ip4 = dbus.Dictionary({'method': 'auto'})
s_ip6 = dbus.Dictionary({'method': 'auto'})

con = dbus.Dictionary({
    'connection': s_con,
    '802-11-wireless': s_wifi,
    '802-11-wireless-security': s_wsec,
    'ipv4': s_ip4,
    'ipv6': s_ip6,
})


bus = dbus.SystemBus()

proxy = bus.get_object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager/Settings")
settings = dbus.Interface(proxy, "org.freedesktop.NetworkManager.Settings")

settings.AddConnection(con)

The above example will add a new WiFi connection file to your hostOS NetworkManager configuration in /etc/NetworkManager/system-connections. It should be noted that you will not see a new file created in resin-boot/system-connections because there isn't a two way binding. The way it works is that on device boot, the files in resin-boot/system-connections is copied into /mnt/state/root-overlay/etc/NetworkManager/system-connections without removing any files from the destination. That directory is then bind mounted to /etc/NetworkManager/system-connections in the root filesystem on the Host.

For other network setting needs, such as modifying existing network connection files, or listing connection information, please see the NetworkManager examples.

Warning: It can be dangerous to install NetworkManager or python-networkmanager in your container, especially if you have INITSYSTEM=on, as systemd will automatically try to start your container NetworkManager and this will take your devices offline. However, you can prevent this behavior by masking the NetworkManager service in your Dockerfile: RUN apt-get update && apt-get install -y network-manager && systemctl mask NetworkManager.service.

Note: The python-networkmanager Debian package depends on NetworkManager. Preferably python-networkmanager should be installed with pip instead of apt-get. That will avoid the issue described in the warning above and additionally the application container size will be kept minimal. It is most straightforward to use our Python base images, since they provide pip support out of the box: RUN pip install python-networkmanager.

Network Requirements

In order for a balena device to get outside of the local network and connect to the balena API, there are a few core network requirements.

Balena makes use of the following ports:

  • 443 TCP - This is the most fundamental requirement - it is used to connect to the VPN and the web terminal, and many web endpoints using TLS (https://.)
  • 123 UDP - For NTP time synchronisation.
  • 53 UDP - For DNS name resolution.

Each of these should work with outward only (and inward once outward connection established) firewall settings.

Additionally, if the network your device is connecting to works with whitelisting, you should whitelist the following domains on Port 80 and 443:

  • *.balena-cloud.com

Additionally make an outgoing connection to mixpanel.com, but this is not a functional requirement for balena, but rather allows us to track some useful metrics.

Connecting Behind a Proxy

We use redsocks to connect your device to balena from behind a proxy. To enable, a redsocks.conf file should be added at /mnt/boot/system-proxy/, specifying the needed proxy configuration:

base {
log_debug = off;
log_info = on;
log = "syslog:local7";
daemon = off;
redirector = iptables;
}

redsocks {
type = socks5;
ip = <SERVER IP>;
port = 8123;
local_ip = 127.0.0.1;
local_port = 12345;
}

Be sure that:

— File logging (log = "file:/var/log/redsocks";) is not used. It will lead to permission problems.

  • daemon = off is set, so that redsocks doesn’t fork.
  • local_port = 12345 is set, so that the iptables rules and redsocks port match.

Additionally, a /mnt/boot/system-proxy/no_proxy file can be added with a newline-separated list of IPs or subnets to not route through the proxy.