RaspberryPi tethered to iPad personal hotspot via usb

Hi,
I would like to use the iPad personal hotspot to connect a raspberryPi to the internet via USB tethering.
I found a pretty old guide:
http://www.vk3erw.com/index.php/16-software/23-raspberry-pi-tethered-to-iphone-5

I’m wondering if that will work with Balena though and eventually how should I configure the networking settings.
Any help will be very useful,
thanks,
Enrico

Hi @enricopenzo , I don’t have an iphone or ipad, but just tested usb tethering with my Google pixel 2, it just works out the box. I just had to plug it into my RPI3, and then enable usb tethering when prompted. This then creates a usb0 interface on the RPI3 that gets an IP. This is super cool, didn’t know it was possible. I would imagine the iphone should be as easy, but I can’t say for sure. balenaOS runs networkManager similar to ubuntu, so you might also have luck if you google usb tether for ubuntu and iphone.

Thanks @shaunmulligan, it sounds promising!
I tried with both iphone and google pixel but not luck so far.
Do you mind to share your networking settings?
I download a balena image with both wifi and ethernet enabled,
many thanks

Sorry, just to clarify, when you say “enable usb tethering when prompted” do you mean through the mobile device interface or raspberry pi display?
I’m running and headless pi at the moment so I can’t see the pi display

Sorry, yeah i had to enable usb tethering from my Google pixel. When i plug my phone into the RPi3, it makes the “charging chime sound” and i have a notification that says “CHarging this device via USB, tap for more options”. if i tap that notifications, i get into the USB preferences page and on that there is an option to select “USB tethering”. Once that is a enabled, i get a second notification that says “Tethering or hotspot active. Tap to set up” and again tapping that takes you to the Hotspot & tethering page and you need to enable “USB tethering” there as well.

that worked! thanks
Now I have to find a way to make it work with an iphone or ipad

Awesome! glad that helped, let us know how you get on with the iphone side, I’m sure we can find someone on the team that has an iphone to help debug :slight_smile:

Hi, I managed to use an iPhone installing some packages:
ipheth-utils libimobiledevice-dev libimobiledevice-utils ifuse usbmuxd

To make it work I have to manually run usbmuxd
I’m now trying to startup usbmuxd in the background on boot.

I read that’s usually done with systemctl:
systemctl enable usbmuxd
systemctl start usbmuxd

However, since I have a multicontainer application it looks like systemd is not longer there:
https://www.balena.io/docs/reference/base-images/base-images/#installing-your-own-initsystem

I tried to install systemd but it’s not working, I think there might be some conflicts with my NGINX setup.
Do you guys know if there are other alternatives to systemctl I can use in this circumstance?
thanks

Hi there,

Without seeing your Dockerfile/docker-compose setup I might be mistaken, but you should be able to use NGINX in a systemd enabled container by dropping in the following unit file: https://www.nginx.com/resources/wiki/start/topics/examples/systemd/

Depending on the base image you’re using, this might be helpful (this is a project of ours that installs NGINX into a container with systemd already enabled): https://github.com/balena-io/balena-base-ui/blob/master/Dockerfile

This should hopefully allow you to install both in your Dockerfile, use systemd for your init system and therefore use the usbmuxd libraries as intended. If there are any more details you can give us as to why NGINX doesn’t seem to want to coexist, we might be able to offer some more ideas!

Best regards, Heds

thanks, I’m trying to use the suggested base image but I’m getting an error:
[nginx] The command '/bin/sh -c echo 'deb http://deb.debian.org/debian jessie main' >> /etc/apt/sources.list && wget -q -O - https://nginx.org/keys/nginx_signing.key | apt-key add - && echo 'deb http://nginx.org/packages/debian/ stretch nginx' >> /etc/apt/sources.list && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list && wget -q -O - https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && echo 'deb https://dl.yarnpkg.com/debian/ stable main' >> /etc/apt/sources.list && apt-get update -y && apt-get -t jessie install rpl && apt-get install yarn=${YARN_VERSION} google-chrome-stable nginx=${NGINX_VERSION} -y && rm /etc/init.d/nginx && rm -rf /etc/nginx/conf.d/* && rm -rf /var/lib/apt/lists/* && systemctl mask nginx.service' returned a non-zero code: 2

any ideas?
thanks

here’s my docker compose:

version: '2'
volumes: 
    resin-data:
services:
  node:
    build: ./node
    expose:
      - "8080"
      - "631"
    volumes: 
      - 'resin-data:/data'
    privileged: true
    restart: always
    network_mode: host
    environment:
      - UDEV=1
    devices:
      - '/dev:/dev'
  nginx:
    build: ./nginx
    depends_on:
      - node
    ports:
      - "80"
    privileged: true
    restart: always
    network_mode: host

and docker.template for nginx

FROM balena/open-balena-base:v7.2.1

ENV NGINX_VERSION 1.14.2-1~stretch
ENV YARN_VERSION 1.13.0-1

