A hack to change the device hostname

Hi all,

I’ve been having some trouble working out how to change the device hostname properly using the API.

We need this as we have some IoT devices using mDNS to talk to a broker running in a Docker container.

I’ve worked out a hack that may help some.

  • connect to the host OS on the device (i.e not a container app)
  • mount the boot partition as read/write

mount -o remount,rw /mnt/boot

  • edit the config.json file

nano /mnt/boot/config.json

  • add a key-pair to the end of the JSON

,"hostname":"my_new_hostname" }

  • reboot and hey presto you have a new host name

I’d really appreciate some for dummies advice on where to find the API key so I can use the curl mechanism.

Also how to set up multiple containers with docker-compose with support for different hostnames published to the network with mDNS?

Thanks!

Alex

1 Like

Hi,

if you’d like to use curl to change the hostname, you can do it via:

curl -X PATCH -H "Authorization: Bearer $BALENA_SUPERVISOR_API_KEY" \
  -H "Content-Type: application/json" \
  "$BALENA_SUPERVISOR_ADDRESS/v1/device/host-config" \
  -d '{"network":{"hostname":"foo"}}'

You can get / verify it via:

curl -X GET -H "Authorization: Bearer $BALENA_SUPERVISOR_API_KEY" \
  -H "Content-Type: application/json" \
   "$BALENA_SUPERVISOR_ADDRESS/v1/device/host-config"

Supervisor API address is available via BALENA_SUPERVISOR_ADDRESS environment variable and the API key is available via BALENA_SUPERVISOR_API_KEY. Or you can use session token or generated access tokens.

Thanks @zrzka - I hunted high and low for the environment variables but couldn’t find them anywhere in the device. I’m using OpenBalena. Dunno if that makes a difference?

@ajlennon The BALENA_SUPERVISOR_API_KEY should be generated by the supervisor when it starts a container and then it is injected into the container if it has the io.balena.features.supervisor-api: 1 label for that service in the compose.yml. Do you not see this in your service containers?

I don’t think I have this - will check and revert - thanks!

Hey @ajlennon! How did it go in the end?

Hiya,

So having a bit of a look at this now. Couple of bits of feedback

  • so mostly I’m using single containers on OpenBalena so no docker-compose file
  • however I do have one multi-container with a docker-compose I’ll modify

With the current setup with OpenBalena I’m using the SSH forwarding setup to SSH into remote units so this goes into the base image not a container. Given I’m in the base image I’d like to just “run something” to change the hostname but I couldn’t find a way (hence the original post). There are no BALENA_ env vars.

So with that label added to a container definition in my docker compose I see the env vars in the container :slight_smile:

bash-4.4# set | grep BALENA
...
BALENA_SUPERVISOR_ADDRESS=http://172.17.0.1:48484
BALENA_SUPERVISOR_API_KEY=8a....
...

Hmmm - I’m sending

curl -X GET -H Authorization: Bearer 8a....  -H Content-Type: application/json http://172.17.0.1:48484/v1/device/host-config

And getting

Unauthorized

On a side-note while I look at this it would be useful to be able to broadcast different container hostnames via mDNS from a single physical device. Is that possible?

Any thoughts @jviotti?

@ajlennon are you using quotes in -H "Authorization: Bearer <apikey>"? (Not sure if that would cause that error, but just checking)

Hi there @ajlennon,

You should be able to publish container hostnames from a service container on a device with the device’s IP address by using the DBus interface to the Avahi service running on the host.

If you’re running singlecontainer, then this will be privileged and you won’t need to do anything extra apart from installing the DBus library via your Dockerfile. If you’re using multicontainer, you’ll need the io.balena.features.dbus label set. You’ll also need to set the DBus socket address. There’s more information on working with DBus in balena here.

Briefly, using a Debian base image, you should be able to:

RUN apt-get update && \
    apt-get install -yq --no-install-recommends \
    libdbus-glib-1-dev \
    && apt-get clean && rm -rf /var/lib/apt/lists/*

in your Dockerfile to install the DBus library, and then use it in your application to call Avahi via it. In the following snippet, I’m using NodeJS (via TypeScript) and using the dbus-native NPM module (I also use Bluebird here for async callbacks):

import { Message, systemBus } from 'dbus-native';
import * as Bluebird from 'bluebird';
...
const dbus = systemBus();
const dbusInvoker = (message: Message): PromiseLike<any> => {
	return Bluebird.fromCallback(cb => {
		return dbus.invoke(message, cb);
	});
};
...
const group = await dbusInvoker({
		destination: 'org.freedesktop.Avahi',
		path: '/',
		interface: 'org.freedesktop.Avahi.Server',
		member: 'EntryGroupNew',
});

await dbusInvoker({
		destination: 'org.freedesktop.Avahi',
		path: group,
		interface: 'org.freedesktop.Avahi.EntryGroup',
		member: 'AddAddress',
		body: [-1, -1, 0x10, 'myNewHostname', '192.168.1.20'],
		signature: 'iiuss',
});

await dbusInvoker({
		destination: 'org.freedesktop.Avahi',
		path: group,
		interface: 'org.freedesktop.Avahi.EntryGroup',
		member: 'Commit',
});

You should be able to replace myHostname with the container hostname programmatically however you choose, (eg. via require('os').hostname() for NodeJS), and the IP address for the host can easily be achieved by querying the Supervisor API (the device endpoint, here has an ip_address field with the current IP facing IP addresses).

Hopefully this is enough to get you going, let us know if anything’s unclear!

1 Like

Hi @pcarranzav - yes I’m using quotes

That looks great thanks @hedss - I’ll give it a go!

So the ping test works…

curl -X GET --header "Content-Type:application/json" \
    "$BALENA_SUPERVISOR_ADDRESS/ping?apikey=$BALENA_SUPERVISOR_API_KEY"

OK looking at this page I need to provide the key on the GET line

https://www.balena.io/docs/reference/supervisor/supervisor-api/

curl -X GET -H "Authorization: Bearer ${BALENA_SUPERVISOR_API_KEY}" \
  -H "Content-Type: application/json" \
   "${BALENA_SUPERVISOR_ADDRESS}/v1/device/host-config?apikey=${BALENA_SUPERVISOR_API_KEY}"

This works for me…

Hi,
Do you mean that curl "$BALENA_SUPERVISOR_ADDRESS/v1/device/host-config?apikey=$BALENA_SUPERVISOR_API_KEY" didn’t work for you when not specifying an Authorization header?
I can confirm on my side that this works on v2.27.0.
What os/supervisor version are you using?

I have to provide ?apikey= on the GET line or the authorisation isn’t working (i.e. via the header)

That’s weird @ajlennon What os/supervisor version are you using?