#!/bin/bash # Run with sudo: sudo bash scripts/install-tor-onion.sh # Regenerates Tor + nginx from scripts/onion-nodes.json, installs configs only when # they changed, restores backed-up onion keys if any service dirs are missing, and # starts/restarts nginx + Tor only when required. set -euo pipefail [[ "${EUID}" -eq 0 ]] || { echo "Run as root (sudo)."; exit 1; } REPO="$(cd "$(dirname "$0")/.." && pwd)" TORRC="/etc/tor/torrc" TOR_INCLUDE="/etc/tor/cyberlux-nodes.conf" if ! command -v node >/dev/null 2>&1; then echo "node is required to run scripts/generate-onion-config.cjs" exit 1 fi install_if_changed() { local src="$1" dest="$2" mode="$3" if [[ -f "${dest}" ]] && cmp -s "${src}" "${dest}"; then return 1 fi install -m "${mode}" "${src}" "${dest}" return 0 } tor_is_active() { systemctl is-active --quiet tor@default.service 2>/dev/null || systemctl is-active --quiet tor 2>/dev/null } nginx_is_active() { systemctl is-active --quiet nginx 2>/dev/null } restart_tor() { systemctl restart tor@default.service 2>/dev/null || systemctl restart tor } start_tor() { systemctl start tor@default.service 2>/dev/null || systemctl start tor } node "${REPO}/scripts/generate-onion-config.cjs" mkdir -p /etc/tor /etc/nginx/conf.d /etc/nginx/sites-available /etc/nginx/sites-enabled touch "${TORRC}" tor_changed=0 nginx_changed=0 if install_if_changed "${REPO}/tor/cyberlux-nodes.conf" "${TOR_INCLUDE}" 0644; then tor_changed=1 fi if grep -qF '%include /etc/tor/cyberlux-onion.conf' "${TORRC}"; then sed -i '\|%include /etc/tor/cyberlux-onion.conf|d' "${TORRC}" tor_changed=1 fi if ! grep -qF "${TOR_INCLUDE}" "${TORRC}"; then printf '\n%%include %s\n' "${TOR_INCLUDE}" >> "${TORRC}" tor_changed=1 fi if install_if_changed "${REPO}/nginx/cyberlux-ddos-zones.conf" /etc/nginx/conf.d/cyberlux-ddos-zones.conf 0644; then nginx_changed=1 fi if install_if_changed "${REPO}/nginx/cyberlux-server-common.inc" /etc/nginx/cyberlux-server-common.inc 0644; then nginx_changed=1 fi if install_if_changed "${REPO}/nginx.example.conf" /etc/nginx/sites-available/cyberlux-onion 0644; then nginx_changed=1 fi ln -sf /etc/nginx/sites-available/cyberlux-onion /etc/nginx/sites-enabled/cyberlux-onion if [[ -x "${REPO}/scripts/restore-onion-keys.sh" ]]; then bash "${REPO}/scripts/restore-onion-keys.sh" fi nginx -t if command -v tor >/dev/null 2>&1; then tor --verify-config -f "${TORRC}" >/dev/null fi if (( nginx_changed )); then systemctl reload nginx 2>/dev/null || systemctl restart nginx elif ! nginx_is_active; then systemctl start nginx fi if (( tor_changed )); then restart_tor elif ! tor_is_active; then start_tor fi # Hidden services proxy to nginx → Next on 127.0.0.1:3000. If Next is down, every .onion returns 502. if command -v curl >/dev/null 2>&1; then up="$(curl -g -sS -o /dev/null -w "%{http_code}" --connect-timeout 2 --max-time 5 "http://127.0.0.1:3000/" 2>/dev/null)" || up="000" if [[ ! "${up}" =~ ^(200|301|302|304)$ ]]; then echo "[!] Next.js is not serving on 127.0.0.1:3000 (HTTP ${up}) — onion URLs will fail until it is running." >&2 echo " Start: cd ${REPO} && npm run start:onion or: sudo systemctl start cyberlux.service" >&2 echo " Install service: sudo CYBERLUX_USER=\${SUDO_USER:-\$USER} bash ${REPO}/scripts/install-systemd.sh" >&2 fi fi # Refresh repo-root onion-urls.txt while we have root (hostname dirs are 0700 debian-tor). if [[ -f "${REPO}/scripts/export-onion-urls.sh" ]]; then bash "${REPO}/scripts/export-onion-urls.sh" || true fi if [[ "${CYBERLUX_INSTALL_QUIET:-}" == "1" ]]; then exit 0 fi echo "" echo "CyberLux Tor nodes (see hostname files):" while IFS= read -r dir || [[ -n "${dir}" ]]; do [[ -z "${dir}" ]] && continue f="/var/lib/tor/${dir}/hostname" if [[ -f "$f" ]]; then echo " ${dir}: http://$(tr -d '\n' < "$f")" else echo " ${dir}: (generating…) sudo cat $f" fi done < "${REPO}/scripts/generated/tor-dirs.txt" echo "" echo "Config status:" echo " • Tor: $([[ ${tor_changed} -eq 1 ]] && echo changed || echo unchanged)" echo " • nginx: $([[ ${nginx_changed} -eq 1 ]] && echo changed || echo unchanged)" echo "" echo "Host hardening:" echo " • Next: npm run start:onion (127.0.0.1:3000)" echo " • Do not expose 3000 or nginx loopback ports to the public internet." echo " • Onion key backup set: /var/backups/cyberlux-onion-keys/current" echo " • Optional: sudo bash ${REPO}/scripts/classroom-ufw.sh" echo "" echo "Start app: cd ${REPO} && ./start.sh or npm run build && npm run start:onion"