Files
dark-lord/start.sh
2026-04-26 22:28:40 -07:00

260 lines
8.5 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# CyberLux — single entry: regenerate onion config, deps, build, Tor/nginx,
# self-heal onion key directories from backup, wait for hostname readiness,
# print all .onion URLs, back them up, then start Next.
#
# ./start.sh
# git pull && ./start.sh
#
# Env (optional):
# CYBERLUX_SKIP_GIT_PULL=1
# CYBERLUX_SKIP_TOR=1 — local only → http://127.0.0.1:3000
# CYBERLUX_DEPLOY_SEED=n
# CYBERLUX_RANDOM_SEED=1
# CYBERLUX_SKIP_ONION_BACKUP=1
# CYBERLUX_PREPARE_ONLY=1 — build + Tor/nginx install, then exit (no Next.js; use with systemd)
set -euo pipefail
REPO="$(cd "$(dirname "$0")" && pwd)"
cd "${REPO}"
if ! command -v node >/dev/null 2>&1; then
echo "[!] node not found (required for scripts/generate-onion-config.cjs)."
exit 1
fi
echo "[*] Regenerating Tor/nginx/app maps from scripts/onion-nodes.json"
node "${REPO}/scripts/generate-onion-config.cjs"
TOR_DIRS_FILE="${REPO}/scripts/generated/tor-dirs.txt"
LABELS_FILE="${REPO}/scripts/generated/onion-labels.tsv"
RANGE_FILE="${REPO}/scripts/generated/onion-port-range.txt"
RESTORE_SCRIPT="${REPO}/scripts/restore-onion-keys.sh"
BACKUP_SCRIPT="${REPO}/scripts/backup-onion-keys.sh"
if [[ ! -f "${TOR_DIRS_FILE}" ]]; then
echo "[!] Missing ${TOR_DIRS_FILE} — generator failed."
exit 1
fi
declare -A CYBERLUX_ROLE=()
if [[ -f "${LABELS_FILE}" ]]; then
while IFS=$'\t' read -r dir desc || [[ -n "${dir}" ]]; do
[[ -z "${dir}" ]] && continue
CYBERLUX_ROLE["${dir}"]="${desc}"
done < "${LABELS_FILE}"
fi
read -r ONION_PORT_MIN ONION_PORT_MAX < "${RANGE_FILE}" || true
ONION_PORT_MIN="${ONION_PORT_MIN:-8080}"
ONION_PORT_MAX="${ONION_PORT_MAX:-8080}"
mapfile -t CYBERLUX_TOR_DIRS < "${TOR_DIRS_FILE}"
count_ready_hostnames() {
local ready=0
local dir
for dir in "${CYBERLUX_TOR_DIRS[@]}"; do
[[ -z "${dir}" ]] && continue
if sudo test -s "/var/lib/tor/${dir}/hostname" 2>/dev/null; then
((ready++)) || true
fi
done
echo "${ready}"
}
wait_for_all_hostnames() {
local max_wait="${1:-90}"
local waited=0
local total=0
local ready=0
total="${#CYBERLUX_TOR_DIRS[@]}"
while (( waited < max_wait )); do
ready="$(count_ready_hostnames)"
if (( ready >= total )); then
return 0
fi
sleep 1
((waited++)) || true
done
ready="$(count_ready_hostnames)"
echo "[!] Timeout waiting for onion hostname files (${ready}/${total} ready)." >&2
return 1
}
print_onion_banner() {
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " CYBERLUX — copy this .onion URL (Tor Browser, http:// only)"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
local any=0
local ready=0
for dir in "${CYBERLUX_TOR_DIRS[@]}"; do
[[ -z "${dir}" ]] && continue
local f="/var/lib/tor/${dir}/hostname"
local onion=""
if onion=$(sudo cat "${f}" 2>/dev/null | tr -d '\n'); then
any=1
((ready++)) || true
printf " %-26s %s\n" "${dir}" "http://${onion}"
printf " %-26s %s\n" "" "${CYBERLUX_ROLE[$dir]:-}"
echo ""
else
printf " %-26s %s\n" "${dir}" "(hostname not readable — sudo cat ${f})"
echo ""
fi
done
if [[ "${any}" -eq 0 ]]; then
echo " [!] Could not read hostnames. Check: sudo systemctl status tor"
echo ""
fi
echo " Hostnames ready: ${ready}/${#CYBERLUX_TOR_DIRS[@]}"
echo ""
echo " Loopback (do not bind publicly):"
echo " Next.js http://127.0.0.1:3000"
echo " nginx 127.0.0.1:${ONION_PORT_MIN}${ONION_PORT_MAX} → Next (one port per .onion)"
echo ""
echo " Service status:"
if command -v systemctl >/dev/null 2>&1; then
if systemctl is-active --quiet tor@default.service 2>/dev/null || systemctl is-active --quiet tor 2>/dev/null; then
echo " tor: active"
else
echo " tor: inactive or unknown"
fi
if systemctl is-active --quiet nginx 2>/dev/null; then
echo " nginx: active"
else
echo " nginx: inactive or unknown"
fi
else
echo " (systemctl not found)"
fi
echo ""
echo " Onion key backup:"
echo " /var/backups/cyberlux-onion-keys/current"
echo ""
echo " Firewall (optional): sudo bash ${REPO}/scripts/classroom-ufw.sh"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
}
# --- Deploy seed (optional) ---
if [[ -n "${CYBERLUX_DEPLOY_SEED:-}" ]]; then
export NEXT_PUBLIC_DEPLOY_SEED="${CYBERLUX_DEPLOY_SEED}"
echo "[*] NEXT_PUBLIC_DEPLOY_SEED=${NEXT_PUBLIC_DEPLOY_SEED} (from env)"
elif [[ "${CYBERLUX_RANDOM_SEED:-}" == "1" ]]; then
export NEXT_PUBLIC_DEPLOY_SEED=$((RANDOM % 10000))
echo "[*] NEXT_PUBLIC_DEPLOY_SEED=${NEXT_PUBLIC_DEPLOY_SEED} (random)"
fi
if [[ -d .git ]] && [[ "${CYBERLUX_SKIP_GIT_PULL:-}" != "1" ]]; then
echo "[*] git pull --ff-only"
if ! git pull --ff-only; then
echo "[!] git pull failed (offline, dirty tree, or no upstream). Continuing — use CYBERLUX_SKIP_GIT_PULL=1 to skip this step."
fi
fi
if ! command -v npm >/dev/null 2>&1; then
echo "[!] npm not found. Install Node.js LTS."
exit 1
fi
echo "[*] npm install"
npm install
# Root-owned .next (e.g. after `sudo npm run build`) breaks `next build` — fix with sudo once.
if [[ -d "${REPO}/.next" ]] && [[ ! -w "${REPO}/.next" ]]; then
echo "[*] .next/ is not writable (often root-owned). Repairing ownership (sudo may ask for password)…"
if command -v sudo >/dev/null 2>&1; then
sudo chown -R "$(id -un):$(id -gn)" "${REPO}/.next" || {
echo "[!] Could not chown .next. Run manually:"
echo " sudo bash ${REPO}/scripts/fix-next-perms.sh"
exit 1
}
else
echo "[!] No sudo — run as root once: chown -R \$(whoami) ${REPO}/.next"
exit 1
fi
fi
echo "[*] npm run build"
if ! npm run build; then
echo ""
echo "[!] Build failed. Common fix after a root-owned build:"
echo " sudo bash ${REPO}/scripts/fix-next-perms.sh"
echo " ./start.sh"
exit 1
fi
if command -v ss >/dev/null 2>&1; then
if ss -ltn 2>/dev/null | grep -qE '127\.0\.0\.1:3000\b'; then
echo "[!] Something is already listening on 127.0.0.1:3000 — stop it first."
exit 1
fi
elif command -v lsof >/dev/null 2>&1; then
if lsof -iTCP:3000 -sTCP:LISTEN >/dev/null 2>&1; then
echo "[!] Port 3000 is in use."
exit 1
fi
fi
if [[ "${CYBERLUX_SKIP_TOR:-}" == "1" ]]; then
echo "[*] CYBERLUX_SKIP_TOR=1 — skipping Tor/nginx. Open http://127.0.0.1:3000"
echo ""
else
if ! command -v sudo >/dev/null 2>&1; then
echo "[!] sudo required for Tor/nginx install."
exit 1
fi
bin_exists() {
command -v "$1" >/dev/null 2>&1 || [[ -x "/usr/bin/$1" ]] || [[ -x "/usr/sbin/$1" ]] || [[ -x "/sbin/$1" ]]
}
for bin in tor nginx; do
if ! bin_exists "$bin"; then
echo "[!] Missing '${bin}'. On Debian/Ubuntu: sudo apt install tor nginx"
exit 1
fi
done
if [[ ! -f "${REPO}/scripts/install-tor-onion.sh" ]]; then
echo "[!] Missing install script."
exit 1
fi
if [[ -f "${RESTORE_SCRIPT}" ]]; then
echo "[*] Restoring backed-up onion keys (missing dirs only)…"
sudo bash "${RESTORE_SCRIPT}"
fi
echo "[*] Installing Tor + nginx (sudo)…"
sudo env CYBERLUX_INSTALL_QUIET=1 bash "${REPO}/scripts/install-tor-onion.sh"
echo "[*] Waiting for Tor hostname files…"
wait_for_all_hostnames 90 || true
if [[ "${CYBERLUX_SKIP_ONION_BACKUP:-}" != "1" ]] && [[ -f "${BACKUP_SCRIPT}" ]]; then
echo "[*] Refreshing onion key backup set…"
sudo bash "${BACKUP_SCRIPT}" || echo "[!] Onion key backup refresh failed."
fi
if [[ -f "${REPO}/scripts/export-onion-urls.sh" ]]; then
echo "[*] Exporting live .onion list to onion-urls.txt (readable without /var/lib/tor access)…"
sudo bash "${REPO}/scripts/export-onion-urls.sh" || echo "[!] export-onion-urls.sh failed (URLs still in Tor; re-run with sudo if needed)."
fi
print_onion_banner
fi
if [[ "${CYBERLUX_PREPARE_ONLY:-}" == "1" ]]; then
echo "[*] CYBERLUX_PREPARE_ONLY=1 — skipping Next.js start (use: systemctl start cyberlux.service)"
exit 0
fi
echo "[*] Starting Next.js on 127.0.0.1:3000 (Ctrl+C to stop)"
exec npm run start:onion