Background
A family member wants to have access to devices on their home network from the internet, and have been using the public IP-address given by the ISP to connect back home.
Unfortunately, during certain events, such as power outages, the ISP has a short enough lease that a new IP-address is given.
When this happens, the family member can no longer connect to their home network until they have manually changed the IP-address to the new one in the applications they use.
It would be adventageous for them to avoid this “debacle” of the things not working and the digging up of the new/current IP-address.
It would also be a bonus if the family member can monitor whatever solution is implemented, for their own sake.
Requirements and Constraints
Since this is a home project; costs, especially monthly/anually ones, should be minimized/reasonable. Therefore a free solution is highly preferred.
Using an existing device on the network may be troublesome:
- Whatever existing device I may choose can (read: will) be replaced at some point beyond my control, and probably without warning
- An existing device on their network is still their device, which does not let me do whatever I want on it, and they can do whatever they want with it (ex. shut it down, factory reset)
- I want minimal required hands-on and setup by the family member
- Ease of install and ease of replacement
Research and Resources
DNS and DDNS
DNS is the way to abstract away IP-addresses, and Dynamic DNS (DDNS) is the way to keep periodically changing IP-addresses current in a DNS registrar. What is DDNS? Wipikedia summarizes it adequately:
Dynamic DNS (DDNS) is a method of automatically updating (IP-addresses in*) a name server in the Domain Name System (DNS), often in real time…
*DDNS can update more than just IP-addresses.
DDNS requires a service to run within the target/local home network on something. This something can be anything from the ISP-provided router, smart home hub, personal computer/device, maybe even the fridge these days, as long as it has LAN access, can reach the internet, and can run some user specified code periodically. The actual piece of code that has to run depends on what the DDNS provider requires, as no established standard exists. However, for the most part, DDNS providers either have an API or a HTTP/HTTPS based protocol (or both) for updating the registrar.
Since I am not looking to do anything fancy with DDNS, I am choosing the path of a HTTP/HTTPS based protocol. Primarily because it is dead simple; a single HTTP/HTTPS request, and Bob’s your uncle.
And because of cost; a free DDNS platform is highly preferred.
I settled on these two DDNS providers:
For these reasons:
- Free (for this type of use)
- Supports updating via HTTPS request
- Community made container for Duck DNS. More on this later
- Signup with GitHub
- Token/separate credentails used for HTTPS requests
- I like the duck
Support structure
With this device being far away, being able to just zip over and just do something real quick is not an option. We are talking ~24hour round trip by car. Therefore, some kind of support structure has to be in place. In this case I am defining support structure as (most-to-least important):
- Establishing a remote connection for basic tools, such as ssh and scp
- Having functionality that separates device management from applications
- Being able to update and roll back software versions
- Management for multiple devices
I could set this all up using existing open source tools and software, however, the part about the family member wanting to “monitor” the implementation falls down this alley. With ssh not being user friendly for someone that is “not good with computers”, I am begrudginly leaning towards some kind of all-in-one IoT platform.
Fortunately, or more like unfortunately, I have had the pleasure of working with some of these platforms in my career.
The one I ended up choosing for this project is not one I endorse, but I can not really say I disprove of it either; balena.io
It has all the bells and whistles one could ask for, but most importantly for this project: it is free (for this kind of use)
Basic explanation of what balena is and how it works:
- Supports certain types of devices. Compatible devices found here
- Each device gets loaded with a project-specific image of balenas own os, called balenaOS
- The device will connect to balenas cloud, be discovered, and automatically added to the aformentioned project
- Management of the device happens through the dashboard provided by balena
Device
I could use an existing device on the local home network, as mentioned before, but this is a one-time cost I am happy to pay. The device I am looking for for this project should match these criterias:
- Inexpensive or disposable/consumable
- Available and off-the-shelf
- Reliable (read: tested and supported, now and in the future)
- Able to run a simple service/application
- Compatible with the support structure (balena.io)
And the winner is, to my great dismay, a Raspberry Pi… ugh
Don’t get me wrong, they are useful for what they are, I just don’t like them. In fact, I really don’t like them, and I will give you some heavily biased reasons why:
- They started out as toys (a way to learn computers), and they are still toys today, just very vetted toys
- They are boring because they are in every blog and vlog as the bog standard computing device to throw at any home project with a low budget (exactly like this one)
- Since entry level engineers think they are great and/or used them in school, they get used in all kinds of “professional” products
- The penny pinchers love the price, and I hate the penny pinchers
Unfortunately, there really is no other competitor that can beat them on price, availability, and support.
I guess I just want something fresh, but for now a Raspberry Pi will do…
Application
Some software is needed for the DDNS implementation. The actual HTTP/HTTPS request is simple, but some more potatoes are needed. Particularly the scheduling and/or triggering of the request periodically. The container shell is also needed.
Luckily, as mentioned before, LinuxServer.io have made a simple free and open source docker image for Duck DNS called docker-duckdns under the GNU general public license.
The same container can be easily modified to work for other DDNS services, such as dynu.
Solution
Note: Two devices was used in this project; one for local use, and one to send off. This way, changes can be tested locally before pushing them to the unreachable device. Instructions will reflect this.
Design
Setting up DDNS providers
DuckDNS
- Register at duckdns.org. I used GitHub credentials
- Add domain(s). I added something similar to this:
- ProjectName
- ProjectNameDemo
- Copy the token from the site. Keep it for later
Dynu {d}DNS
- Register at dynu.com. I used GitHub credentials
- Navigate to DDNS Services
- Choose whatever option suits you. I chose option 1 (using their domain name)
- Add domain(s). I added something similar to this:
- ProjectName.freeddns.org
- ProjectNameDemo.freeddns.org
- When viewing one particular DNS entry, there is a link at the bottom to set IP Update Password. The same page can be found at
Control Panel → Control Panel → My Account → Username/Password
- Type in your
Current Password
, and a different “loosable” inNew IP Update Password
as well asConfirm New IP Update Password
. This newIP password
will potentially be sent over HTTP! Hopefully only over HTTPS and hashed, but consider this password as leaked. Misuse is limited to messing with the settable IP of you domain entires. - Navigate to IP Update Protocol via
DDNS → IP Update Protocol
- This page describes the basics of Dynus updating protocol using HTTP/HTTPS requests instead of their API. Read it if you like.
- Dynu can use clear text passwords (please don’t) and MD5 hashed passwords when updating over HTTP/HTTPS. Either hash your password to MD5 using your favorite hasher, or use the hasher on Dynu:
- Navigate to Dynu Hash via the page for IP Update Protocol or
Control Panel → Network Tools → Hash
- Type the
IP Update Password
created earlier into the big text box in the center - Press the putton for
MD5 Hash
- Copy the output string that appears above the text boy in white with grey background. Keep it for later
- Close the webpage, as a password in clear text is visible
- Navigate to Dynu Hash via the page for IP Update Protocol or
Support structure
Getting connected with Balena:
- Register at Balena-cloud.com. I used GitHub credentials
- Create a fleet (read: project). Setting a default device type is required.
- Add device. I chose:
- Device type: default
- Select OS type: default
- Select version: default / recommended
- Select edition: Development
- Network: Ethernet only
- Advanced settings: default
- Choose Flash or Download balenaOS. I downloaded
- Flash the image, either downloaded or from the web, to the SD-card intended for the Raspberry Pi
This is the bare minimum to get the device connected to the Balena platform. You should now skip ahead to setup the device and come back later, somewhere in the DDNS setup, as some of these steps are unavailable until software is pushed to Balena.
Setting up variables in Balena:
The device needs credentials/token and DDNS entry details to connect and update the DDNS entry, and this has to be stored/available for the device to use. To avoid baking these credentials and details into the image of the device, variables in Balena can be used.
There are two types of variables in balena:
- Fleet Variables (global variables / project wide variable)
- Device Variables
In terms of scalability, if multiple devices were to report one IP-address each, then storing this information in the section named Variables will make all devices update the same DDNS entry. The result will be one DDNS entry which constantly changed IP-address from each device, which could not be used to anything. Therefore, each device need at least their own entry/ies to differentiate between devices, IP-addresses, and entries.
Clicking on a specific device will show Device Variables instead. Storing credentials here will allow each device to use the same variable name/path, while still having different values between devices.
Create the following device variables:
Credentials for
Device
Nothing to write home about here:
- A case for the raspberry is used to improve physical handling of the device
- SD-card is loaded with the base image of the project from Balena.io is inserted
- Ethernet with internet access is connected
- Power is connected
The device automatically shows up under the project in Balena.io as a new device
DDNS setup
Forking LinuxServer.io - docker-duckdns