diff --git a/bin/disinto b/bin/disinto index 3b31f94..c9f1845 100755 --- a/bin/disinto +++ b/bin/disinto @@ -1693,7 +1693,7 @@ disinto_edge() { # SSH to edge host and register echo "Registering tunnel for ${project} on ${edge_host}..." local response - response=$(ssh -o StrictHostKeyChecking=no -o BatchMode=yes \ + response=$(ssh -o StrictHostKeyChecking=accept-new -o BatchMode=yes \ "disinto-register@${edge_host}" \ "register ${project} ${pubkey}" 2>&1) || { echo "Error: failed to register tunnel" >&2 @@ -1712,7 +1712,14 @@ disinto_edge() { exit 1 fi - # Write to .env + # Write to .env (replace existing entries to avoid duplicates) + local tmp_env + tmp_env=$(mktemp) + grep -v "^EDGE_TUNNEL_HOST=" "$env_file" > "$tmp_env" 2>/dev/null || true + grep -v "^EDGE_TUNNEL_PORT=" "$env_file" >> "$tmp_env" 2>/dev/null || true + grep -v "^EDGE_TUNNEL_FQDN=" "$env_file" >> "$tmp_env" 2>/dev/null || true + cat "$tmp_env" > "$env_file" + rm -f "$tmp_env" echo "EDGE_TUNNEL_HOST=${edge_host}" >> "$env_file" echo "EDGE_TUNNEL_PORT=${port}" >> "$env_file" echo "EDGE_TUNNEL_FQDN=${fqdn}" >> "$env_file" @@ -1768,9 +1775,7 @@ disinto_edge() { if [ -f "$env_file" ]; then local tmp_env tmp_env=$(mktemp) - grep -v "^EDGE_TUNNEL_HOST=" "$env_file" > "$tmp_env" 2>/dev/null || true - grep -v "^EDGE_TUNNEL_PORT=" "$env_file" >> "$tmp_env" 2>/dev/null || true - grep -v "^EDGE_TUNNEL_FQDN=" "$env_file" >> "$tmp_env" 2>/dev/null || true + grep -Ev "^EDGE_TUNNEL_(HOST|PORT|FQDN)=" "$env_file" > "$tmp_env" 2>/dev/null || true mv "$tmp_env" "$env_file" fi diff --git a/tools/edge-control/install.sh b/tools/edge-control/install.sh index 8c98262..b525d3e 100755 --- a/tools/edge-control/install.sh +++ b/tools/edge-control/install.sh @@ -42,6 +42,7 @@ GANDI_TOKEN="" INSTALL_DIR="/opt/disinto-edge" REGISTRY_DIR="/var/lib/disinto" CADDY_VERSION="2.8.4" +DOMAIN_SUFFIX="disinto.ai" usage() { cat < Install directory (default: /opt/disinto-edge) --registry-dir Registry directory (default: /var/lib/disinto) --caddy-version Caddy version to install (default: ${CADDY_VERSION}) + --domain-suffix Domain suffix for tunnels (default: disinto.ai) -h, --help Show this help Example: @@ -78,6 +80,10 @@ while [[ $# -gt 0 ]]; do CADDY_VERSION="$2" shift 2 ;; + --domain-suffix) + DOMAIN_SUFFIX="$2" + shift 2 + ;; -h|--help) usage ;; @@ -164,11 +170,12 @@ if ! command -v caddy &>/dev/null; then } fi -# Download Caddy binary directly (faster than building) -CADDY_LINUX_AMD64="https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}/caddy_${CADDY_VERSION}_linux_amd64" +# Download Caddy with Gandi DNS plugin using Caddy's download API +# The API returns a binary with specified plugins baked in +CADDY_DOWNLOAD_API="https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com/caddy-dns/gandi" -log_info "Downloading Caddy..." -curl -sL "$CADDY_LINUX_AMD64" -o /tmp/caddy +log_info "Downloading Caddy with Gandi DNS plugin..." +curl -sL "$CADDY_DOWNLOAD_API" -o /tmp/caddy chmod +x /tmp/caddy # Verify it works @@ -177,6 +184,11 @@ if ! /tmp/caddy version &>/dev/null; then exit 1 fi +# Check for Gandi plugin +if ! /tmp/caddy version 2>&1 | grep -qi gandi; then + log_warn "Gandi plugin not found in Caddy binary - DNS-01 challenge will fail" +fi + mv /tmp/caddy "$CADDY_BINARY" log_info "Installed Caddy: $CADDY_BINARY" @@ -250,11 +262,11 @@ log_info "Installing control plane scripts to ${INSTALL_DIR}..." mkdir -p "${INSTALL_DIR}/lib" -# Copy scripts -cp -n "${BASH_SOURCE%/*}/register.sh" "${INSTALL_DIR}/" -cp -n "${BASH_SOURCE%/*}/lib/ports.sh" "${INSTALL_DIR}/lib/" -cp -n "${BASH_SOURCE%/*}/lib/authorized_keys.sh" "${INSTALL_DIR}/lib/" -cp -n "${BASH_SOURCE%/*}/lib/caddy.sh" "${INSTALL_DIR}/lib/" +# Copy scripts (overwrite existing to ensure idempotent updates) +cp "${BASH_SOURCE%/*}/register.sh" "${INSTALL_DIR}/" +cp "${BASH_SOURCE%/*}/lib/ports.sh" "${INSTALL_DIR}/lib/" +cp "${BASH_SOURCE%/*}/lib/authorized_keys.sh" "${INSTALL_DIR}/lib/" +cp "${BASH_SOURCE%/*}/lib/caddy.sh" "${INSTALL_DIR}/lib/" chmod +x "${INSTALL_DIR}/register.sh" chmod +x "${INSTALL_DIR}/lib/"*.sh @@ -330,10 +342,7 @@ fi # ============================================================================= # Step 7: Final configuration # ============================================================================= -log_info "Setting environment variables..." - -# Set DOMAIN_SUFFIX in register.sh -sed -i "s/DOMAIN_SUFFIX=\"${DOMAIN_SUFFIX:-disinto.ai}\"/DOMAIN_SUFFIX=\"${DOMAIN_SUFFIX:-disinto.ai}\"/" "${INSTALL_DIR}/register.sh" +log_info "Configuring domain suffix: ${DOMAIN_SUFFIX}" # Reload systemd if needed systemctl daemon-reload 2>/dev/null || true diff --git a/tools/edge-control/lib/authorized_keys.sh b/tools/edge-control/lib/authorized_keys.sh index 26f8af7..e0f1175 100755 --- a/tools/edge-control/lib/authorized_keys.sh +++ b/tools/edge-control/lib/authorized_keys.sh @@ -14,8 +14,8 @@ # ============================================================================= set -euo pipefail -# Source ports library -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +# Source ports library (SCRIPT_DIR is this file's directory, so lib/ports.sh is adjacent) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "${SCRIPT_DIR}/ports.sh" # Tunnel user home directory diff --git a/tools/edge-control/lib/caddy.sh b/tools/edge-control/lib/caddy.sh index f8759e0..92bc01e 100755 --- a/tools/edge-control/lib/caddy.sh +++ b/tools/edge-control/lib/caddy.sh @@ -26,73 +26,50 @@ add_route() { local port="$2" local fqdn="${project}.${DOMAIN_SUFFIX}" - # Build Caddy site block configuration - local config - config=$(cat <&1) || { + -d "$route_config" 2>&1) || { echo "Error: failed to add route for ${fqdn}" >&2 echo "Response: ${response}" >&2 return 1 } - # Check response - local loaded - loaded=$(echo "$response" | jq -r '.loaded // empty' 2>/dev/null) || loaded="" - - if [ "$loaded" = "true" ]; then - echo "Added route: ${fqdn} → 127.0.0.1:${port}" - else - echo "Warning: Caddy admin response: ${response}" >&2 - # Don't fail hard - config might have been merged successfully - fi + echo "Added route: ${fqdn} → 127.0.0.1:${port}" } # Remove a route for a project @@ -101,11 +78,33 @@ remove_route() { local project="$1" local fqdn="${project}.${DOMAIN_SUFFIX}" - # Use Caddy admin API to delete the config for this host - # We need to delete the specific host match from the config + # First, get current routes + local routes_json + routes_json=$(curl -s "${CADDY_ADMIN_URL}/config/apps/http/servers/edge/routes" 2>&1) || { + echo "Error: failed to get current routes" >&2 + return 1 + } + + # Find the route index that matches our fqdn + local route_index=-1 + local idx=0 + while IFS= read -r host; do + if [ "$host" = "$fqdn" ]; then + route_index=$idx + break + fi + idx=$((idx + 1)) + done < <(echo "$routes_json" | jq -r '.[].match[].host[]' 2>/dev/null) + + if [ "$route_index" -lt 0 ]; then + echo "Warning: route for ${fqdn} not found" >&2 + return 0 + fi + + # Delete the route at the found index local response response=$(curl -s -X DELETE \ - "${CADDY_ADMIN_URL}/config/apps/http/servers/edge/routes/0" \ + "${CADDY_ADMIN_URL}/config/apps/http/servers/edge/routes/${route_index}" \ -H "Content-Type: application/json" 2>&1) || { echo "Error: failed to remove route for ${fqdn}" >&2 echo "Response: ${response}" >&2