Archipelago — open-source initial import
This commit is contained in:
+340
@@ -0,0 +1,340 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# archipelago main menu
|
||||
# interactive setup for archipelago bitcoin node os
|
||||
#
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# 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}"; }
|
||||
|
||||
# Install required tools on first run (for live mode)
|
||||
install_required_tools() {
|
||||
if [ -f /tmp/.archipelago-tools-installed ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
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
|
||||
|
||||
if [ $NEED_TOOLS -eq 1 ]; then
|
||||
echo ""
|
||||
cc "${D}installing required tools...${N}"
|
||||
echo ""
|
||||
sudo apt-get update -qq 2>/dev/null
|
||||
sudo apt-get install -y parted debootstrap dosfstools e2fsprogs 2>/dev/null
|
||||
cc "${G}tools installed${N}"
|
||||
echo ""
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
touch /tmp/.archipelago-tools-installed
|
||||
}
|
||||
|
||||
install_required_tools
|
||||
|
||||
show_banner() {
|
||||
get_width
|
||||
clear
|
||||
echo ""
|
||||
echo -e " ${O}▄▀█ █▀▄ █▀▀ █ █ █ █▀█ █▀▀ █ ▄▀█ █▀▀ █▀█${N}"
|
||||
echo -e " ${O}█▀█ █▀▄ █ █▀█ █ █▀▀ ██▀ █ █▀█ █ █ █ █${N}"
|
||||
echo -e " ${O}▀ ▀ ▀ ▀ ▀▀▀ ▀ ▀ ▀ ▀ ▀▀▀ ▀▀▀ ▀ ▀ ▀▀▀ ▀▀▀${N}"
|
||||
echo -e " ${D}bitcoin node os${N}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
show_status() {
|
||||
if [ -d /run/live ]; then
|
||||
cc "${R}live mode${N} ${D}(changes won't persist)${N}"
|
||||
else
|
||||
cc "${G}installed${N}"
|
||||
fi
|
||||
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}"
|
||||
fi
|
||||
|
||||
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}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
while true; do
|
||||
show_banner
|
||||
show_status
|
||||
|
||||
# Connection info
|
||||
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
[ -z "$IP" ] && IP=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '127.0.0.1' | head -1)
|
||||
|
||||
if [ -n "$IP" ]; then
|
||||
if pgrep -f "archipelago" >/dev/null 2>&1; then
|
||||
cc "${C}web ui${N} ${W}http://$IP${N}"
|
||||
else
|
||||
cc "${C}web ui${N} ${D}http://$IP${N} ${Y}(not started)${N}"
|
||||
fi
|
||||
cc "${C}ssh${N} ${D}archipelago@$IP${N}"
|
||||
else
|
||||
cc "${D}no network detected${N}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
hrule
|
||||
echo ""
|
||||
cc "${D}r${N} refresh status ${D}w${N} start web ui"
|
||||
echo ""
|
||||
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"
|
||||
echo ""
|
||||
cc "${D}q quit${N}"
|
||||
echo ""
|
||||
|
||||
local pad=$(( (TW - 18) / 2 ))
|
||||
[ $pad -lt 0 ] && pad=0
|
||||
printf "%*s" "$pad" ""
|
||||
read -p "select option: " choice
|
||||
|
||||
case $choice in
|
||||
r|R)
|
||||
;;
|
||||
w|W)
|
||||
echo ""
|
||||
if command -v archipelago >/dev/null 2>&1; then
|
||||
if pgrep -f "archipelago" >/dev/null 2>&1; then
|
||||
cc "${G}backend already running${N}"
|
||||
else
|
||||
cc "${D}starting backend on port 5678...${N}"
|
||||
nohup archipelago >/tmp/archipelago.log 2>&1 &
|
||||
sleep 2
|
||||
if pgrep -f "archipelago" >/dev/null 2>&1; then
|
||||
cc "${G}backend started${N}"
|
||||
else
|
||||
cc "${R}failed — see /tmp/archipelago.log${N}"
|
||||
fi
|
||||
fi
|
||||
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
echo ""
|
||||
cc "open in browser: ${W}http://$IP${N}"
|
||||
else
|
||||
cc "${R}binary not found at /usr/local/bin/archipelago${N}"
|
||||
fi
|
||||
echo ""
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
1)
|
||||
if [ -f "$SCRIPT_DIR/install-to-disk.sh" ]; then
|
||||
sudo bash "$SCRIPT_DIR/install-to-disk.sh"
|
||||
else
|
||||
echo " installer not found at: $SCRIPT_DIR"
|
||||
fi
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
2)
|
||||
if [ -f "$SCRIPT_DIR/setup-bitcoin.sh" ]; then
|
||||
bash "$SCRIPT_DIR/setup-bitcoin.sh"
|
||||
else
|
||||
echo " bitcoin setup script not found."
|
||||
fi
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
3)
|
||||
if [ -f "$SCRIPT_DIR/setup-lnd.sh" ]; then
|
||||
bash "$SCRIPT_DIR/setup-lnd.sh"
|
||||
else
|
||||
echo " lnd setup script not found."
|
||||
fi
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
4)
|
||||
setup_btcpay
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
5)
|
||||
view_logs
|
||||
;;
|
||||
6)
|
||||
network_settings
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
7)
|
||||
system_info
|
||||
read -sp " press enter to continue..."
|
||||
;;
|
||||
q|Q)
|
||||
echo ""
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
sleep 0.5
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
setup_btcpay() {
|
||||
show_banner
|
||||
cc "${W}btcpay server setup${N}"
|
||||
cc "${D}self-hosted bitcoin payment processor${N}"
|
||||
echo ""
|
||||
|
||||
if ! podman ps | grep -q bitcoind; then
|
||||
cc "${R}bitcoin core must be running first${N}"
|
||||
return
|
||||
fi
|
||||
|
||||
local pad=$(( (TW - 30) / 2 ))
|
||||
[ $pad -lt 0 ] && pad=0
|
||||
printf "%*s" "$pad" ""
|
||||
read -p "setup btcpay server? [y/N]: " SETUP
|
||||
if [[ ! "$SETUP" =~ ^[Yy]$ ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo ""
|
||||
cc "${D}pulling btcpay server image...${N}"
|
||||
podman pull "${BTCPAY_IMAGE}"
|
||||
mkdir -p ~/.btcpay
|
||||
|
||||
echo ""
|
||||
cc "${D}full setup: https://docs.btcpayserver.org${N}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
view_logs() {
|
||||
show_banner
|
||||
cc "${W}view logs${N}"
|
||||
echo ""
|
||||
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}"
|
||||
echo ""
|
||||
|
||||
local pad=$(( (TW - 10) / 2 ))
|
||||
[ $pad -lt 0 ] && pad=0
|
||||
printf "%*s" "$pad" ""
|
||||
read -p "select: " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
if podman ps -a | grep -q bitcoind; then
|
||||
podman logs -f --tail 50 bitcoind
|
||||
else
|
||||
cc "${D}bitcoin core not running${N}"
|
||||
read -sp " press enter..."
|
||||
fi
|
||||
;;
|
||||
2)
|
||||
if podman ps -a | grep -q lnd; then
|
||||
podman logs -f --tail 50 lnd
|
||||
else
|
||||
cc "${D}lnd not running${N}"
|
||||
read -sp " press enter..."
|
||||
fi
|
||||
;;
|
||||
3)
|
||||
journalctl -f
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
network_settings() {
|
||||
show_banner
|
||||
cc "${W}network settings${N}"
|
||||
echo ""
|
||||
|
||||
IP=$(hostname -I | awk '{print $1}')
|
||||
cc "${C}ip${N} ${W}$IP${N}"
|
||||
echo ""
|
||||
|
||||
cc "${D}interfaces:${N}"
|
||||
ip -br addr | grep -v "^lo" | while read line; do
|
||||
cc " ${D}$line${N}"
|
||||
done
|
||||
echo ""
|
||||
|
||||
cc "${D}service ports:${N}"
|
||||
cc " ${D}8332 bitcoin rpc 9735 lightning p2p${N}"
|
||||
cc " ${D}8333 bitcoin p2p 10009 lightning grpc${N}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
system_info() {
|
||||
show_banner
|
||||
cc "${W}system information${N}"
|
||||
echo ""
|
||||
|
||||
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}"
|
||||
echo ""
|
||||
|
||||
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}"
|
||||
echo ""
|
||||
|
||||
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
|
||||
|
||||
if [ -d ~/.bitcoin ]; then
|
||||
local btc_size=$(du -sh ~/.bitcoin 2>/dev/null | cut -f1)
|
||||
cc " ${D}bitcoin: $btc_size${N}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if command -v podman >/dev/null 2>&1; then
|
||||
cc "${D}containers:${N}"
|
||||
podman ps --format " {{.Names}}: {{.Status}}" 2>/dev/null | while read line; do
|
||||
cc "${D}${line}${N}"
|
||||
done
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
main_menu
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# Configure Nginx to listen on Tailscale IP address
|
||||
# This script should be run after Tailscale is set up and connected
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 Detecting Tailscale IP..."
|
||||
|
||||
# Get Tailscale IP from tailscale0 interface
|
||||
TAILSCALE_IP=$(ip -4 addr show tailscale0 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}' || echo "")
|
||||
|
||||
if [ -z "$TAILSCALE_IP" ]; then
|
||||
echo "❌ Tailscale interface not found. Is Tailscale running with host networking?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Found Tailscale IP: $TAILSCALE_IP"
|
||||
|
||||
NGINX_CONFIG="/etc/nginx/sites-available/archipelago"
|
||||
|
||||
# Check if Tailscale IP is already in the config
|
||||
if grep -q "listen $TAILSCALE_IP:80" "$NGINX_CONFIG"; then
|
||||
echo "✅ Nginx already configured for Tailscale IP $TAILSCALE_IP"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "📝 Adding Tailscale IP to Nginx configuration..."
|
||||
|
||||
# Backup the config
|
||||
sudo cp "$NGINX_CONFIG" "$NGINX_CONFIG.backup.$(date +%s)"
|
||||
|
||||
# Add Tailscale IP to listen directive (after the first "listen 80;")
|
||||
sudo sed -i "0,/listen 80;/s//listen 80;\n listen $TAILSCALE_IP:80;/" "$NGINX_CONFIG"
|
||||
|
||||
echo "🔍 Testing Nginx configuration..."
|
||||
sudo nginx -t
|
||||
|
||||
echo "🔄 Reloading Nginx..."
|
||||
sudo systemctl reload nginx
|
||||
|
||||
echo "✅ Nginx configured to accept connections from Tailscale!"
|
||||
echo " Access your Archipelago UI via Tailscale at:"
|
||||
echo " http://$(hostname).tail<your-tailnet>.ts.net/"
|
||||
+372
@@ -0,0 +1,372 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Archipelago Disk Installer
|
||||
# Installs Archipelago Bitcoin Node OS to a disk
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ 🏝️ ARCHIPELAGO DISK INSTALLER ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
echo "❌ Please run as root: sudo $0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install required tools if missing
|
||||
echo "📦 Checking required tools..."
|
||||
NEED_INSTALL=""
|
||||
for tool in parted debootstrap; do
|
||||
if ! command -v $tool >/dev/null 2>&1; then
|
||||
NEED_INSTALL="$NEED_INSTALL $tool"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$NEED_INSTALL" ]; then
|
||||
echo "📥 Installing required tools:$NEED_INSTALL"
|
||||
apt-get update
|
||||
apt-get install -y $NEED_INSTALL dosfstools e2fsprogs
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# List available disks
|
||||
echo "📋 Available disks:"
|
||||
echo ""
|
||||
lsblk -d -o NAME,SIZE,MODEL | grep -v loop | grep -v sr
|
||||
echo ""
|
||||
|
||||
# Get target disk
|
||||
read -p "Enter target disk (e.g., sda, nvme0n1): " TARGET_DISK
|
||||
TARGET_DEVICE="/dev/$TARGET_DISK"
|
||||
|
||||
if [ ! -b "$TARGET_DEVICE" ]; then
|
||||
echo "❌ Device $TARGET_DEVICE not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Confirm
|
||||
echo ""
|
||||
echo "⚠️ WARNING: This will ERASE ALL DATA on $TARGET_DEVICE"
|
||||
echo ""
|
||||
read -p "Type 'yes' to continue: " CONFIRM
|
||||
|
||||
if [ "$CONFIRM" != "yes" ]; then
|
||||
echo "Aborted."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🔧 Partitioning $TARGET_DEVICE..."
|
||||
|
||||
# Unmount any existing partitions
|
||||
umount ${TARGET_DEVICE}* 2>/dev/null || true
|
||||
|
||||
# Create GPT partition table
|
||||
parted -s "$TARGET_DEVICE" mklabel gpt
|
||||
|
||||
# Create partitions:
|
||||
# 1. EFI System Partition (512MB)
|
||||
# 2. Root partition (remaining space)
|
||||
parted -s "$TARGET_DEVICE" mkpart primary fat32 1MiB 513MiB
|
||||
parted -s "$TARGET_DEVICE" set 1 esp on
|
||||
parted -s "$TARGET_DEVICE" mkpart primary ext4 513MiB 100%
|
||||
|
||||
# Wait for partitions to appear
|
||||
sleep 2
|
||||
|
||||
# Determine partition names (handle both /dev/sdX and /dev/nvmeXnYpZ naming)
|
||||
if [[ "$TARGET_DISK" == nvme* ]]; then
|
||||
EFI_PART="${TARGET_DEVICE}p1"
|
||||
ROOT_PART="${TARGET_DEVICE}p2"
|
||||
else
|
||||
EFI_PART="${TARGET_DEVICE}1"
|
||||
ROOT_PART="${TARGET_DEVICE}2"
|
||||
fi
|
||||
|
||||
echo "🗂️ Formatting partitions..."
|
||||
|
||||
# Format EFI partition
|
||||
mkfs.vfat -F32 -n ARCHIPELAGO "$EFI_PART"
|
||||
|
||||
# Format root partition
|
||||
mkfs.ext4 -L archipelago-root "$ROOT_PART"
|
||||
|
||||
echo "📦 Mounting partitions..."
|
||||
|
||||
# Create mount points
|
||||
mkdir -p /mnt/archipelago
|
||||
mount "$ROOT_PART" /mnt/archipelago
|
||||
mkdir -p /mnt/archipelago/boot/efi
|
||||
mount "$EFI_PART" /mnt/archipelago/boot/efi
|
||||
|
||||
echo "📋 Installing base system..."
|
||||
|
||||
# Install base system using debootstrap
|
||||
if command -v debootstrap >/dev/null 2>&1; then
|
||||
debootstrap --arch=amd64 trixie /mnt/archipelago http://deb.debian.org/debian
|
||||
else
|
||||
echo "❌ debootstrap not found. Installing..."
|
||||
apt-get update && apt-get install -y debootstrap
|
||||
debootstrap --arch=amd64 trixie /mnt/archipelago http://deb.debian.org/debian
|
||||
fi
|
||||
|
||||
echo "⚙️ Configuring system..."
|
||||
|
||||
# Mount virtual filesystems for chroot
|
||||
mount --bind /dev /mnt/archipelago/dev
|
||||
mount --bind /dev/pts /mnt/archipelago/dev/pts
|
||||
mount --bind /proc /mnt/archipelago/proc
|
||||
mount --bind /sys /mnt/archipelago/sys
|
||||
mount --bind /sys/firmware/efi/efivars /mnt/archipelago/sys/firmware/efi/efivars 2>/dev/null || true
|
||||
mount --bind /run /mnt/archipelago/run
|
||||
|
||||
# Create fstab
|
||||
cat > /mnt/archipelago/etc/fstab <<EOF
|
||||
# Archipelago Bitcoin Node OS
|
||||
UUID=$(blkid -s UUID -o value "$ROOT_PART") / ext4 errors=remount-ro 0 1
|
||||
UUID=$(blkid -s UUID -o value "$EFI_PART") /boot/efi vfat umask=0077 0 1
|
||||
EOF
|
||||
|
||||
# Set hostname
|
||||
echo "archipelago" > /mnt/archipelago/etc/hostname
|
||||
|
||||
# Configure hosts
|
||||
cat > /mnt/archipelago/etc/hosts <<EOF
|
||||
127.0.0.1 localhost
|
||||
127.0.1.1 archipelago
|
||||
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
EOF
|
||||
chmod 644 /mnt/archipelago/etc/hosts
|
||||
|
||||
# Install bootloader and essential packages in chroot
|
||||
echo "📦 Configuring package sources..."
|
||||
|
||||
# Create sources.list
|
||||
cat > /mnt/archipelago/etc/apt/sources.list <<EOF
|
||||
deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
|
||||
deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
|
||||
deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmware
|
||||
EOF
|
||||
|
||||
echo "📥 Updating package lists..."
|
||||
chroot /mnt/archipelago apt-get update
|
||||
|
||||
echo "🔒 Applying Debian security updates..."
|
||||
chroot /mnt/archipelago apt-get -y full-upgrade
|
||||
|
||||
echo "📦 Installing kernel and bootloader..."
|
||||
chroot /mnt/archipelago apt-get install -y linux-image-amd64 grub-efi-amd64 grub-efi-amd64-signed shim-signed
|
||||
|
||||
echo "📦 Installing essential packages..."
|
||||
chroot /mnt/archipelago apt-get install -y \
|
||||
sudo \
|
||||
network-manager \
|
||||
wpasupplicant \
|
||||
wireless-regdb \
|
||||
iw \
|
||||
rfkill \
|
||||
pciutils \
|
||||
usbutils \
|
||||
polkitd \
|
||||
openssh-server \
|
||||
curl \
|
||||
wget \
|
||||
htop \
|
||||
vim-tiny \
|
||||
nano \
|
||||
ca-certificates \
|
||||
chrony
|
||||
|
||||
echo "📦 Installing container tools..."
|
||||
chroot /mnt/archipelago apt-get install -y podman catatonit || echo "⚠️ Podman/catatonit not available in base repos, will use containers.io later"
|
||||
|
||||
echo "🔧 Installing GRUB bootloader..."
|
||||
# Need to run grub-install inside chroot with proper environment
|
||||
chroot /mnt/archipelago /bin/bash -c "
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=archipelago --recheck 2>&1 || \
|
||||
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=archipelago --removable 2>&1 || \
|
||||
echo '⚠️ GRUB install had issues, trying alternative...'
|
||||
"
|
||||
chroot /mnt/archipelago update-grub
|
||||
|
||||
echo "👤 Creating archipelago user..."
|
||||
# Create user first, then add to groups that exist
|
||||
chroot /mnt/archipelago useradd -m -s /bin/bash archipelago || echo "User may already exist"
|
||||
chroot /mnt/archipelago usermod -aG sudo archipelago || true
|
||||
chroot /mnt/archipelago usermod -aG podman archipelago 2>/dev/null || true
|
||||
|
||||
# Set password using chpasswd
|
||||
echo "archipelago:archipelago" | chroot /mnt/archipelago chpasswd
|
||||
|
||||
echo "⚙️ Enabling services..."
|
||||
chroot /mnt/archipelago systemctl enable NetworkManager || true
|
||||
chroot /mnt/archipelago systemctl enable polkit || chroot /mnt/archipelago systemctl enable polkit.service || true
|
||||
chroot /mnt/archipelago systemctl enable ssh || chroot /mnt/archipelago systemctl enable sshd || true
|
||||
chroot /mnt/archipelago systemctl enable chrony || true
|
||||
|
||||
mkdir -p /mnt/archipelago/etc/polkit-1/rules.d
|
||||
cat > /mnt/archipelago/etc/polkit-1/rules.d/49-archipelago-networkmanager.rules <<'EOF'
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (subject.user == "archipelago" && action.id.indexOf("org.freedesktop.NetworkManager.") == 0) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
EOF
|
||||
chmod 644 /mnt/archipelago/etc/polkit-1/rules.d/49-archipelago-networkmanager.rules
|
||||
|
||||
# Remove policy-rc.d so services can start on first boot
|
||||
rm -f /mnt/archipelago/usr/sbin/policy-rc.d
|
||||
|
||||
echo "💾 Creating swap file..."
|
||||
TOTAL_MEM_KB=$(chroot /mnt/archipelago grep MemTotal /proc/meminfo 2>/dev/null | awk '{print $2}')
|
||||
SWAP_GB=${TOTAL_MEM_KB:+$((TOTAL_MEM_KB / 1024 / 1024))}
|
||||
SWAP_GB=${SWAP_GB:-4}
|
||||
[ "$SWAP_GB" -gt 8 ] && SWAP_GB=8
|
||||
[ "$SWAP_GB" -lt 2 ] && SWAP_GB=2
|
||||
fallocate -l ${SWAP_GB}G /mnt/archipelago/swapfile 2>/dev/null || dd if=/dev/zero of=/mnt/archipelago/swapfile bs=1G count=$SWAP_GB status=progress
|
||||
chmod 600 /mnt/archipelago/swapfile
|
||||
chroot /mnt/archipelago mkswap /swapfile
|
||||
echo '/swapfile none swap sw 0 0' >> /mnt/archipelago/etc/fstab
|
||||
echo "✅ Created ${SWAP_GB}G swap"
|
||||
|
||||
echo "📁 Creating Archipelago directories..."
|
||||
chroot /mnt/archipelago mkdir -p /var/lib/archipelago/{data,config,containers}
|
||||
chroot /mnt/archipelago mkdir -p /etc/archipelago
|
||||
chroot /mnt/archipelago chown -R archipelago:archipelago /var/lib/archipelago
|
||||
|
||||
echo "✅ Base system configured"
|
||||
|
||||
# Copy Archipelago files
|
||||
echo "📋 Installing Archipelago components..."
|
||||
|
||||
BOOT_MEDIA=""
|
||||
for dev in /run/live/medium /lib/live/mount/medium /cdrom; do
|
||||
if [ -d "$dev/archipelago" ]; then
|
||||
BOOT_MEDIA="$dev"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$BOOT_MEDIA" ]; then
|
||||
echo " Copying from: $BOOT_MEDIA/archipelago"
|
||||
|
||||
# Copy entire archipelago directory
|
||||
mkdir -p /mnt/archipelago/opt/archipelago
|
||||
cp -r "$BOOT_MEDIA/archipelago/"* /mnt/archipelago/opt/archipelago/ 2>/dev/null || true
|
||||
|
||||
# Install binaries
|
||||
if [ -d "$BOOT_MEDIA/archipelago/bin" ]; then
|
||||
cp "$BOOT_MEDIA/archipelago/bin/"* /mnt/archipelago/usr/local/bin/ 2>/dev/null || true
|
||||
chmod +x /mnt/archipelago/usr/local/bin/* 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Install scripts
|
||||
if [ -d "$BOOT_MEDIA/archipelago/scripts" ]; then
|
||||
mkdir -p /mnt/archipelago/opt/archipelago/scripts
|
||||
cp "$BOOT_MEDIA/archipelago/scripts/"* /mnt/archipelago/opt/archipelago/scripts/ 2>/dev/null || true
|
||||
chmod +x /mnt/archipelago/opt/archipelago/scripts/*.sh 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Install app manifests
|
||||
if [ -d "$BOOT_MEDIA/archipelago/apps" ]; then
|
||||
mkdir -p /mnt/archipelago/etc/archipelago
|
||||
cp -r "$BOOT_MEDIA/archipelago/apps" /mnt/archipelago/etc/archipelago/
|
||||
fi
|
||||
|
||||
# Mesh radio udev rule: stable /dev/mesh-radio symlink + dialout perms
|
||||
# for known LoRa USB-serial chips (this installer never shipped it)
|
||||
for p in "$BOOT_MEDIA/99-mesh-radio.rules" "$BOOT_MEDIA/archipelago/configs/99-mesh-radio.rules"; do
|
||||
if [ -f "$p" ]; then
|
||||
mkdir -p /mnt/archipelago/etc/udev/rules.d
|
||||
cp "$p" /mnt/archipelago/etc/udev/rules.d/99-mesh-radio.rules
|
||||
chmod 644 /mnt/archipelago/etc/udev/rules.d/99-mesh-radio.rules
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Create profile.d script for welcome message on login
|
||||
mkdir -p /mnt/archipelago/etc/profile.d
|
||||
cat > /mnt/archipelago/etc/profile.d/archipelago.sh <<'PROFILE_EOF'
|
||||
#!/bin/bash
|
||||
# Archipelago welcome message
|
||||
if [ -t 0 ] && [ -z "$ARCHIPELAGO_WELCOMED" ]; then
|
||||
export ARCHIPELAGO_WELCOMED=1
|
||||
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
echo ""
|
||||
echo " ╔═══════════════════════════════════════════════════════════╗"
|
||||
echo " ║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
|
||||
echo " ╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
if [ -n "$IP" ]; then
|
||||
echo " ┌─────────────────────────────────────────────────────────────┐"
|
||||
echo " │ 🌐 Web UI: http://$IP:5678 │"
|
||||
echo " │ 📡 SSH: ssh archipelago@$IP │"
|
||||
echo " └─────────────────────────────────────────────────────────────┘"
|
||||
echo ""
|
||||
fi
|
||||
echo " Commands:"
|
||||
echo " archipelago - Start backend server"
|
||||
echo " archipelago-menu - Open setup menu"
|
||||
echo ""
|
||||
fi
|
||||
PROFILE_EOF
|
||||
chmod +x /mnt/archipelago/etc/profile.d/archipelago.sh
|
||||
|
||||
# Create systemd service to auto-start archipelago backend
|
||||
mkdir -p /mnt/archipelago/etc/systemd/system
|
||||
cat > /mnt/archipelago/etc/systemd/system/archipelago.service <<'SERVICE_EOF'
|
||||
[Unit]
|
||||
Description=Archipelago Backend Server
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
# Never start before the data volume (if one exists) is mounted — without this
|
||||
# the service races the mount on cold boot and "[FAILED]"-loops until it lands (B17)
|
||||
RequiresMountsFor=/var/lib/archipelago
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=archipelago
|
||||
ExecStart=/usr/local/bin/archipelago
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SERVICE_EOF
|
||||
|
||||
# Enable the service
|
||||
chroot /mnt/archipelago systemctl enable archipelago.service 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "🧹 Cleaning up..."
|
||||
|
||||
# Unmount in reverse order
|
||||
sync
|
||||
umount /mnt/archipelago/run 2>/dev/null || true
|
||||
umount /mnt/archipelago/sys/firmware/efi/efivars 2>/dev/null || true
|
||||
umount /mnt/archipelago/sys 2>/dev/null || true
|
||||
umount /mnt/archipelago/proc 2>/dev/null || true
|
||||
umount /mnt/archipelago/dev/pts 2>/dev/null || true
|
||||
umount /mnt/archipelago/dev 2>/dev/null || true
|
||||
umount /mnt/archipelago/boot/efi 2>/dev/null || true
|
||||
umount /mnt/archipelago 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ✅ INSTALLATION COMPLETE! ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Remove the USB drive and reboot to start Archipelago."
|
||||
echo ""
|
||||
echo "Default login:"
|
||||
echo " Username: archipelago"
|
||||
echo " Password: archipelago"
|
||||
echo ""
|
||||
echo "⚠️ Please change the password after first login!"
|
||||
echo ""
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Bitcoin Core Setup Script for Archipelago
|
||||
# Sets up Bitcoin Core in a Podman container
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ₿ BITCOIN CORE SETUP ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Check if running as root
|
||||
if [ "$EUID" -eq 0 ]; then
|
||||
echo "⚠️ Running as root. For rootless Podman, run as regular user."
|
||||
fi
|
||||
|
||||
# Check for Podman
|
||||
if ! command -v podman >/dev/null 2>&1; then
|
||||
echo "📦 Installing Podman..."
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y podman podman-compose
|
||||
fi
|
||||
|
||||
# Create data directory
|
||||
BITCOIN_DATA="${HOME}/.bitcoin"
|
||||
mkdir -p "$BITCOIN_DATA"
|
||||
|
||||
echo "📍 Bitcoin data directory: $BITCOIN_DATA"
|
||||
echo ""
|
||||
|
||||
# Ask for configuration
|
||||
echo "Bitcoin Core Configuration:"
|
||||
echo ""
|
||||
read -p "Enable pruning? (saves disk space) [y/N]: " PRUNE
|
||||
read -p "Enable txindex? (required for some apps) [y/N]: " TXINDEX
|
||||
read -p "RPC username [bitcoin]: " RPC_USER
|
||||
RPC_USER=${RPC_USER:-bitcoin}
|
||||
read -p "RPC password [randomly generated]: " RPC_PASS
|
||||
|
||||
if [ -z "$RPC_PASS" ]; then
|
||||
RPC_PASS=$(openssl rand -hex 16)
|
||||
echo " Generated RPC password: $RPC_PASS"
|
||||
fi
|
||||
|
||||
# Create bitcoin.conf
|
||||
cat > "$BITCOIN_DATA/bitcoin.conf" <<EOF
|
||||
# Archipelago Bitcoin Core Configuration
|
||||
|
||||
# Network
|
||||
server=1
|
||||
listen=1
|
||||
|
||||
# RPC
|
||||
rpcuser=$RPC_USER
|
||||
rpcpassword=$RPC_PASS
|
||||
rpcallowip=10.0.0.0/8
|
||||
rpcallowip=172.16.0.0/12
|
||||
rpcallowip=192.168.0.0/16
|
||||
|
||||
# Performance
|
||||
dbcache=450
|
||||
maxmempool=300
|
||||
|
||||
EOF
|
||||
|
||||
if [[ "$PRUNE" =~ ^[Yy]$ ]]; then
|
||||
echo "prune=550" >> "$BITCOIN_DATA/bitcoin.conf"
|
||||
echo " Pruning enabled (550MB)"
|
||||
fi
|
||||
|
||||
if [[ "$TXINDEX" =~ ^[Yy]$ ]]; then
|
||||
echo "txindex=1" >> "$BITCOIN_DATA/bitcoin.conf"
|
||||
echo " Transaction index enabled"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📋 Created bitcoin.conf"
|
||||
echo ""
|
||||
|
||||
# Pull Bitcoin Core image
|
||||
echo "🐳 Pulling Bitcoin Core container image..."
|
||||
podman pull docker.io/lncm/bitcoind:v27.0
|
||||
|
||||
# Create systemd user service for Bitcoin Core
|
||||
mkdir -p ~/.config/systemd/user
|
||||
|
||||
cat > ~/.config/systemd/user/bitcoind.service <<EOF
|
||||
[Unit]
|
||||
Description=Bitcoin Core (Podman)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=-/usr/bin/podman stop bitcoind
|
||||
ExecStartPre=-/usr/bin/podman rm bitcoind
|
||||
ExecStart=/usr/bin/podman run --name bitcoind \\
|
||||
--rm \\
|
||||
-v ${BITCOIN_DATA}:/data/.bitcoin:Z \\
|
||||
-p 8332:8332 \\
|
||||
-p 8333:8333 \\
|
||||
docker.io/lncm/bitcoind:v27.0
|
||||
ExecStop=/usr/bin/podman stop bitcoind
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
echo "📋 Created systemd service"
|
||||
echo ""
|
||||
|
||||
# Enable and start service
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable bitcoind.service
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ✅ BITCOIN CORE SETUP COMPLETE! ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " Start: systemctl --user start bitcoind"
|
||||
echo " Stop: systemctl --user stop bitcoind"
|
||||
echo " Status: systemctl --user status bitcoind"
|
||||
echo " Logs: podman logs -f bitcoind"
|
||||
echo ""
|
||||
echo "Bitcoin CLI:"
|
||||
echo " podman exec bitcoind bitcoin-cli -getinfo"
|
||||
echo ""
|
||||
echo "RPC Credentials (save these!):"
|
||||
echo " User: $RPC_USER"
|
||||
echo " Pass: $RPC_PASS"
|
||||
echo ""
|
||||
|
||||
read -p "Start Bitcoin Core now? [Y/n]: " START_NOW
|
||||
if [[ ! "$START_NOW" =~ ^[Nn]$ ]]; then
|
||||
echo ""
|
||||
echo "🚀 Starting Bitcoin Core..."
|
||||
systemctl --user start bitcoind
|
||||
echo ""
|
||||
echo "Bitcoin Core is syncing. This will take several hours/days."
|
||||
echo "Monitor with: podman logs -f bitcoind"
|
||||
fi
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# LND (Lightning Network Daemon) Setup Script for Archipelago
|
||||
# Sets up LND in a Podman container
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ⚡ LND (LIGHTNING) SETUP ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# Check for Podman
|
||||
if ! command -v podman >/dev/null 2>&1; then
|
||||
echo "❌ Podman not found. Please run setup-bitcoin.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if Bitcoin Core is running
|
||||
if ! podman ps | grep -q bitcoind; then
|
||||
echo "⚠️ Bitcoin Core is not running."
|
||||
echo " LND requires a synced Bitcoin Core node."
|
||||
read -p "Continue anyway? [y/N]: " CONTINUE
|
||||
if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create data directory
|
||||
LND_DATA="${HOME}/.lnd"
|
||||
mkdir -p "$LND_DATA"
|
||||
|
||||
echo "📍 LND data directory: $LND_DATA"
|
||||
echo ""
|
||||
|
||||
# Get Bitcoin RPC credentials
|
||||
BITCOIN_CONF="${HOME}/.bitcoin/bitcoin.conf"
|
||||
if [ -f "$BITCOIN_CONF" ]; then
|
||||
RPC_USER=$(grep "^rpcuser=" "$BITCOIN_CONF" | cut -d= -f2)
|
||||
RPC_PASS=$(grep "^rpcpassword=" "$BITCOIN_CONF" | cut -d= -f2)
|
||||
else
|
||||
read -p "Bitcoin RPC username: " RPC_USER
|
||||
read -p "Bitcoin RPC password: " RPC_PASS
|
||||
fi
|
||||
|
||||
# Ask for LND configuration
|
||||
echo "LND Configuration:"
|
||||
echo ""
|
||||
read -p "Node alias (public name): " LND_ALIAS
|
||||
LND_ALIAS=${LND_ALIAS:-archipelago-node}
|
||||
|
||||
# Create lnd.conf
|
||||
cat > "$LND_DATA/lnd.conf" <<EOF
|
||||
# Archipelago LND Configuration
|
||||
|
||||
[Application Options]
|
||||
alias=$LND_ALIAS
|
||||
color=#FF9900
|
||||
listen=0.0.0.0:9735
|
||||
rpclisten=0.0.0.0:10009
|
||||
restlisten=0.0.0.0:8080
|
||||
|
||||
# Automatically unlock wallet (create password file after first run)
|
||||
# wallet-unlock-password-file=/data/.lnd/password.txt
|
||||
|
||||
[Bitcoin]
|
||||
bitcoin.active=true
|
||||
bitcoin.mainnet=true
|
||||
bitcoin.node=bitcoind
|
||||
|
||||
[Bitcoind]
|
||||
bitcoind.rpchost=host.containers.internal:8332
|
||||
bitcoind.rpcuser=$RPC_USER
|
||||
bitcoind.rpcpass=$RPC_PASS
|
||||
bitcoind.zmqpubrawblock=tcp://host.containers.internal:28332
|
||||
bitcoind.zmqpubrawtx=tcp://host.containers.internal:28333
|
||||
|
||||
[tor]
|
||||
tor.active=false
|
||||
|
||||
[wtclient]
|
||||
wtclient.active=true
|
||||
EOF
|
||||
|
||||
echo "📋 Created lnd.conf"
|
||||
echo ""
|
||||
|
||||
# Pull LND image
|
||||
echo "🐳 Pulling LND container image..."
|
||||
podman pull docker.io/lightninglabs/lnd:v0.18.0-beta
|
||||
|
||||
# Create systemd user service for LND
|
||||
mkdir -p ~/.config/systemd/user
|
||||
|
||||
cat > ~/.config/systemd/user/lnd.service <<EOF
|
||||
[Unit]
|
||||
Description=LND Lightning Network Daemon (Podman)
|
||||
After=bitcoind.service
|
||||
Requires=bitcoind.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=-/usr/bin/podman stop lnd
|
||||
ExecStartPre=-/usr/bin/podman rm lnd
|
||||
ExecStart=/usr/bin/podman run --name lnd \\
|
||||
--rm \\
|
||||
--add-host=host.containers.internal:host-gateway \\
|
||||
-v ${LND_DATA}:/data/.lnd:Z \\
|
||||
-p 9735:9735 \\
|
||||
-p 10009:10009 \\
|
||||
-p 18080:8080 \\
|
||||
docker.io/lightninglabs/lnd:v0.18.0-beta \\
|
||||
--configfile=/data/.lnd/lnd.conf
|
||||
ExecStop=/usr/bin/podman stop lnd
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
EOF
|
||||
|
||||
echo "📋 Created systemd service"
|
||||
echo ""
|
||||
|
||||
# Enable service
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable lnd.service
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ ✅ LND SETUP COMPLETE! ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " Start: systemctl --user start lnd"
|
||||
echo " Stop: systemctl --user stop lnd"
|
||||
echo " Status: systemctl --user status lnd"
|
||||
echo " Logs: podman logs -f lnd"
|
||||
echo ""
|
||||
echo "LND CLI:"
|
||||
echo " podman exec lnd lncli --network=mainnet getinfo"
|
||||
echo ""
|
||||
echo "⚠️ IMPORTANT: On first start, you need to create a wallet:"
|
||||
echo " 1. Start LND: systemctl --user start lnd"
|
||||
echo " 2. Create wallet: podman exec -it lnd lncli create"
|
||||
echo " 3. Save your seed phrase securely!"
|
||||
echo ""
|
||||
|
||||
read -p "Start LND now? [Y/n]: " START_NOW
|
||||
if [[ ! "$START_NOW" =~ ^[Nn]$ ]]; then
|
||||
echo ""
|
||||
echo "🚀 Starting LND..."
|
||||
systemctl --user start lnd
|
||||
sleep 3
|
||||
echo ""
|
||||
echo "LND is starting. Create your wallet with:"
|
||||
echo " podman exec -it lnd lncli create"
|
||||
fi
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple API server for Archipelago Web UI
|
||||
Serves static files and handles basic API endpoints
|
||||
"""
|
||||
|
||||
import http.server
|
||||
import socketserver
|
||||
import json
|
||||
import os
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
|
||||
PORT = 80
|
||||
WEB_DIR = None
|
||||
|
||||
# Find web UI directory
|
||||
for path in ['/opt/archipelago/web-ui', '/run/live/medium/archipelago/web-ui', '/lib/live/mount/medium/archipelago/web-ui']:
|
||||
if os.path.isdir(path):
|
||||
WEB_DIR = path
|
||||
break
|
||||
|
||||
if not WEB_DIR:
|
||||
print("Web UI directory not found!")
|
||||
exit(1)
|
||||
|
||||
os.chdir(WEB_DIR)
|
||||
|
||||
class ArchipelagoHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
"""Handle POST requests with mock responses"""
|
||||
content_length = int(self.headers.get('Content-Length', 0))
|
||||
post_data = self.rfile.read(content_length) if content_length > 0 else b''
|
||||
|
||||
path = urlparse(self.path).path
|
||||
|
||||
# Mock API responses
|
||||
response = {"success": True}
|
||||
|
||||
if '/api/auth' in path or '/auth' in path:
|
||||
response = {
|
||||
"success": True,
|
||||
"token": "mock-token-12345",
|
||||
"user": "archipelago"
|
||||
}
|
||||
elif '/api/setup' in path or '/setup' in path:
|
||||
response = {
|
||||
"success": True,
|
||||
"status": "complete"
|
||||
}
|
||||
elif '/api/status' in path or '/status' in path:
|
||||
response = {
|
||||
"success": True,
|
||||
"status": "running",
|
||||
"version": "0.1.0",
|
||||
"hostname": "archipelago"
|
||||
}
|
||||
elif '/api/apps' in path or '/apps' in path:
|
||||
response = {
|
||||
"success": True,
|
||||
"apps": []
|
||||
}
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Access-Control-Allow-Origin', '*')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(response).encode())
|
||||
|
||||
def do_OPTIONS(self):
|
||||
"""Handle CORS preflight"""
|
||||
self.send_response(200)
|
||||
self.send_header('Access-Control-Allow-Origin', '*')
|
||||
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
|
||||
self.send_header('Access-Control-Allow-Headers', 'Content-Type, Authorization')
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
"""Handle GET requests - serve files or API"""
|
||||
path = urlparse(self.path).path
|
||||
|
||||
if path.startswith('/api/'):
|
||||
# Mock API GET endpoints
|
||||
response = {"success": True}
|
||||
|
||||
if '/status' in path:
|
||||
response = {
|
||||
"success": True,
|
||||
"status": "running",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
elif '/apps' in path:
|
||||
response = {
|
||||
"success": True,
|
||||
"apps": [
|
||||
{"id": "bitcoin", "name": "Bitcoin Core", "status": "available"},
|
||||
{"id": "lnd", "name": "Lightning (LND)", "status": "available"}
|
||||
]
|
||||
}
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', 'application/json')
|
||||
self.send_header('Access-Control-Allow-Origin', '*')
|
||||
self.end_headers()
|
||||
self.wfile.write(json.dumps(response).encode())
|
||||
else:
|
||||
# Serve static files, default to index.html for SPA routing
|
||||
if not os.path.exists(self.translate_path(self.path)) or path == '/':
|
||||
self.path = '/index.html'
|
||||
super().do_GET()
|
||||
|
||||
def log_message(self, format, *args):
|
||||
"""Quieter logging"""
|
||||
if '404' in str(args) or 'error' in str(args).lower():
|
||||
print(f" {args[0]}")
|
||||
|
||||
print(f"""
|
||||
╔═══════════════════════════════════════════════════════════╗
|
||||
║ 🏝️ ARCHIPELAGO WEB UI ║
|
||||
╚═══════════════════════════════════════════════════════════╝
|
||||
|
||||
Serving from: {WEB_DIR}
|
||||
|
||||
🌐 Open in your browser: http://localhost:{PORT}
|
||||
|
||||
Press Ctrl+C to stop
|
||||
""")
|
||||
|
||||
with socketserver.TCPServer(("0.0.0.0", PORT), ArchipelagoHandler) as httpd:
|
||||
try:
|
||||
httpd.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
print("\nShutting down...")
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Start Archipelago Backend Server
|
||||
# Serves the Vue.js UI and handles all API calls
|
||||
#
|
||||
|
||||
# Find archipelago binary
|
||||
ARCHIPELAGO_BIN=""
|
||||
for path in /usr/local/bin/archipelago /opt/archipelago/bin/archipelago /run/live/medium/archipelago/bin/archipelago; do
|
||||
if [ -x "$path" ]; then
|
||||
ARCHIPELAGO_BIN="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Get IP address
|
||||
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
|
||||
if [ -z "$IP" ]; then
|
||||
IP="localhost"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════════════════╗"
|
||||
echo "║ 🏝️ ARCHIPELAGO BITCOIN NODE OS ║"
|
||||
echo "╚═══════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo " Starting Archipelago server..."
|
||||
echo ""
|
||||
echo " ┌─────────────────────────────────────────────────────────┐"
|
||||
echo " │ │"
|
||||
echo " │ 🌐 OPEN IN YOUR BROWSER: │"
|
||||
echo " │ │"
|
||||
echo " │ http://$IP "
|
||||
echo " │ │"
|
||||
echo " └─────────────────────────────────────────────────────────┘"
|
||||
echo ""
|
||||
|
||||
if [ -n "$ARCHIPELAGO_BIN" ]; then
|
||||
echo " Using backend: $ARCHIPELAGO_BIN"
|
||||
echo " Press Ctrl+C to stop"
|
||||
echo ""
|
||||
|
||||
# Set environment for dev mode
|
||||
export ARCHIPELAGO_DEV_MODE=true
|
||||
export ARCHIPELAGO_DATA_DIR=/var/lib/archipelago
|
||||
export RUST_LOG=info
|
||||
|
||||
# Create data directory
|
||||
sudo mkdir -p /var/lib/archipelago 2>/dev/null
|
||||
|
||||
exec "$ARCHIPELAGO_BIN"
|
||||
else
|
||||
echo " ⚠️ Backend binary not found, using static file server"
|
||||
echo ""
|
||||
|
||||
# Fallback to static file server
|
||||
WEB_UI_DIR=""
|
||||
for path in /opt/archipelago/web-ui /run/live/medium/archipelago/web-ui; do
|
||||
if [ -d "$path" ]; then
|
||||
WEB_UI_DIR="$path"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$WEB_UI_DIR" ]; then
|
||||
cd "$WEB_UI_DIR"
|
||||
exec python3 -m http.server 80 --bind 0.0.0.0
|
||||
else
|
||||
echo "❌ Neither backend nor web UI found"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user