headplane/remote-access
Ryan Malloy 7c21720519
Some checks are pending
Build / native (push) Waiting to run
Build / nix (push) Waiting to run
Complete the Astro rewrite
Drop the entire app/ Remix tree (144 deletions) and replace with the
Astro + Alpine.js architecture under src/. The Remix entrypoint, routes,
components, layouts, server bindings, and types are all gone; the Astro
pages (acls, dns, machines, settings, terminal, users, login, index)
plus their API endpoints under src/pages/api/ now own the surface.

Other surfaces touched:
- package.json: drop react-router, react-router-hono-server, remix-utils
  and the rest of the Remix stack; pull in Astro + integrations + Alpine
- pnpm-lock.yaml: regenerated against the new dependency set
- astro.config.mjs added; vite.config.ts, react-router.config.ts dropped
- New src/lib/auth/ (oidc-client, role-mapper, session-manager) and
  src/lib/config/authentik.ts for env-driven config
- biome.json: enable VCS-aware filtering, exclude .astro/dist/data/
  upstream/ and the React Router backup
- Extensive docs (HEADY_MANIFESTO, AUTHENTIK_*, BETTER_ROLE_MAPPING* etc.)
  and example role-mapping yamls added under examples/
- New remote-access/ tree for the Guacamole-Lite integration
- terminal.astro: prerender disabled (data is request-time only)

Committed with --no-verify; biome auto-fix was applied first but there
are still lint warnings in the new code worth a separate cleanup pass.
The legacy app/ tree was never re-pushed after the rewrite, which is
why the Gitea/Docker builds were trying to compile app/routes/ssh/
console.tsx.
2026-06-06 13:05:35 -06:00
..
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00
2026-06-06 13:05:35 -06:00

🤠 Heady Remote Access

Secure, lightweight remote access for awesome VPN management. Replaces the problematic 38MB WASM SSH console with a production-grade architecture.

Architecture

  • FastAPI Backend: Lightweight Python ASGI server
  • Official Guacd: Separate container using maintained guacamole/guacd image
  • WebSocket Bridge: Real-time communication between browser and guacd
  • OIDC Integration: Role-based access control from Heady's authentication system

Features

🔐 Security-First Design

  • Server-side connections: SSH keys never leave the infrastructure
  • Role-based access: Integrates with Heady OIDC role mapping
  • Session recording: Audit trails for privileged access
  • Connection isolation: Each session in separate context

🚀 Protocols Supported

  • SSH: Terminal access to Linux/Unix systems
  • RDP: Windows desktop access (for IT admin role)
  • VNC: General desktop access
  • Telnet: Legacy system support
  • Kubernetes: Container access (experimental)

📊 Session Management

  • Active session tracking: Monitor concurrent connections
  • Recording capabilities: Automatic recording for admin roles
  • Audit logging: Complete session history
  • Self-service termination: Users can manage their own sessions

Quick Start

# Clone the implementation
cd /path/to/heady/remote-access

# Configure environment
cp .env.example .env
# Edit .env with your settings

# Start services
docker compose up -d

# Check health
curl http://localhost:8000/health

Integration with Heady

OIDC Role Permissions

Role SSH RDP VNC Recording Admin Nodes
owner
admin
network_admin
it_admin
auditor
member

Environment Variables

# Guacd connection
GUACD_HOST=heady-guacd
GUACD_PORT=4822

# Heady integration
HEADPLANE_API_URL=http://headplane:3000
JWT_SECRET=your-secret-key

# Optional configuration
GUACD_LOG_LEVEL=info
HEADY_DOMAIN=remote.yourdomain.com

API Endpoints

WebSocket

  • GET /terminal/{node_name}?protocol=ssh - Terminal WebSocket connection

REST API

  • GET /health - Health check
  • GET /sessions - List user sessions
  • DELETE /sessions/{session_id} - Terminate session

Development

# Install dependencies
pip install -r requirements.txt

# Run in development mode
uvicorn main:app --reload --host 0.0.0.0 --port 8000

# Run with guacd in development
docker compose -f docker-compose.dev.yml up guacd

Differences from WASM Approach

Metric 38MB WASM Heady Remote Access
Bundle Size 38MB <1MB
Security Client-side crypto Server-side only
Protocols SSH only SSH, RDP, VNC, Telnet, K8s
Recording None Full session recording
Mobile Poor Responsive WebSocket
Maintenance Complex Go build Standard containers
Enterprise Ready No Yes

Production Deployment

With Existing Heady Stack

Add to your main docker-compose.yml:

services:
  # ... existing heady services ...
  
  heady-remote-access:
    build: ./remote-access
    environment:
      - HEADPLANE_API_URL=http://heady:3000
      - JWT_SECRET=${JWT_SECRET}
    depends_on:
      - heady-guacd
      - heady
    
  heady-guacd:
    image: guacamole/guacd:latest
    volumes:
      - ./recordings:/recordings:rw

Kubernetes Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: heady-remote-access
spec:
  replicas: 2
  selector:
    matchLabels:
      app: heady-remote-access
  template:
    spec:
      containers:
      - name: remote-access
        image: heady/remote-access:latest
        env:
        - name: GUACD_HOST
          value: "heady-guacd"
        - name: HEADPLANE_API_URL
          value: "http://heady:3000"
      - name: guacd
        image: guacamole/guacd:latest

Security Considerations

  • Network isolation: Guacd in separate container network
  • TLS termination: All WebSocket connections over WSS
  • Session timeouts: Automatic cleanup of stale connections
  • Audit compliance: Complete session logging and recording
  • Principle of least privilege: Role-based protocol access

Heady Remote Access: Because VPN infrastructure deserves secure, awesome remote management! 🤠