diff --git a/Makefile b/Makefile index 914e55c..52db38f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install install-cli db db-tools migrate seed api dashboard check start clean register-project validate-adr add-domain rename-domain add-repo list-repos cleanup-stale +.PHONY: install install-cli db db-tools migrate seed api dashboard check start clean register-project validate-adr add-domain rename-domain add-repo list-repos cleanup-stale tunnel tunnel-daemon tunnel-loop tunnel-status tunnel-stop COMPOSE = docker compose -f infra/docker-compose.yml --env-file .env @@ -34,14 +34,65 @@ dashboard: check: curl -sf http://127.0.0.1:8000/state/health | python3 -m json.tool -## Open a reverse SSH tunnel so a remote host can reach the local State Hub. -## Usage: make tunnel HOST=user@hostname -## The remote host will then reach the hub at http://127.0.0.1:8000 +## COULOMBCORE host (default target for tunnel targets) +COULOMBCORE ?= tegwick@92.205.130.254 +TUNNEL_PORT ?= 8000 + +## Foreground reverse tunnel — good for debugging. Ctrl-C to stop. +## Usage: make tunnel HOST=tegwick@92.205.130.254 tunnel: @test -n "$(HOST)" || (echo "ERROR: HOST is required. Usage: make tunnel HOST=user@hostname"; exit 1) - @echo "Opening reverse tunnel → $(HOST) (remote :8000 → local :8000)" + @echo "Opening reverse tunnel → $(HOST) (remote :$(TUNNEL_PORT) → local :$(TUNNEL_PORT))" @echo "Keep this terminal open. Ctrl-C to close the tunnel." - ssh -R 8000:127.0.0.1:8000 $(HOST) + ssh -N -o "ServerAliveInterval=30" -o "ServerAliveCountMax=3" \ + -R $(TUNNEL_PORT):127.0.0.1:$(TUNNEL_PORT) $(HOST) + +## Background tunnel to COULOMBCORE with auto-reconnect. +## Uses autossh if available; prints install hint and exits if not. +## After running, COULOMBCORE can reach the State Hub at http://127.0.0.1:8000 +tunnel-daemon: + @if command -v autossh >/dev/null 2>&1; then \ + echo "Starting autossh tunnel → $(COULOMBCORE)"; \ + autossh -f -N -M 0 \ + -o "ServerAliveInterval=30" \ + -o "ServerAliveCountMax=3" \ + -o "ExitOnForwardFailure=yes" \ + -R $(TUNNEL_PORT):127.0.0.1:$(TUNNEL_PORT) $(COULOMBCORE); \ + echo "Tunnel running in background. Use 'make tunnel-status' to check."; \ + else \ + echo "autossh not found — install it: sudo apt-get install autossh"; \ + echo "Fallback: run 'make tunnel-loop HOST=$(COULOMBCORE)' in a dedicated terminal."; \ + exit 1; \ + fi + +## Reconnect loop — works without autossh. Run in a terminal you can leave open. +## Usage: make tunnel-loop HOST=tegwick@92.205.130.254 +tunnel-loop: + @test -n "$(HOST)" || (echo "ERROR: HOST is required. Usage: make tunnel-loop HOST=user@hostname"; exit 1) + @echo "Reconnect loop → $(HOST). Ctrl-C to stop." + @while true; do \ + echo "[$(shell date -u +%Y-%m-%dT%H:%M:%SZ)] Connecting..."; \ + ssh -N -o "ServerAliveInterval=30" -o "ServerAliveCountMax=3" \ + -o "ExitOnForwardFailure=yes" \ + -R $(TUNNEL_PORT):127.0.0.1:$(TUNNEL_PORT) $(HOST) || true; \ + echo "[$(shell date -u +%Y-%m-%dT%H:%M:%SZ)] Connection lost — retrying in 5s..."; \ + sleep 5; \ + done + +## Check whether a tunnel is currently active +tunnel-status: + @if command -v autossh >/dev/null 2>&1 && pgrep -f "autossh.*$(TUNNEL_PORT)" > /dev/null 2>&1; then \ + echo "autossh tunnel: RUNNING (PIDs: $$(pgrep -f 'autossh.*$(TUNNEL_PORT)' | tr '\n' ' '))"; \ + elif pgrep -f "ssh.*-R $(TUNNEL_PORT)" > /dev/null 2>&1; then \ + echo "ssh tunnel: RUNNING (PIDs: $$(pgrep -f 'ssh.*-R $(TUNNEL_PORT)' | tr '\n' ' '))"; \ + else \ + echo "Tunnel: NOT running"; \ + fi + +## Stop any active tunnel (autossh or plain ssh) +tunnel-stop: + @pkill -f "autossh.*$(TUNNEL_PORT)" 2>/dev/null && echo "autossh stopped" || true + @pkill -f "ssh.*-R $(TUNNEL_PORT)" 2>/dev/null && echo "ssh loop stopped" || true start: db sleep 3