diff --git a/README.md b/README.md index de59b63..0aa90ed 100644 --- a/README.md +++ b/README.md @@ -99,19 +99,29 @@ The following environment variables are supported: Defaults to `false` if omitted. Try `true` if NAT does not seem to be working. -* `ZEROTIER_ONE_NETWORK_ID` – auto-join network on first launch. Example: +* `ZEROTIER_ONE_NETWORK_IDS` – auto-join network(s). This variable is only effective on first launch. There is no default if it is omitted. Examples: - ``` yaml - ZEROTIER_ONE_NETWORK_ID=565758596a6b6c44 - ``` + - if using `docker run`: + + ``` console + --env ZEROTIER_ONE_NETWORK_IDS="aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbb" + ``` - This variable is only effective on first launch. There is no default if it is omitted. It is the equivalent of running the following command after the container first starts: + - if using `docker-compose`: + + ``` yaml + environment: + - ZEROTIER_ONE_NETWORK_IDS=aaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbb + ``` + + In each case, it is the equivalent of running the following commands after the container first starts: ``` - $ docker exec zerotier zerotier-cli join 565758596a6b6c44 + $ docker exec zerotier zerotier-cli join aaaaaaaaaaaaaaaa + $ docker exec zerotier zerotier-cli join bbbbbbbbbbbbbbbb ``` - It does not matter whether you use this environment variable or the `join` command, you still need to authorize the computer in ZeroTier Central. + It does not matter whether you use this environment variable or the `join` command, you still need to authorize the computer for each network in ZeroTier Central. #### Source diff --git a/docker-compose-router.yml b/docker-compose-router.yml index 2b0c4a3..35dfcfa 100644 --- a/docker-compose-router.yml +++ b/docker-compose-router.yml @@ -19,4 +19,4 @@ services: - PGID=994 - ZEROTIER_ONE_LOCAL_PHYS=eth0 - ZEROTIER_ONE_USE_IPTABLES_NFT=false - # - ZEROTIER_ONE_NETWORK_ID=yourNetworkID + # - ZEROTIER_ONE_NETWORK_IDS=yourNetworkID diff --git a/scripts/entrypoint-router.sh b/scripts/entrypoint-router.sh index f8fdbdc..dd137f2 100755 --- a/scripts/entrypoint-router.sh +++ b/scripts/entrypoint-router.sh @@ -2,6 +2,7 @@ set -Eeo pipefail echo "$(date) - launching ZeroTier-One in routing mode" +echo "command and args: $@" if [ "${1:0:1}" = '-' ]; then set -- zerotier-one "$@" @@ -9,24 +10,26 @@ fi # useful paths CONFIG_DIR="/var/lib/zerotier-one" -NETWORKS_DIR="$CONFIG_DIR/networks.d" +NETWORKS_DIR="${CONFIG_DIR}/networks.d" # set up network auto-join if (a) the networks directory does not exist -# and (b) the ZEROTIER_ONE_NETWORK_ID environment variable is non-null. -if [ ! -d "$NETWORKS_DIR" -a -n "$ZEROTIER_ONE_NETWORK_ID" ] ; then - echo "Assuming container first run. Configuring auto-join of network ID:" - echo " $ZEROTIER_ONE_NETWORK_ID" - echo "You will need to authorize this host at:" - echo " https://my.zerotier.com/network/$ZEROTIER_ONE_NETWORK_ID" - mkdir -p "$NETWORKS_DIR" - touch "$NETWORKS_DIR/$ZEROTIER_ONE_NETWORK_ID.conf" +# and (b) the ZEROTIER_ONE_NETWORK_IDS environment variable is non-null. +if [ ! -d "${NETWORKS_DIR}" -a -n "${ZEROTIER_ONE_NETWORK_IDS}" ] ; then + echo "Assuming container first run." + mkdir -p "${NETWORKS_DIR}" + for NETWORK_ID in ${ZEROTIER_ONE_NETWORK_IDS} ; do + echo "Configuring auto-join of network ID: ${NETWORK_ID}" + touch "${NETWORKS_DIR}/${NETWORK_ID}.conf" + echo "You will need to authorize this host at:" + echo " https://my.zerotier.com/network/${NETWORK_ID}" + done fi # make sure permissions are correct PUID="${PUID:-"999"}" PGID="${PGID:-"994"}" -if [ "$(id -u)" = '0' -a -d "$CONFIG_DIR" ]; then - chown -Rc "$PUID:$PGID" "$CONFIG_DIR" +if [ "$(id -u)" = '0' -a -d "${CONFIG_DIR}" ]; then + chown -Rc "${PUID}:${PGID}" "${CONFIG_DIR}" fi # use an appropriate default for a local physical interface @@ -35,19 +38,77 @@ PHY_IFACES="${ZEROTIER_ONE_LOCAL_PHYS:-"eth0"}" # default to iptables (maintain compatibility for existing systems) IPTABLES_CMD=iptables # but support override to use iptables-nft -[ "$ZEROTIER_ONE_USE_IPTABLES_NFT" = "true" ] && IPTABLES_CMD=iptables-nft +[ "${ZEROTIER_ONE_USE_IPTABLES_NFT}" = "true" ] && IPTABLES_CMD=iptables-nft # the wildcard for the local zerotier interface is ZT_IFACE="zt+" -# iterate the local interface(s) and enable NAT services -for PHY_IFACE in $PHY_IFACES ; do - echo "Using $IPTABLES_CMD to enable NAT services on $PHY_IFACE" - $IPTABLES_CMD -t nat -A POSTROUTING -o $PHY_IFACE -j MASQUERADE - $IPTABLES_CMD -A FORWARD -i $PHY_IFACE -o $ZT_IFACE -m state --state RELATED,ESTABLISHED -j ACCEPT - $IPTABLES_CMD -A FORWARD -i $ZT_IFACE -o $PHY_IFACE -j ACCEPT -done +# a script to add and remove the requisite rules - $1 is either "A" or "D" +update_iptables() { -# launch zerotier-one -exec "$@" + # iterate the local interface(s) and enable NAT services + for PHY_IFACE in ${PHY_IFACES} ; do + ${IPTABLES_CMD} -t nat -${1} POSTROUTING -o ${PHY_IFACE} -j MASQUERADE + ${IPTABLES_CMD} -${1} FORWARD -i ${PHY_IFACE} -o ${ZT_IFACE} -m state --state RELATED,ESTABLISHED -j ACCEPT + ${IPTABLES_CMD} -${1} FORWARD -i ${ZT_IFACE} -o ${PHY_IFACE} -j ACCEPT + done +} + +# add rules to set up routing +echo "Using ${IPTABLES_CMD} to enable NAT services on ${PHY_IFACES}" +update_iptables "A" + +# define where the ZeroTier daemon will write its output (if any) +PIPE=$(mktemp /tmp/zerotier-ipc-XXXXXX) + +# start listening and echoing anything that appears there into this process +tail -f "${PIPE}" & + +# make a note of the process ID for tail +TAIL_PIPE_PID=${!} + +# report +echo "tail has started with PID=${TAIL_PIPE_PID} listening to ${PIPE}" + +# now start the ZeroTier daemon in detached state +nohup "$@" "${PIPE}" 2>&1 & + +# make a note of the process ID +ZEROTIER_DAEMON_PID=${!} + +# report +echo "ZeroTier daemon has PID ${ZEROTIER_DAEMON_PID}" + +echo "Setting up trap" +trap 'echo "**INT" ; kill -TERM ${ZEROTIER_DAEMON_PID}' INT +trap 'echo "**TERM" ; kill -TERM ${ZEROTIER_DAEMON_PID}' TERM +trap 'echo "**HUP" ; kill -TERM ${ZEROTIER_DAEMON_PID}' HUP + +trap 'echo "**EXIT-nohandler"' EXIT +trap 'echo "**ABRT-nohandler"' ABRT +trap 'echo "**QUIT-nohandler"' QUIT +trap 'echo "**TRAP-nohandler"' TRAP + +echo "now waiting on ZeroTier daemon" +wait ${ZEROTIER_DAEMON_PID} +echo "the ZeroTier daemon has gone away - cleaning up" + +# kill the tail listener +echo "Killing tail listener" +kill -TERM ${TAIL_PIPE_PID} + +# wait for it to go away +echo "Waiting for tail listener to go away" +wait ${TAIL_PIPE_PID} + +# which means we are done with the pipe +echo "removing pipe" +rm "${PIPE}" + +# remove rules used to set up routing +echo "Using ${IPTABLES_CMD} to disable NAT services on ${PHY_IFACES}" +update_iptables "D" + +# using the sigterm is a normal exit for us so exit with 0 +echo "all done"