#!/usr/bin/env bash set -euo pipefail # Check permissions if [ "$UID" != "0" ]; then echo "This script must be run as root / with sudo" >&2 exit 1 fi # Get settings RID=$(cat /etc/radio_id) read -rp "Radio ID (${RID:-1-254}): " ip ip=${ip:-$RID} echo $ip > /etc/radio_id read -rp "Radio Name ($HOSTNAME): " name name=${name:-$HOSTNAME} read -rp "HuggingFace Token: " token export HUGGING_FACE_HUB_TOKEN=${token} read -p "Enable wireguard (Y/N): " wireguard if [ "${wireguard,,}" == "y" ]; then while [ ! -f "/etc/wireguard/wg0.conf" ]; do read -n 1 -s -p "Add '/etc/wireguard/wg0.conf' then press any key to continue..." done fi # Install updates & packages export DEBIAN_FRONTEND=noninteractive apt update && apt upgrade -y && apt install -y \ build-essential libpcap-dev libusb-1.0-0-dev libnetfilter-queue-dev \ btop jq tmux unzip zip # Update hostname hostnamectl set-hostname "${name}" sed -i "s/$HOSTNAME/$name" /etc/hostname sed -i "s/$HOSTNAME/$name" /etc/hosts # Update banner cat <> /etc/motd ██████ ██████ ███████████ █████████ ░░██████ ██████ ░░███░░░░░███ ███░░░░░███ ░███░█████░███ ░███ ░███ ░███ ░░░ ░███░░███ ░███ ░██████████ ░░█████████ ░███ ░░░ ░███ ░███░░░░░███ ░░░░░░░░███ ░███ ░███ ░███ ░███ ███ ░███ █████ █████ █████ █████░░█████████ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ EOF # Node curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh | bash source ~/.bashrc nvm install stable && nvm use stable # Setup wireguard if [ "${wireguard,,}" == "y" ]; then apt install wireguard -y systemctl enable wg-quick@wg0 systemctl start wg-quick@wg0 fi # Setup GPS - gpsmon sed -i '/^enable_uart=/d' /boot/firmware/config.txt echo "enable_uart=1" >> /boot/firmware/config.txt apt install -y gpsd gpsd-clients chrony tee /etc/default/gpsd > /dev/null <<'EOF' START_DAEMON="true" GPSD_OPTIONS="-n" DEVICES="/dev/serial0" USBAUTO="false" GPSD_SOCKET="/var/run/gpsd.sock" EOF tee -a /etc/chrony/chrony.conf > /dev/null <<'EOF' refclock SHM 0 offset 0.5 delay 0.2 refid NMEA EOF systemctl enable --now gpsd chrony # Setup Fallback AP curl -sL https://git.zakscode.com/ztimson/fallback-ap/raw/branch/master/install.sh | sudo bash # Install docker apt install -y qemu-user-static curl -fsSL https://get.docker.com | sh usermod -aG docker $USER newgrp docker # VNC sudo raspi-config nonint do_vnc 0 cat < /etc/udev/rules.d/99-udisks2.rules # docker run -d --name filebrowser --restart unless-stopped -p 1200:8080 -e FB_USERNAME=$USER -v filebrowser:/config -v /media:/data hurlenko/filebrowser:latest # sleep 3 # fb_pass=$(docker logs filebrowser 2>&1 | grep -oP 'randomly generated password: \K.*'); echo $fb_pass # Setup Kiwix - http://localhost:1300 # mkdir -p /media/library/archive # mkdir -p /media/library/zim # docker run -d --name kiwix --restart unless-stopped -p 1300:3000 -v /media/library:/data ztimson/kiwixm:latest # Maps - http://localhost:1400 mkdir -p /media/maps/tiles mkdir -p /media/maps/styles docker run -d --name maps --restart unless-stopped -p 1400:8080 -v /media/maps/config.json:/config.json -v /media/maps/tiles:/data -v /media/maps/styles:/styles maptiler/tileserver-gl:v4.11.0 # Setup AI (LiteRT + Gemma4-E2B) curl -LsSf https://astral.sh/uv/install.sh | sh source $HOME/.local/bin/env INSTALL_DIR="$(pwd)" uv venv --clear --python=3.13 --seed source .venv/bin/activate uv pip install litert-cli-nightly litert-lm-nightly litert-lm import --from-huggingface-repo litert-community/gemma-4-E2B-it-litert-lm MODEL_PATH="$INSTALL_DIR/gemma-4-E2B-it.litertlm" LITERT_BIN="$INSTALL_DIR/.venv/bin/litert-lm" SERVICE_USER="$(whoami)" cat < /etc/element/config.json # docker run -d --name element --restart unless-stopped -p 1500:80 -v /etc/element/config.json:/app/config.json vectorim/element-web:latest # Setup pentest suite - http:localhost:1600 sudo apt install -y arp-scan aircrack-ng gobuster hashcat hcxtools hydra john netcat-openbsd nikto nmap masscan reaver sqlmap tcpdump wireshark curl https://raw.githubusercontent.com/rapid7/metasploit-omnibus/master/config/templates/metasploit-framework-wrappers/msfupdate.erb > msfinstall chmod +x msfinstall ./msfinstall rm msfinstall docker run -d --name bettercap --restart unless-stopped --privileged --net=host bettercap/bettercap -eval "set api.rest.address 0.0.0.0; set ui.address 0.0.0.0; set ui.port 1600; ui on; set gps.device localhost:2947;" # ATAK - http://localhost:1100 (XMPP - 5222, API - 8089) docker run -d --name atak --restart unless-stopped --platform=linux/amd64 -p 8089:8080 -p 5222:8999 -p 1100:8088 -v atak:/app kdudkov/goatak_server:latest # TODO: SDR tools (SDRangel, dump1060) #docker run -d --name sdrserver --restart unless-stopped --device /dev/bus/usb:/dev/bus/usb -p 8091:8091 -p 8092:8092 f4exb06/sdrangelsrv:v7.22.7 --bind 0.0.0.0 #docker run -d --name sdrcli --restart unless-stopped -p 1000:8080 -e SDRANGEL_SERVER_URL=http://10.69.5.108:8091 f4exb06/sdrangelcli:v4.0.2 # Speedtest - http://localhost:1900 docker run -d --name speedtest --restart unless-stopped -p 1900:80 lscr.io/linuxserver/librespeed:latest # TODO: Captive Portal + PWA # TODO: E-Ink + QR Join AP # TODO: Mesh