2026-02-01 02:22:02 +00:00
#!/bin/bash
#
2026-03-28 11:31:48 +00:00
# archipelago main menu
# interactive setup for archipelago bitcoin node os
2026-02-01 02:22:02 +00:00
#
SCRIPT_DIR = " $( cd " $( dirname " $0 " ) " && pwd ) "
2026-03-28 11:31:48 +00:00
# Colors (256-color — works on Linux console with fbcon)
O = $'\033[38;5;208m' # Orange
W = $'\033[1;37m' # Bold white
D = $'\033[38;5;242m' # Dim
C = $'\033[38;5;37m' # Cyan
G = $'\033[38;5;35m' # Green
R = $'\033[38;5;196m' # Red
Y = $'\033[38;5;220m' # Yellow
N = $'\033[0m' # Reset
# Adaptive centering
get_width( ) { TW = $( tput cols 2>/dev/null || echo 60) ; [ " $TW " -gt 120 ] && TW = 120; }
get_width
cc( ) { local s = $( echo -e " $1 " | sed 's/\x1b\[[0-9;]*m//g' ) ; local p = $(( ( TW - ${# s } ) / 2 )) ; [ $p -lt 0 ] && p = 0; printf "%*s" " $p " "" ; echo -e " $1 " ; }
# Box helpers (Claude-style rounded corners)
bw( ) { echo $(( TW > 52 ? 52 : TW - 4 )) ; }
btop( ) { local w = $( bw) ; local t = "╭" ; for i in $( seq 1 $(( w-2)) ) ; do t = " ${ t } ─ " ; done ; cc " ${ D } ${ t } ╮ ${ N } " ; }
bbox( ) { local w = $( bw) ; local s = $( echo -e " $1 " | sed 's/\x1b\[[0-9;]*m//g' ) ; local pad = $(( w - 2 - ${# s } )) ; [ $pad -lt 0 ] && pad = 0; local r = "" ; for i in $( seq 1 $pad ) ; do r = " ${ r } " ; done ; cc " ${ D } │ ${ N } $1 ${ r } ${ D } │ ${ N } " ; }
bbot( ) { local w = $( bw) ; local b = "╰" ; for i in $( seq 1 $(( w-2)) ) ; do b = " ${ b } ─ " ; done ; cc " ${ D } ${ b } ╯ ${ N } " ; }
hrule( ) { local len = $(( TW > 50 ? 50 : TW - 4 )) ; local hr = "" ; for i in $( seq 1 $len ) ; do hr = " ${ hr } ─ " ; done ; cc " ${ D } ${ hr } ${ N } " ; }
2026-02-01 02:22:02 +00:00
# Install required tools on first run (for live mode)
install_required_tools( ) {
if [ -f /tmp/.archipelago-tools-installed ] ; then
return 0
fi
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
local NEED_TOOLS = 0
for tool in parted debootstrap mkfs.ext4 mkfs.vfat; do
if ! command -v $tool >/dev/null 2>& 1; then
NEED_TOOLS = 1
break
fi
done
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
if [ $NEED_TOOLS -eq 1 ] ; then
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } installing required tools... ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
sudo apt-get update -qq 2>/dev/null
sudo apt-get install -y parted debootstrap dosfstools e2fsprogs 2>/dev/null
2026-03-28 11:31:48 +00:00
cc " ${ G } tools installed ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
sleep 1
fi
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
touch /tmp/.archipelago-tools-installed
}
install_required_tools
show_banner( ) {
2026-03-28 11:31:48 +00:00
get_width
2026-02-01 02:22:02 +00:00
clear
echo ""
2026-03-29 16:08:41 +01:00
echo -e " ${ O } ▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█ ${ N } "
echo -e " ${ O } █▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █ ${ N } "
echo -e " ${ O } ▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀ ${ N } "
echo -e " ${ D } bitcoin node os ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
}
show_status( ) {
if [ -d /run/live ] ; then
2026-03-28 11:31:48 +00:00
cc " ${ R } live mode ${ N } ${ D } (changes won't persist) ${ N } "
2026-02-01 02:22:02 +00:00
else
2026-03-28 11:31:48 +00:00
cc " ${ G } installed ${ N } "
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
echo ""
local podman_ok = 0
command -v podman >/dev/null 2>& 1 && podman_ok = 1
if [ $podman_ok -eq 1 ] && podman ps 2>/dev/null | grep -q bitcoind; then
local blocks = $( podman exec bitcoind bitcoin-cli getblockcount 2>/dev/null || echo "syncing" )
cc " ${ G } bitcoin ${ N } ${ D } running ( $blocks blocks) ${ N } "
elif [ $podman_ok -eq 1 ] && podman ps -a 2>/dev/null | grep -q bitcoind; then
cc " ${ Y } bitcoin ${ N } ${ D } stopped ${ N } "
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
if [ $podman_ok -eq 1 ] && podman ps 2>/dev/null | grep -q lnd; then
cc " ${ G } lightning ${ N } ${ D } running ${ N } "
elif [ $podman_ok -eq 1 ] && podman ps -a 2>/dev/null | grep -q lnd; then
cc " ${ Y } lightning ${ N } ${ D } stopped ${ N } "
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
echo ""
}
main_menu( ) {
while true; do
show_banner
show_status
2026-03-28 11:31:48 +00:00
# Connection info
2026-02-01 02:22:02 +00:00
IP = $( hostname -I 2>/dev/null | awk '{print $1}' )
2026-02-01 05:42:05 +00:00
[ -z " $IP " ] && IP = $( ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
if [ -n " $IP " ] ; then
2026-02-01 05:42:05 +00:00
if pgrep -f "archipelago" >/dev/null 2>& 1; then
2026-03-28 11:31:48 +00:00
cc " ${ C } web ui ${ N } ${ W } http:// $IP ${ N } "
2026-02-01 05:42:05 +00:00
else
2026-03-28 11:31:48 +00:00
cc " ${ C } web ui ${ N } ${ D } http:// $IP ${ N } ${ Y } (not started) ${ N } "
2026-02-01 05:42:05 +00:00
fi
2026-03-28 11:31:48 +00:00
cc " ${ C } ssh ${ N } ${ D } archipelago@ $IP ${ N } "
2026-02-01 05:42:05 +00:00
else
2026-03-28 11:31:48 +00:00
cc " ${ D } no network detected ${ N } "
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
2026-02-01 05:42:05 +00:00
echo ""
2026-03-28 11:31:48 +00:00
hrule
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } r ${ N } refresh status ${ D } w ${ N } start web ui "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ O } 1 ${ N } install to disk ${ O } 5 ${ N } view logs "
cc " ${ O } 2 ${ N } setup bitcoin core ${ O } 6 ${ N } network settings "
cc " ${ O } 3 ${ N } setup lightning ${ O } 7 ${ N } system info "
cc " ${ O } 4 ${ N } setup btcpay server "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } q quit ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
local pad = $(( ( TW - 18 ) / 2 ))
[ $pad -lt 0 ] && pad = 0
printf "%*s" " $pad " ""
read -p "select option: " choice
2026-02-01 02:22:02 +00:00
case $choice in
2026-02-17 15:03:34 +00:00
r| R)
; ;
2026-02-01 02:22:02 +00:00
w| W)
2026-02-01 05:42:05 +00:00
echo ""
if command -v archipelago >/dev/null 2>& 1; then
if pgrep -f "archipelago" >/dev/null 2>& 1; then
2026-03-28 11:31:48 +00:00
cc " ${ G } backend already running ${ N } "
2026-02-01 05:42:05 +00:00
else
2026-03-28 11:31:48 +00:00
cc " ${ D } starting backend on port 5678... ${ N } "
2026-02-01 05:42:05 +00:00
nohup archipelago >/tmp/archipelago.log 2>& 1 &
sleep 2
if pgrep -f "archipelago" >/dev/null 2>& 1; then
2026-03-28 11:31:48 +00:00
cc " ${ G } backend started ${ N } "
2026-02-01 05:42:05 +00:00
else
2026-03-28 11:31:48 +00:00
cc " ${ R } failed — see /tmp/archipelago.log ${ N } "
2026-02-01 02:22:02 +00:00
fi
2026-02-01 05:42:05 +00:00
fi
IP = $( hostname -I 2>/dev/null | awk '{print $1}' )
echo ""
2026-03-28 11:31:48 +00:00
cc " open in browser: ${ W } http:// $IP ${ N } "
2026-02-01 05:42:05 +00:00
else
2026-03-28 11:31:48 +00:00
cc " ${ R } binary not found at /usr/local/bin/archipelago ${ N } "
2026-02-01 02:22:02 +00:00
fi
2026-02-01 05:42:05 +00:00
echo ""
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
1)
if [ -f " $SCRIPT_DIR /install-to-disk.sh " ] ; then
sudo bash " $SCRIPT_DIR /install-to-disk.sh "
else
2026-03-28 11:31:48 +00:00
echo " installer not found at: $SCRIPT_DIR "
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
2)
if [ -f " $SCRIPT_DIR /setup-bitcoin.sh " ] ; then
bash " $SCRIPT_DIR /setup-bitcoin.sh "
else
2026-03-28 11:31:48 +00:00
echo " bitcoin setup script not found."
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
3)
if [ -f " $SCRIPT_DIR /setup-lnd.sh " ] ; then
bash " $SCRIPT_DIR /setup-lnd.sh "
else
2026-03-28 11:31:48 +00:00
echo " lnd setup script not found."
2026-02-01 02:22:02 +00:00
fi
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
4)
setup_btcpay
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
5)
view_logs
; ;
6)
network_settings
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
7)
system_info
2026-03-28 11:31:48 +00:00
read -sp " press enter to continue..."
2026-02-01 02:22:02 +00:00
; ;
q| Q)
echo ""
exit 0
; ;
*)
2026-03-28 11:31:48 +00:00
sleep 0.5
2026-02-01 02:22:02 +00:00
; ;
esac
done
}
setup_btcpay( ) {
show_banner
2026-03-28 11:31:48 +00:00
cc " ${ W } btcpay server setup ${ N } "
cc " ${ D } self-hosted bitcoin payment processor ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
if ! podman ps | grep -q bitcoind; then
2026-03-28 11:31:48 +00:00
cc " ${ R } bitcoin core must be running first ${ N } "
2026-02-01 02:22:02 +00:00
return
fi
2026-03-28 11:31:48 +00:00
local pad = $(( ( TW - 30 ) / 2 ))
[ $pad -lt 0 ] && pad = 0
printf "%*s" " $pad " ""
read -p "setup btcpay server? [y/N]: " SETUP
2026-02-01 02:22:02 +00:00
if [ [ ! " $SETUP " = ~ ^[ Yy] $ ] ] ; then
return
fi
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } pulling btcpay server image... ${ N } "
2026-03-26 14:06:21 +00:00
podman pull " ${ BTCPAY_IMAGE } "
2026-02-01 02:22:02 +00:00
mkdir -p ~/.btcpay
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } full setup: https://docs.btcpayserver.org ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
}
view_logs( ) {
show_banner
2026-03-28 11:31:48 +00:00
cc " ${ W } view logs ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ O } 1 ${ N } ${ D } bitcoin core ${ N } "
cc " ${ O } 2 ${ N } ${ D } lnd ${ N } "
cc " ${ O } 3 ${ N } ${ D } system journal ${ N } "
cc " ${ D } b back ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
local pad = $(( ( TW - 10 ) / 2 ))
[ $pad -lt 0 ] && pad = 0
printf "%*s" " $pad " ""
read -p "select: " choice
2026-02-01 02:22:02 +00:00
case $choice in
1)
if podman ps -a | grep -q bitcoind; then
podman logs -f --tail 50 bitcoind
else
2026-03-28 11:31:48 +00:00
cc " ${ D } bitcoin core not running ${ N } "
read -sp " press enter..."
2026-02-01 02:22:02 +00:00
fi
; ;
2)
if podman ps -a | grep -q lnd; then
podman logs -f --tail 50 lnd
else
2026-03-28 11:31:48 +00:00
cc " ${ D } lnd not running ${ N } "
read -sp " press enter..."
2026-02-01 02:22:02 +00:00
fi
; ;
3)
journalctl -f
; ;
esac
}
network_settings( ) {
show_banner
2026-03-28 11:31:48 +00:00
cc " ${ W } network settings ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
IP = $( hostname -I | awk '{print $1}' )
2026-03-28 11:31:48 +00:00
cc " ${ C } ip ${ N } ${ W } $IP ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } interfaces: ${ N } "
2026-02-01 02:22:02 +00:00
ip -br addr | grep -v "^lo" | while read line; do
2026-03-28 11:31:48 +00:00
cc " ${ D } $line ${ N } "
2026-02-01 02:22:02 +00:00
done
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } service ports: ${ N } "
cc " ${ D } 8332 bitcoin rpc 9735 lightning p2p ${ N } "
cc " ${ D } 8333 bitcoin p2p 10009 lightning grpc ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
}
system_info( ) {
show_banner
2026-03-28 11:31:48 +00:00
cc " ${ W } system information ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ C } host ${ N } ${ D } $( hostname) ${ N } "
cc " ${ C } kernel ${ N } ${ D } $( uname -r) ${ N } "
cc " ${ C } uptime ${ N } ${ D } $( uptime -p 2>/dev/null || echo 'unknown' ) ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
local cpu = $( grep "model name" /proc/cpuinfo 2>/dev/null | head -1 | cut -d: -f2 | xargs)
[ -n " $cpu " ] && cc " ${ C } cpu ${ N } ${ D } ${ cpu } ${ N } "
local mem_total = $( free -h 2>/dev/null | grep Mem | awk '{print $2}' )
local mem_used = $( free -h 2>/dev/null | grep Mem | awk '{print $3}' )
[ -n " $mem_total " ] && cc " ${ C } memory ${ N } ${ D } ${ mem_used } / ${ mem_total } ${ N } "
2026-02-01 02:22:02 +00:00
echo ""
2026-03-28 11:31:48 +00:00
cc " ${ D } disk: ${ N } "
df -h / | tail -1 | awk '{printf " root: %s / %s (%s used)\n", $3, $2, $5}' | while read line; do
cc " ${ D } ${ line } ${ N } "
done
2026-02-01 02:22:02 +00:00
if [ -d ~/.bitcoin ] ; then
2026-03-28 11:31:48 +00:00
local btc_size = $( du -sh ~/.bitcoin 2>/dev/null | cut -f1)
cc " ${ D } bitcoin: $btc_size ${ N } "
2026-02-01 02:22:02 +00:00
fi
echo ""
2026-03-28 11:31:48 +00:00
2026-02-01 02:22:02 +00:00
if command -v podman >/dev/null 2>& 1; then
2026-03-28 11:31:48 +00:00
cc " ${ D } containers: ${ N } "
podman ps --format " {{.Names}}: {{.Status}}" 2>/dev/null | while read line; do
cc " ${ D } ${ line } ${ N } "
done
2026-02-01 02:22:02 +00:00
fi
echo ""
}
main_menu