From 7520aff3732db09872a95ec5981d3a89cea4a287 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 17 Feb 2026 18:34:51 +0000 Subject: [PATCH] security: restrict picoclaw access to tailscale tailnet only - Bind Docker port to 127.0.0.1 only (not publicly exposed) - Remove UFW rule that opened port 18790 to the internet - Install Tailscale in setup-server.sh with optional auth key - Configure tailscale serve to proxy tailnet -> localhost:18790 - Add deploy workflow step to ensure tailscale serve stays active Port 18790 is now only reachable via the tailnet, not the public internet. https://claude.ai/code/session_019vXaqxGmkdCjM8m3jp6rYj --- .github/workflows/deploy-hostinger.yml | 23 +++++++++++++ .../hostinger/docker-compose.production.yml | 2 +- deploy/hostinger/setup-server.sh | 33 +++++++++++++++---- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy-hostinger.yml b/.github/workflows/deploy-hostinger.yml index c6a3c62e9..de8346ef4 100644 --- a/.github/workflows/deploy-hostinger.yml +++ b/.github/workflows/deploy-hostinger.yml @@ -110,6 +110,29 @@ jobs: echo "Docker deploy complete" EOF + - name: Ensure Tailscale serve is active + env: + SSHPASS: ${{ secrets.HOSTINGER_SSH_PASSWORD }} + run: | + SSH_PORT="${{ secrets.HOSTINGER_SSH_PORT }}" + SSH_PORT="${SSH_PORT:-22}" + SSH_USER="${{ secrets.HOSTINGER_SSH_USER }}" + SSH_USER="${SSH_USER:-root}" + + sshpass -e ssh \ + -o StrictHostKeyChecking=accept-new \ + -o ConnectTimeout=15 \ + -p "${SSH_PORT}" \ + "${SSH_USER}@${{ secrets.HOSTINGER_HOST }}" <<'EOF' + if command -v tailscale &>/dev/null && tailscale status &>/dev/null 2>&1; then + tailscale serve --bg http://localhost:18790 2>/dev/null || true + echo "Tailscale serve active on tailnet" + tailscale ip -4 2>/dev/null && echo "(use the IP above or tailnet hostname to access)" + else + echo "::warning::Tailscale not installed or not authenticated. Run setup-server.sh first." + fi + EOF + - name: Health check env: SSHPASS: ${{ secrets.HOSTINGER_SSH_PASSWORD }} diff --git a/deploy/hostinger/docker-compose.production.yml b/deploy/hostinger/docker-compose.production.yml index 3109c3653..09bcdb8d7 100644 --- a/deploy/hostinger/docker-compose.production.yml +++ b/deploy/hostinger/docker-compose.production.yml @@ -15,7 +15,7 @@ services: container_name: picoclaw-gateway restart: unless-stopped ports: - - "18790:18790" + - "127.0.0.1:18790:18790" volumes: # Configuration (read-only) - /opt/picoclaw/config/config.json:/root/.picoclaw/config.json:ro diff --git a/deploy/hostinger/setup-server.sh b/deploy/hostinger/setup-server.sh index 999fcc43e..6c959bdb1 100755 --- a/deploy/hostinger/setup-server.sh +++ b/deploy/hostinger/setup-server.sh @@ -130,18 +130,37 @@ if command -v ufw &>/dev/null; then ufw default deny incoming ufw default allow outgoing ufw allow ssh - ufw allow 18790/tcp comment "PicoClaw Gateway" - # Uncomment if you need webhook ports: - # ufw allow 18791/tcp comment "PicoClaw Line Webhook" + # Port 18790 is NOT opened publicly - accessible only via Tailscale ufw --force enable - log "UFW firewall configured" + log "UFW firewall configured (port 18790 is tailscale-only)" elif command -v firewall-cmd &>/dev/null; then systemctl enable firewalld systemctl start firewalld firewall-cmd --permanent --add-service=ssh - firewall-cmd --permanent --add-port=18790/tcp + # Port 18790 is NOT opened publicly - accessible only via Tailscale firewall-cmd --reload - log "firewalld configured" + log "firewalld configured (port 18790 is tailscale-only)" +fi + +# ── 6b. Install and configure Tailscale ────────────── +log "Installing Tailscale..." +if ! command -v tailscale &>/dev/null; then + curl -fsSL https://tailscale.com/install.sh | sh + log "Tailscale installed" +else + log "Tailscale already installed: $(tailscale version 2>/dev/null | head -1)" +fi + +if [ -n "${TAILSCALE_AUTH_KEY:-}" ]; then + log "Authenticating Tailscale with auth key..." + tailscale up --authkey="${TAILSCALE_AUTH_KEY}" --hostname="picoclaw" --ssh + log "Tailscale authenticated. Configuring serve..." + tailscale serve --bg http://localhost:18790 + log "Tailscale serve active: https://picoclaw.TAILNET.ts.net -> localhost:18790" +else + warn "TAILSCALE_AUTH_KEY not set. Run manually after setup:" + warn " tailscale up --hostname=picoclaw --ssh" + warn " tailscale serve --bg http://localhost:18790" fi # ── 7. Configure fail2ban ──────────────────────────── @@ -300,5 +319,5 @@ else echo " 6. View logs: tail -f ${PICOCLAW_HOME}/logs/picoclaw.log" fi echo "" -log "Firewall ports open: SSH (22), PicoClaw Gateway (18790)" +log "Firewall ports open: SSH (22) only. Port 18790 accessible via Tailscale only." echo ""