I wanted to run Zerotier on a Pi running Libreelec so a remote device (the Pi) could access content stored in another city
The Zerotier network is "private" ie. every node must be authorised to access the network.
I found a docker image which delivers Zerotier functionality on a Raspberry Pi --> bltavares zerotier docker image
After installing the Docker addon and the above docker image, Zerotier is running BUT it will issue a new zerotier address each time Librelec reboots and this is not useable for a private Zerotier network because the new address will have to be authorised (on each reboot) ... not much use for a remote device
It turns out that -
1. There are 3 key files in the docker container which need to be "preserved" between boot sessions
- /var/lib/zerotier-one/identity.public
- /var/lib/zerotier-one/identity.secret
- /var/lib/zerotier-one/authtoken.secret
2. The container needs to "connect" to the network anew on each boot, once the above files are restored and the container has been restarted
With that understanding we can retain the same ZeroTier node address and authorisation
Additionally I have a need to mount some directories from a remote host ... so we do that after reconnecting the container to ZT
The steps are
* install the docker addon in Libreelec using the menu system
o From addons/install from repository/libreelec addons/services/docker
* log in via ssh and install the docker container
> docker pull bltavares/zerotier
then install the ZeroTier container
docker run --device=/dev/net/tun \
--net=host \
--cap-add=NET_ADMIN \
--cap-add=SYS_ADMIN \
-v /var/lib/zerotier-one:/var/lib/zerotier-one \
--restart always \
--name zerotier-one \
-d bltavares/zerotier
* Now check and record the ZT node id (referred to as <node-id> later
> docker exec zerotier-one zerotier-cli info
* Join your network - and authorise this node using the tools at ZeroTier Central
> docker exec zerotier-one join <your network id>
* Then copy the 3 key files off to a new directory
> mkdir /storage/.kodi/userdata/<your_dir>
> mkdir /storage/.kodi/userdata/<your_dir>/zerotier
> TEMP=$(docker exec zerotier-one cat /var/lib/zerotier-one/identity.public);echo $TEMP > /storage/.kodi/userdata/<your_dir>/zerotier/identity.public
> TEMP=$(docker exec zerotier-one cat /var/lib/zerotier-one/identity.secret);echo $TEMP > /storage/.kodi/userdata/<your_dir>/zerotier/identity.secret
> TEMP=$(docker exec zerotier-one cat /var/lib/zerotier-one/authtoken.secret);echo $TEMP > /storage/.kodi/userdata/<your_dir>/zerotier/authtoken.secret
* Now we need to create/update the Libreelec autostart.sh
> nano /storage/.config/autostart.sh
Paste the following after existing code (add "#!/bin/sh" at the first line if this is a new file and execute chown ug+x /storage/.config/autostart.sh after saving it).
You may wish to improve this code ... I hacked this together with my limited understanding of shell scripts and I left everything really basic and simple to aid understanding (and debugging). The main thing is that it seems to work and was reasonably easy to debug
You will also need to replace the <node-id> and <network-id> values with your ids and <your-dir> with the name of the directory you created above
#!/bin/sh
#
# https://hub.docker.com/r/bltavares/zerotier
# https://cwilko.github.io/home%20automation/2017/02/28/Raspberry-Pi-Home-Server.html
# DO NOT MAKE CONFIG CHANGE DESCRIBED IN ABOVE LINK
# https://github.com/zerotier/ZeroTierOne/issues/868
#
#
# Start Docker
# From "docker images" command
# bltavares/zerotier latest dc402527ab88 11 months ago 12.8MB
# From "docker ps" command to list containers
# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
# <your id> bltavares/zerotier "/usr/sbin/zerotier-…" 9 minutes ago Up 9 minutes zerotier-one
#
# Leave a record of the last time we started (for debugging)
echo START $( date) > /storage/.kodi/userdata/<your_dir>/start_script.txt
# Ensure docker is started
systemctl start docker
sleep 2
# Write our "Standard" public key
TEMP1A="echo $(cat /storage/.kodi/userdata/<your_dir>/zerotier/identity.public) > /var/lib/zerotier-one/identity.public"
TEMP1B="/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one "$TEMP1A
eval $TEMP1B
# TEMP1C="/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one cat /var/lib/zerotier-one/identity.public"
# eval $TEMP1C
# Now write our "Standard" private key
TEMP2A="echo $(cat /storage/.kodi/userdata/<your_dir>/zerotier/identity.secret) > /var/lib/zerotier-one/identity.secret"
TEMP2B="/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one "$TEMP2A
eval $TEMP2B
# TEMP2C="/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one cat /var/lib/zerotier-one/identity.secret"
# eval $TEMP2C
# Now wite our "Standard" authorisation private key
TEMP3A="echo $(cat /storage/.kodi/userdata/<your_dir>/zerotier/identity.secret) > /var/lib/zerotier-one/authtoken.secret"
TEMP3B="/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one "$TEMP2A
eval $TEMP3B
# TEMP3C="/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one cat /var/lib/zerotier-one/authtoken.secret"
# eval $TEMP3C
#
docker stop zerotier-one
sleep 1
# Hopefully this will guarantee the container MAC address ... and therefore the zerotier node id
ifconfig docker0 hw ether "<my MAC address"
sleep 1
docker start zerotier-one
#sleep 2
# docker exec zerotier-one zerotier-cli info
# DON'T DO THIS (resets id !) docker exec zerotier-one zerotier-cli join <ZT network id>
#
# Now mount all the required foreign mounts (look in system.d directory for the 3 definitions)
ZT_ONLINE='200 info <node-id> 1.2.12 ONLINE'
echo "ENTERING LOOP"
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
#for i in {1..40}
do
TEMP=$(/storage/.kodi/addons/service.system.docker/bin/docker exec zerotier-one zerotier-cli info )
echo $i '->' $TEMP
# if [ $TEMP == $ZT_ONLINE ]
if test "$TEMP" == "$ZT_ONLINE"; then
echo BREAKING
break
else
echo "NO BREAK waiting for ZT to be online sleeping 1"
sleep 1
fi
echo after if
done
docker exec zerotier-one zerotier-cli join <network-id>
# Now check for network adapter
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
do
TEMP=$(ifconfig|grep ztb)
if ifconfig |grep ztb ;then
echo "Zerotier connected"
break
else
echo "NO BREAK waiting for ZT network adapter sleeping 1"
sleep 1
fi
done
echo EXITED LOOP
# Now we should have a connected container, ready for VPN access. I added custom mounts via systemd using the examples provided by Libreelec in /storage/.config/system.d
sleep 4
systemctl start var-media*
# Leave a record of the last time we finished (for debugging)
echo FINISH $( date) >> /storage/.kodi/userdata/<your_dir>/start_script.txt
Display More
Note that the above code will deliberately slow the boot process with the "sleep" commands. Not an issue for my remove device and it improved the reliability of the network connection and mounts
You can run the above code from the command line to check that it "compiles" and runs ok .... and that it doesn't make a mess. Then try a reboot to prove that ZT will automagically connect again on reboot.
* Reboot and check that we are connected back to the ZeroTier network
> reboot
Then ssh back into the machine (reboot will have logged you out of the previous session)
* Check we have the expected node id
docker exec zerotier-one zerotier-cli info
* Check there is a "ztb....." adapter listed ... and an appropriate IP address for it
ifconfig
If you have the wrong node id or there's no zt adapter you'll need to start debugging to see what's wrong