You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
10 KiB
313 lines
10 KiB
#!/bin/bash
|
|
#
|
|
###############################################################################
|
|
# Copyright (C) 2020 Simon Adlem, G7RZU <g7rzu@gb7fr.org.uk>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation,
|
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
###############################################################################
|
|
|
|
set -e
|
|
|
|
BASE_URL='https://gitlab.hacknix.net/hacknix/FreeDMR/-/raw/master'
|
|
|
|
prompt_value()
|
|
{
|
|
prompt_text="$1"
|
|
default_value="$2"
|
|
if [ ! -r /dev/tty ]
|
|
then
|
|
echo "Interactive input is required unless installer values are supplied as environment variables." >&2
|
|
exit 2
|
|
fi
|
|
if [ -n "$default_value" ]
|
|
then
|
|
printf '%s [%s]: ' "$prompt_text" "$default_value" >/dev/tty
|
|
else
|
|
printf '%s: ' "$prompt_text" >/dev/tty
|
|
fi
|
|
read -r entered_value </dev/tty
|
|
if [ -z "$entered_value" ]
|
|
then
|
|
printf '%s' "$default_value"
|
|
else
|
|
printf '%s' "$entered_value"
|
|
fi
|
|
}
|
|
|
|
is_unsigned_integer()
|
|
{
|
|
case "$1" in
|
|
''|*[!0-9]*) return 1 ;;
|
|
*) return 0 ;;
|
|
esac
|
|
}
|
|
|
|
validate_server_id()
|
|
{
|
|
description="$1"
|
|
value="$2"
|
|
if ! is_unsigned_integer "$value" || [ "$value" -lt 1 ] || [ "$value" -gt 4294967295 ]
|
|
then
|
|
echo "$description must be an unsigned non-zero DMR/server ID." >&2
|
|
exit 2
|
|
fi
|
|
}
|
|
|
|
build_data_gateway_relationships()
|
|
{
|
|
count="$1"
|
|
base_id="$2"
|
|
key="$3"
|
|
relationships='['
|
|
number=1
|
|
while [ "$number" -le "$count" ]
|
|
do
|
|
if [ "$count" -eq 1 ]
|
|
then
|
|
server_id="$base_id"
|
|
else
|
|
server_id=$((base_id + number))
|
|
fi
|
|
bind_port=$((62030 + number))
|
|
peer_port=$((62040 + number))
|
|
if [ "$number" -gt 1 ]
|
|
then
|
|
relationships="${relationships},"
|
|
fi
|
|
relationships="${relationships}{\"link_id\":\"hdstack-${number}\",\"bind_host\":\"0.0.0.0\",\"bind_port\":${bind_port},\"peer_host\":\"freedmr\",\"peer_port\":${peer_port},\"peer_network_id\":${server_id},\"direct_source_server_id\":${server_id},\"key\":\"${key}\"}"
|
|
number=$((number + 1))
|
|
done
|
|
printf '%s]' "$relationships"
|
|
}
|
|
|
|
CPU_COUNT=$(getconf _NPROCESSORS_ONLN 2>/dev/null) || CPU_COUNT=2
|
|
if ! is_unsigned_integer "$CPU_COUNT" || [ "$CPU_COUNT" -lt 1 ]
|
|
then
|
|
CPU_COUNT=2
|
|
fi
|
|
DEFAULT_HDSTACK=$((CPU_COUNT - 1))
|
|
if [ "$DEFAULT_HDSTACK" -lt 1 ]
|
|
then
|
|
DEFAULT_HDSTACK=1
|
|
elif [ "$DEFAULT_HDSTACK" -gt 5 ]
|
|
then
|
|
DEFAULT_HDSTACK=5
|
|
fi
|
|
|
|
echo 'FreeDMR Docker installer'
|
|
echo
|
|
echo 'Assigned Server ID, or your own DMR ID if you do not have one.'
|
|
HDSTACK_BASEID="${HDSTACK_BASEID:-}"
|
|
if [ -z "$HDSTACK_BASEID" ]
|
|
then
|
|
HDSTACK_BASEID=$(prompt_value 'Main/aggregator server ID' '')
|
|
fi
|
|
validate_server_id 'Main/aggregator server ID' "$HDSTACK_BASEID"
|
|
|
|
echo
|
|
echo 'Enabling HDStack allows FreeDMR to use more than one CPU core and support more than 100 HBP connections.'
|
|
HDSTACK_COUNT="${HDSTACK:-}"
|
|
if [ -z "$HDSTACK_COUNT" ]
|
|
then
|
|
HDSTACK_COUNT=$(prompt_value 'Number of HDStack workers (1-5)' "$DEFAULT_HDSTACK")
|
|
fi
|
|
if ! is_unsigned_integer "$HDSTACK_COUNT" || [ "$HDSTACK_COUNT" -lt 1 ] || [ "$HDSTACK_COUNT" -gt 5 ]
|
|
then
|
|
echo 'HDSTACK must be an integer from 1 to 5.' >&2
|
|
exit 2
|
|
fi
|
|
if [ $((HDSTACK_BASEID + HDSTACK_COUNT)) -gt 4294967295 ]
|
|
then
|
|
echo 'Main/aggregator ID plus worker IDs exceed the supported ID range.' >&2
|
|
exit 2
|
|
fi
|
|
|
|
HDSTACK_BRIDGE_VALUE="${HDSTACK_BRIDGE:-}"
|
|
if [ -z "$HDSTACK_BRIDGE_VALUE" ]
|
|
then
|
|
HDSTACK_BRIDGE_VALUE=$(prompt_value 'Enable the separate bridge server? (y/N)' 'N')
|
|
fi
|
|
case "$HDSTACK_BRIDGE_VALUE" in
|
|
1|y|Y|yes|YES) HDSTACK_BRIDGE_VALUE=1 ;;
|
|
0|n|N|no|NO) HDSTACK_BRIDGE_VALUE=0 ;;
|
|
*)
|
|
echo 'HDSTACK_BRIDGE must be 0 or 1 (or yes/no).' >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
HDSTACK_BRIDGE_ID="${HDSTACK_BRIDGE_ID:-0}"
|
|
if [ "$HDSTACK_BRIDGE_VALUE" -eq 1 ]
|
|
then
|
|
if [ "$HDSTACK_COUNT" -eq 1 ]
|
|
then
|
|
echo 'The separate bridge process requires HDSTACK to be 2..5.' >&2
|
|
exit 2
|
|
fi
|
|
if [ "$HDSTACK_BRIDGE_ID" -eq 0 ] 2>/dev/null
|
|
then
|
|
echo
|
|
echo 'The bridge server requires its own assigned server ID.'
|
|
HDSTACK_BRIDGE_ID=$(prompt_value 'Bridge server ID' '')
|
|
fi
|
|
validate_server_id 'Bridge server ID' "$HDSTACK_BRIDGE_ID"
|
|
if [ "$HDSTACK_BRIDGE_ID" -ge "$HDSTACK_BASEID" ] &&
|
|
[ "$HDSTACK_BRIDGE_ID" -le $((HDSTACK_BASEID + HDSTACK_COUNT)) ]
|
|
then
|
|
echo 'Bridge server ID must not duplicate the aggregator or a worker ID.' >&2
|
|
exit 2
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo 'The separate Data Gateway provides D-APRS and future packet-data services.'
|
|
FREEDMR_GATEWAY_APRS_LOGIN_CALL="${FREEDMR_GATEWAY_APRS_LOGIN_CALL:-}"
|
|
if [ -z "$FREEDMR_GATEWAY_APRS_LOGIN_CALL" ]
|
|
then
|
|
FREEDMR_GATEWAY_APRS_LOGIN_CALL=$(prompt_value 'APRS-IS login callsign' '')
|
|
fi
|
|
case "$FREEDMR_GATEWAY_APRS_LOGIN_CALL" in
|
|
''|*[!A-Za-z0-9-]*)
|
|
echo 'APRS-IS login callsign may contain only letters, digits and a hyphen.' >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
if [ "${#FREEDMR_GATEWAY_APRS_LOGIN_CALL}" -gt 9 ]
|
|
then
|
|
echo 'APRS-IS login callsign must not exceed 9 characters.' >&2
|
|
exit 2
|
|
fi
|
|
|
|
FREEDMR_GATEWAY_APRS_PASSCODE="${FREEDMR_GATEWAY_APRS_PASSCODE:-}"
|
|
if [ -z "$FREEDMR_GATEWAY_APRS_PASSCODE" ]
|
|
then
|
|
FREEDMR_GATEWAY_APRS_PASSCODE=$(prompt_value 'APRS-IS passcode' '')
|
|
fi
|
|
if ! is_unsigned_integer "$FREEDMR_GATEWAY_APRS_PASSCODE"
|
|
then
|
|
echo 'APRS-IS passcode must be numeric.' >&2
|
|
exit 2
|
|
fi
|
|
|
|
FREEDMR_GATEWAY_FBP_KEY="${FREEDMR_GATEWAY_FBP_KEY:-}"
|
|
if [ -z "$FREEDMR_GATEWAY_FBP_KEY" ]
|
|
then
|
|
FREEDMR_GATEWAY_FBP_KEY=$(od -An -N10 -tx1 /dev/urandom | tr -d ' \n')
|
|
fi
|
|
case "$FREEDMR_GATEWAY_FBP_KEY" in
|
|
''|*[!A-Za-z0-9._-]*)
|
|
echo 'Data Gateway FBP key may contain only letters, digits, dot, underscore and hyphen.' >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
if [ "${#FREEDMR_GATEWAY_FBP_KEY}" -gt 20 ]
|
|
then
|
|
echo 'Data Gateway FBP key must not exceed 20 characters.' >&2
|
|
exit 2
|
|
fi
|
|
FREEDMR_GATEWAY_FBP_RELATIONSHIPS=$(build_data_gateway_relationships \
|
|
"$HDSTACK_COUNT" "$HDSTACK_BASEID" "$FREEDMR_GATEWAY_FBP_KEY")
|
|
|
|
echo
|
|
echo 'Installing required packages and Docker Community Edition...'
|
|
apt-get -y remove docker docker-engine docker.io
|
|
apt-get -y update
|
|
apt-get -y install apt-transport-https ca-certificates curl gnupg2 software-properties-common
|
|
curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
|
|
ARCH=$(/usr/bin/arch)
|
|
echo "System architecture is $ARCH"
|
|
if [ "$ARCH" = "x86_64" ]
|
|
then
|
|
ARCH="amd64"
|
|
fi
|
|
add-apt-repository \
|
|
"deb [arch=$ARCH] https://download.docker.com/linux/debian \
|
|
$(lsb_release -cs) \
|
|
stable"
|
|
apt-get -y update
|
|
apt-get -y install docker-ce docker-compose
|
|
|
|
echo 'Configuring Docker...'
|
|
cat <<EOF > /etc/docker/daemon.json
|
|
{
|
|
"userland-proxy": false,
|
|
"experimental": true,
|
|
"log-driver": "json-file",
|
|
"log-opts": {
|
|
"max-size": "10m",
|
|
"max-file": "3"
|
|
}
|
|
}
|
|
EOF
|
|
systemctl restart docker
|
|
|
|
echo 'Installing FreeDMR configuration...'
|
|
mkdir -p /etc/freedmr/acme.sh /etc/freedmr/certs /etc/freedmr/json
|
|
chmod -R 755 /etc/freedmr
|
|
chown 54000:54000 /etc/freedmr/json
|
|
|
|
curl -fsSL "$BASE_URL/FreeDMR.cfg" -o /etc/freedmr/freedmr.cfg
|
|
sed -i "0,/^SERVER_ID:/s/^SERVER_ID:.*/SERVER_ID: $HDSTACK_BASEID/" /etc/freedmr/freedmr.cfg
|
|
sed -i '/^\[GLOBAL\]/,/^\[/ s/^DATA_GATEWAY:.*/DATA_GATEWAY: True/' /etc/freedmr/freedmr.cfg
|
|
sed -i '/^\[DATA-GATEWAY\]/,/^\[/ s/^ENABLED:.*/ENABLED: True/' /etc/freedmr/freedmr.cfg
|
|
sed -i "/^\[DATA-GATEWAY\]/,/^\[/ s|^PASSPHRASE:.*|PASSPHRASE: $FREEDMR_GATEWAY_FBP_KEY|" /etc/freedmr/freedmr.cfg
|
|
sed -i '/^\[DATA-GATEWAY\]/,/^\[/ s/^TARGET_IP:.*/TARGET_IP: freedmr-data-gateway/' /etc/freedmr/freedmr.cfg
|
|
|
|
|
|
if [ ! -e /etc/freedmr/freedmr-bridge.cfg ]
|
|
then
|
|
curl -fsSL "$BASE_URL/docker-configs/freedmr-bridge.cfg" -o /etc/freedmr/freedmr-bridge.cfg
|
|
fi
|
|
if [ "$HDSTACK_BRIDGE_VALUE" -eq 1 ]
|
|
then
|
|
sed -i "0,/^SERVER_ID:/s/^SERVER_ID:.*/SERVER_ID: $HDSTACK_BRIDGE_ID/" /etc/freedmr/freedmr-bridge.cfg
|
|
fi
|
|
if [ ! -e /etc/freedmr/rules-bridge.py ]
|
|
then
|
|
curl -fsSL "$BASE_URL/docker-configs/rules-bridge.py" -o /etc/freedmr/rules-bridge.py
|
|
fi
|
|
|
|
curl -fsSL "$BASE_URL/docker-configs/docker-compose.yml" -o /etc/freedmr/docker-compose.yml
|
|
sed -i "s|^[[:space:]]*#*- HDSTACK=.*| - HDSTACK=$HDSTACK_COUNT|" /etc/freedmr/docker-compose.yml
|
|
sed -i "s|^[[:space:]]*#*- HDSTACK_BASEID=.*| - HDSTACK_BASEID=$HDSTACK_BASEID|" /etc/freedmr/docker-compose.yml
|
|
sed -i "s|^[[:space:]]*- HDSTACK_BRIDGE=.*| - HDSTACK_BRIDGE=$HDSTACK_BRIDGE_VALUE|" /etc/freedmr/docker-compose.yml
|
|
sed -i "s|__FREEDMR_GATEWAY_FBP_RELATIONSHIPS__|$FREEDMR_GATEWAY_FBP_RELATIONSHIPS|" /etc/freedmr/docker-compose.yml
|
|
sed -i "s|__FREEDMR_GATEWAY_APRS_LOGIN_CALL__|$FREEDMR_GATEWAY_APRS_LOGIN_CALL|" /etc/freedmr/docker-compose.yml
|
|
sed -i "s|__FREEDMR_GATEWAY_APRS_PASSCODE__|$FREEDMR_GATEWAY_APRS_PASSCODE|" /etc/freedmr/docker-compose.yml
|
|
chown -R 54000:54000 /etc/freedmr
|
|
|
|
if [ -e /etc/cron.daily/lastheard ]
|
|
then
|
|
chmod 755 /etc/cron.daily/lastheard
|
|
fi
|
|
|
|
echo 'Tuning network stack...'
|
|
cat <<EOF > /etc/sysctl.conf
|
|
net.core.rmem_default=134217728
|
|
net.core.rmem_max=134217728
|
|
net.core.wmem_max=134217728
|
|
net.core.netdev_max_backlog=250000
|
|
net.netfilter.nf_conntrack_udp_timeout=15
|
|
net.netfilter.nf_conntrack_udp_timeout_stream=35
|
|
EOF
|
|
/usr/sbin/sysctl -p
|
|
|
|
echo 'Starting the FreeDMR release-candidate container...'
|
|
cd /etc/freedmr
|
|
docker-compose up -d
|
|
|
|
echo 'Read /etc/freedmr/docker-compose.yml and docs/hdstack.md before adding optional services or custom links.'
|
|
echo 'FreeDMR setup complete.'
|