# Note that we stop nginx from being available in systemd, as we run it manually in downstream images
RUN echo 'deb http://deb.debian.org/debian jessie main' >> /etc/apt/sources.list \
	&& wget -q -O - https://nginx.org/keys/nginx_signing.key | apt-key add - \
	&& echo 'deb http://nginx.org/packages/debian/ stretch nginx' >> /etc/apt/sources.list \
	&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
	&& echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list \
	&& wget -q -O - https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
	&& echo 'deb https://dl.yarnpkg.com/debian/ stable main' >> /etc/apt/sources.list \
	&& apt-get update -y \
	&& apt-get -t jessie install rpl \
	&& apt-get install yarn=${YARN_VERSION} google-chrome-stable nginx=${NGINX_VERSION} -y \
	&& rm /etc/init.d/nginx \
	&& rm -rf /etc/nginx/conf.d/* \
	&& rm -rf /var/lib/apt/lists/* \
	&& systemctl mask nginx.service

RUN apt-get update && \
    apt-get install telnet nano cups iputils-ping less kmod nano net-tools ifupdown i2c-tools usbutils wget curl ipheth-utils libimobiledevice-dev libimobiledevice-utils ifuse usbmuxd && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*


# Copies the package.json first for better cache on later pushes
COPY package.json package.json

COPY start.sh start.sh
COPY nginx.conf /etc/nginx/nginx.conf


# This will copy all files in our root to the working  directory in the container
COPY . /usr/share/nginx/html/

# Enable systemd init system in container
ENV INITSYSTEM on

CMD ["bash", "start.sh"]

Hi,

Sorry, I probably confused matters. I’d suggest not using that base image because it’s specifically tailored for an AMD64 image, but rolling your own as per the instructions to add systemd referenced earlier. I was just pointing at how we install NGINX alongside systemd in one of our own images. You probably want something like this:

FROM balenalib/amd64-debian:jessie

# Install Systemd
ENV container docker

RUN curl https://nginx.org/keys/nginx_signing.key | apt-key add - \
	&& echo 'deb http://nginx.org/packages/debian/ jessie nginx' >> /etc/apt/sources.list \
    && apt-get update && apt-get install -y --no-install-recommends \
        systemd \
        nginx \
    && rm -rf /var/lib/apt/lists/*

# We never want these to run in a container
# Feel free to edit the list but this is the one we used
RUN systemctl mask \
    dev-hugepages.mount \
    sys-fs-fuse-connections.mount \
    sys-kernel-config.mount \
    display-manager.service \
    getty@.service \
    systemd-logind.service \
    systemd-remount-fs.service \
    getty.target \
    graphical.target

COPY entry.sh /usr/bin/entry.sh

STOPSIGNAL 37
VOLUME ["/sys/fs/cgroup"]
ENTRYPOINT ["/usr/bin/entry.sh"]

# Do things with NGINX config here...

With a relevant entry.sh file. Does this make more sense?

Best regards, Heds

Yes, it makes sense.
I tried to adapt the nginx docker template as follow:

    FROM balenalib/rpi-raspbian:stretch

    # Install Systemd
    RUN apt-get update && apt-get install -y --no-install-recommends \
            systemd \
            systemd-sysv \
        && rm -rf /var/lib/apt/lists/*

    ENV container docker

    RUN curl https://nginx.org/keys/nginx_signing.key | apt-key add - \
    	&& echo 'deb http://nginx.org/packages/debian/ stretch nginx' >> /etc/apt/sources.list \
        && apt-get update && apt-get install -y --no-install-recommends \
            systemd \
            nginx \
        && rm -rf /var/lib/apt/lists/*

    # We never want these to run in a container
    # Feel free to edit the list but this is the one we used
    RUN systemctl mask \
        dev-hugepages.mount \
        sys-fs-fuse-connections.mount \
        sys-kernel-config.mount \

        display-manager.service \
        getty@.service \
        systemd-logind.service \
        systemd-remount-fs.service \

        getty.target \
        graphical.target \
        kmod-static-nodes.service

    COPY entry.sh /usr/bin/entry.sh
    COPY resin.service /etc/systemd/system/resin.service

    RUN systemctl enable resin.service

    STOPSIGNAL 37
    ENTRYPOINT ["/usr/bin/entry.sh"]


    RUN apt-get update && \
        apt-get install telnet nano iputils-ping less kmod net-tools ifupdown i2c-tools usbutils wget curl ipheth-utils libimobiledevice-dev libimobiledevice-utils ifuse usbmuxd && \
        apt-get clean && \
        rm -rf /var/lib/apt/lists/*

    COPY nginx.service /lib/systemd/system/nginx.service

    # Copies the package.json first for better cache on later pushes
    COPY package.json package.json

    COPY start.sh start.sh
    COPY nginx.conf /etc/nginx/nginx.conf


    # This will copy all files in our root to the working  directory in the container
    COPY . /usr/share/nginx/html/

    # Enable systemd init system in container
    ENV INITSYSTEM on

    CMD ["bash", "start.sh"]

Unfortunately the container is not starting.
I might have done some rookie mistake, I’m still pretty new with docker, etc
Any help would be really appreciated

Hey there,

I’m noticing you have both an ENTRYPOINT and a CMD command in your Dockerfile, while one should suffice. Can you also share with us the content of the scripts in either ENTRYPOINT o CMD? One of the most common issues is having an entry point that exits, as that will make the container exit, and what you can do is make the script sleep forever.

Sure, here’s the entry.sh script downloaded from your example:

#!/bin/bash

set -m

if hostname "$HOSTNAME" &> /dev/null; then
	PRIVILEGED=true
else
	PRIVILEGED=false
fi

# Send SIGTERM to child processes of PID 1.
function signal_handler()
{
	kill "$pid"
}

function start_udev()
{
	if [ "$UDEV" == "on" ]; then
		if [ "$INITSYSTEM" != "on" ]; then
			if command -v udevd &>/dev/null; then
				unshare --net udevd --daemon &> /dev/null
			else
				unshare --net /lib/systemd/systemd-udevd --daemon &> /dev/null
			fi
			udevadm trigger &> /dev/null
		fi
	else
		if [ "$INITSYSTEM" == "on" ]; then
			systemctl mask systemd-udevd
		fi
	fi
}

function mount_dev()
{
	tmp_dir='/tmp/tmpmount'
	mkdir -p "$tmp_dir"
	mount -t devtmpfs none "$tmp_dir"
	mkdir -p "$tmp_dir/shm"
	mount --move /dev/shm "$tmp_dir/shm"
	mkdir -p "$tmp_dir/mqueue"
	mount --move /dev/mqueue "$tmp_dir/mqueue"
	mkdir -p "$tmp_dir/pts"
	mount --move /dev/pts "$tmp_dir/pts"
	touch "$tmp_dir/console"
	mount --move /dev/console "$tmp_dir/console"
	umount /dev || true
	mount --move "$tmp_dir" /dev

	# Since the devpts is mounted with -o newinstance by Docker, we need to make
	# /dev/ptmx point to its ptmx.
	# ref: https://www.kernel.org/doc/Documentation/filesystems/devpts.txt
	ln -sf /dev/pts/ptmx /dev/ptmx
	mount -t debugfs nodev /sys/kernel/debug
}

function init_systemd()
{
	GREEN='\033[0;32m'
	echo -e "${GREEN}Systemd init system enabled."
	for var in $(compgen -e); do
		printf '%q=%q\n' "$var" "${!var}"
	done > /etc/docker.env
	echo 'source /etc/docker.env' >> ~/.bashrc

	printf '#!/bin/bash\n exec ' > /etc/resinApp.sh
	printf '%q ' "$@" >> /etc/resinApp.sh
	chmod +x /etc/resinApp.sh

	mkdir -p /etc/systemd/system/resin.service.d
	cat <<-EOF > /etc/systemd/system/resin.service.d/override.conf
		[Service]
		WorkingDirectory=$(pwd)
	EOF

	sleep infinity &
	exec env DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket /sbin/init quiet systemd.show_status=0
}

function init_non_systemd()
{
	# trap the stop signal then send SIGTERM to user processes
	trap signal_handler SIGRTMIN+3 SIGTERM

	# echo error message, when executable file doesn't exist.
	if CMD=$(command -v "$1" 2>/dev/null); then
		shift
		"$CMD" "$@" &
		pid=$!
		wait "$pid"
		exit_code=$?
		fg &> /dev/null || exit "$exit_code"
	else
		echo "Command not found: $1"
		exit 1
	fi
}

INITSYSTEM=$(echo "$INITSYSTEM" | awk '{print tolower($0)}')

case "$INITSYSTEM" in
	'1' | 'true')
		INITSYSTEM='on'
	;;
esac

if $PRIVILEGED; then
	# Only run this in privileged container
	mount_dev
	start_udev
fi

if [ "$INITSYSTEM" = "on" ]; then
	init_systemd "$@"
else
	init_non_systemd "$@"
fi

Start.sh

    #!/bin/bash

    # disable serial console to enable GPIO serial port
    systemctl stop serial-getty@ttyS0.service
    systemctl disable serial-getty@ttyS0.service

    systemctl enable usbmuxd
    systemctl start usbmuxd

    echo 'allow-hotplug eth1' >> /etc/network/interfaces
    echo 'iface eth1 inet dhcp' >> /etc/network/interfaces

    if [ -z "$NGINX_URL" ]; then 
      echo "No NGINX_URL, using http://192.168.1.111/"; 
    else
      echo "NGINX_URL is set to '$NGINX_URL'"; 
      sed -i -e "s@http:\/\/192.168.1.111@$NGINX_URL@g" /etc/nginx/nginx.conf
    fi
    cat /etc/nginx/nginx.conf
    nginx -g "daemon off;"

Yeah, looks like none of those scripts are sleeping forever at the end, so they would exit and therefore make the container exit. Can you try if making the scripts not exit helps?

Does merging entry.sh and start.sh in one file would fix the issue?
thanks

Hey there,

You need to have one entry point, so you do have to merge the scripts, but that alone doesn’t fix the issue. You need to make your script i.e. sleep forever at the very end to make it not exit.