This repository has been archived on 2026-03-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
2026-03-23 14:51:59 +00:00

197 lines
8.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# ============================================================
# Timmy Bitcoin Node — One-shot bootstrap for Ubuntu 22.04 LTS
# Run as root on a fresh Digital Ocean droplet:
# bash setup.sh
# ============================================================
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${CYAN}[setup]${NC} $*"; }
ok() { echo -e "${GREEN}[ok]${NC} $*"; }
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
die() { echo -e "${RED}[error]${NC} $*"; exit 1; }
[[ $EUID -ne 0 ]] && die "Run as root: sudo bash setup.sh"
# ── 0. Config ────────────────────────────────────────────────
DATA_DIR="/data"
INFRA_DIR="/opt/timmy-node"
RPC_PASS=$(openssl rand -hex 24)
info "Starting Timmy node setup..."
echo ""
# ── 1. System packages ───────────────────────────────────────
info "Updating system packages..."
apt-get update -qq
apt-get upgrade -y -qq
apt-get install -y -qq curl wget git ufw jq openssl
# ── 2. Docker ────────────────────────────────────────────────
info "Installing Docker..."
if ! command -v docker &>/dev/null; then
curl -fsSL https://get.docker.com | sh
systemctl enable docker
systemctl start docker
fi
docker --version
ok "Docker ready"
# ── 3. Tailscale ─────────────────────────────────────────────
info "Installing Tailscale..."
if ! command -v tailscale &>/dev/null; then
curl -fsSL https://tailscale.com/install.sh | sh
fi
ok "Tailscale installed — you will authenticate it after this script finishes"
# ── 4. Firewall ──────────────────────────────────────────────
info "Configuring UFW firewall..."
ufw --force reset
# Allow Tailscale
ufw allow in on tailscale0
# Bitcoin P2P
ufw allow 8333/tcp comment "Bitcoin P2P"
# Lightning P2P
ufw allow 9735/tcp comment "Lightning P2P"
# SSH via Tailscale only — but keep public SSH open until Tailscale is confirmed
# (after Tailscale auth, you can run: ufw delete allow 22)
ufw allow 22/tcp comment "SSH (disable after Tailscale is confirmed)"
ufw default deny incoming
ufw default allow outgoing
ufw --force enable
ok "Firewall configured"
# ── 5. Mount the DO block volume ─────────────────────────────
info "Setting up data volume..."
# Digital Ocean attaches block volumes at /dev/sda or /dev/disk/by-id/scsi-...
# Find the attached volume (should be the largest unmounted disk)
VOLUME_DEV=$(lsblk -rno NAME,SIZE,MOUNTPOINT | awk '$3=="" && $2~/G/ {print $1}' | grep -v "^sda$" | head -1)
if [[ -z "$VOLUME_DEV" ]]; then
warn "Could not auto-detect a block volume. If you attached a DO Volume,"
warn "run: lsblk to find it, then: mkfs.ext4 /dev/<name> && mount /dev/<name> /data"
warn "Then re-run this script or continue manually."
mkdir -p "$DATA_DIR"
else
VOLUME_PATH="/dev/$VOLUME_DEV"
info "Found volume at $VOLUME_PATH"
# Format only if not already formatted
if ! blkid "$VOLUME_PATH" &>/dev/null; then
info "Formatting $VOLUME_PATH with ext4..."
mkfs.ext4 -F "$VOLUME_PATH"
fi
mkdir -p "$DATA_DIR"
mount "$VOLUME_PATH" "$DATA_DIR"
# Persist mount across reboots
BLKID=$(blkid -s UUID -o value "$VOLUME_PATH")
if ! grep -q "$BLKID" /etc/fstab; then
echo "UUID=$BLKID $DATA_DIR ext4 defaults,nofail 0 2" >> /etc/fstab
fi
ok "Volume mounted at $DATA_DIR"
fi
# ── 6. Directory structure ───────────────────────────────────
info "Creating directory structure..."
mkdir -p \
"$DATA_DIR/bitcoin" \
"$DATA_DIR/lnd" \
"$DATA_DIR/lnbits" \
"$INFRA_DIR/configs"
ok "Directories ready"
# ── 7. Copy configs & inject RPC password ────────────────────
info "Installing configs..."
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Bitcoin config — bitcoinknots/bitcoin image uses /home/bitcoin/.bitcoin inside container
# which maps to $DATA_DIR/bitcoin on the host via the Docker volume bind
cp "$SCRIPT_DIR/configs/bitcoin.conf" "$DATA_DIR/bitcoin/bitcoin.conf"
echo "rpcpassword=$RPC_PASS" >> "$DATA_DIR/bitcoin/bitcoin.conf"
# LND config — inject rpcpass
cp "$SCRIPT_DIR/configs/lnd.conf" "$INFRA_DIR/configs/lnd.conf"
sed -i "s/# bitcoind.rpcpass is written by setup.sh at runtime/bitcoind.rpcpass=$RPC_PASS/" \
"$INFRA_DIR/configs/lnd.conf"
# Mount lnd.conf into container via docker-compose override
cat > "$INFRA_DIR/docker-compose.override.yml" <<OVERRIDE
services:
lnd:
volumes:
- lnd_data:/root/.lnd
- $INFRA_DIR/configs/lnd.conf:/root/.lnd/lnd.conf:ro
OVERRIDE
# Copy main docker-compose and scripts
cp "$SCRIPT_DIR/docker-compose.yml" "$INFRA_DIR/docker-compose.yml"
cp "$SCRIPT_DIR/lnd-init.sh" "$INFRA_DIR/lnd-init.sh"
cp "$SCRIPT_DIR/sweep.sh" "$INFRA_DIR/sweep.sh"
cp "$SCRIPT_DIR/ops.sh" "$INFRA_DIR/ops.sh"
# Install default sweep config (lnd-init.sh will overwrite with user's cold address)
if [[ ! -f "$INFRA_DIR/sweep.conf" ]]; then
cp "$SCRIPT_DIR/sweep.conf" "$INFRA_DIR/sweep.conf"
chmod 600 "$INFRA_DIR/sweep.conf"
fi
chmod +x "$INFRA_DIR/lnd-init.sh" "$INFRA_DIR/sweep.sh" "$INFRA_DIR/ops.sh"
ok "Configs installed"
# ── 7b. Install cron jobs ─────────────────────────────────────
info "Installing cron jobs (daily sweep + daily backup)..."
# Remove any existing Timmy cron entries before re-adding
crontab -l 2>/dev/null | grep -v "timmy-node" | crontab - || true
(crontab -l 2>/dev/null; cat <<'CRON'
# Timmy Node — auto-sweep hot wallet to cold storage (3am UTC daily)
# sweep.sh manages its own logging to /var/log/timmy-sweep.log via tee
0 3 * * * bash /opt/timmy-node/sweep.sh > /dev/null 2>&1
# Timmy Node — LND channel state backup (4am UTC daily)
0 4 * * * bash /opt/timmy-node/ops.sh backup >> /var/log/timmy-backup.log 2>&1
CRON
) | crontab -
touch /var/log/timmy-sweep.log /var/log/timmy-backup.log
ok "Cron jobs installed (sweep 3am, backup 4am UTC)"
# ── 8. Save credentials ──────────────────────────────────────
CREDS_FILE="/root/node-credentials.txt"
cat > "$CREDS_FILE" <<CREDS
# Timmy Node Credentials — keep this safe
# Generated: $(date -u)
BITCOIN_RPC_USER=satoshi
BITCOIN_RPC_PASS=$RPC_PASS
CREDS
chmod 600 "$CREDS_FILE"
ok "Credentials saved to $CREDS_FILE"
# ── 9. Start Bitcoin Core ────────────────────────────────────
info "Starting Bitcoin Core (this begins chain sync — will take days)..."
cd "$INFRA_DIR"
docker compose up -d bitcoin
ok "Bitcoin Core started"
# ── 10. Done ─────────────────────────────────────────────────
echo ""
echo -e "${GREEN}════════════════════════════════════════${NC}"
echo -e "${GREEN} Setup complete — next steps:${NC}"
echo -e "${GREEN}════════════════════════════════════════${NC}"
echo ""
echo -e " 1. ${CYAN}Authenticate Tailscale:${NC}"
echo -e " tailscale up --ssh"
echo -e " (copy the auth URL, open in browser, log in)"
echo ""
echo -e " 2. ${CYAN}Verify Tailscale SSH works${NC} from another device:"
echo -e " ssh root@<node-name> (via Tailscale MagicDNS)"
echo -e " Then lock down public SSH:"
echo -e " ufw delete allow 22"
echo ""
echo -e " 3. ${CYAN}Check Bitcoin sync progress:${NC}"
echo -e " watch -n 10 'docker exec bitcoin bitcoin-cli getblockchaininfo | jq .verificationprogress'"
echo -e " (will show 0.0 → 1.0 over several days)"
echo ""
echo -e " 4. ${CYAN}Once sync reaches ~1.0, initialize LND:${NC}"
echo -e " bash $INFRA_DIR/lnd-init.sh"
echo ""
echo -e " Credentials: ${YELLOW}cat $CREDS_FILE${NC}"
echo ""