A production-ready, protocol-agnostic browser terminal. The UI renders an xterm.js terminal connected to a WebSocket provided by your backend API. The backend decides the connection protocol (SSH, AWS SSM, GCP IAP, Azure Bastion, etc.) — the UI is purely a WebSocket terminal client.
Browser Backend API Cloud Provider
| | |
|-- GET /api/sessions/:id -->| |
|<-- { websocketUrl } -------| |
| | |
|== WebSocket ===============|== SSH/SSM/IAP/etc. ======>|
| (raw text/binary) | (protocol-specific) |
- User authenticates (OIDC/Cognito)
- App calls
GET /api/sessions/{envId}with Bearer token - Backend returns
{ websocketUrl, sessionId } - xterm.js connects to the WebSocket URL
- User input flows as raw text; backend output flows as text/binary
npm install
npm run devThe dev server proxies /api to http://localhost:3001. Set environment variables in .env:
cp .env.example .env
# Edit .env with your OIDC provider detailsdocker build -t remote-access-ui .
docker run -p 8080:80 \
-e AUTH_PROVIDER=oidc \
-e OIDC_AUTHORITY=https://your-idp.example.com \
-e OIDC_CLIENT_ID=your-client-id \
-e API_BASE_URL=/api \
remote-access-uidocker compose up| Variable | Description | Default |
|---|---|---|
AUTH_PROVIDER |
Auth adapter: oidc or cognito |
oidc |
OIDC_AUTHORITY |
OIDC issuer URL (for oidc) or Cognito domain URL (for cognito) |
— |
OIDC_CLIENT_ID |
OAuth client ID | — |
OIDC_SCOPES |
OAuth scopes | openid email profile |
API_BASE_URL |
Backend API base URL | /api |
APP_TITLE |
Application title | Remote Access Terminal |
In development, prefix with VITE_ (e.g., VITE_AUTH_PROVIDER).
At runtime (Docker), environment variables are injected into config.js by the entrypoint script — no rebuild needed.
Request:
- Header:
Authorization: Bearer <token>
Response (200):
{
"websocketUrl": "wss://backend.example.com/ws/session-abc123",
"sessionId": "session-abc123"
}The UI sends and receives raw data over the WebSocket:
UI to Backend:
- User keystrokes: sent as raw text strings
- Terminal resize:
{"type":"resize","cols":120,"rows":40}
Backend to UI:
- Terminal output: raw text (string) or binary (ArrayBuffer)
The backend is responsible for translating between this raw WebSocket protocol and the underlying connection (SSH, SSM, etc.).
{
"containerDefinitions": [{
"name": "remote-access-ui",
"image": "ghcr.io/inceptionstack/standalone-remote-access-ui:latest",
"portMappings": [{ "containerPort": 80 }],
"environment": [
{ "name": "AUTH_PROVIDER", "value": "cognito" },
{ "name": "OIDC_AUTHORITY", "value": "https://your-domain.auth.us-east-1.amazoncognito.com" },
{ "name": "OIDC_CLIENT_ID", "value": "your-client-id" },
{ "name": "API_BASE_URL", "value": "/api" }
],
"healthCheck": {
"command": ["CMD-SHELL", "wget -qO- http://localhost/health || exit 1"],
"interval": 30,
"timeout": 5,
"retries": 3,
"startPeriod": 10
}
}]
}apiVersion: apps/v1
kind: Deployment
metadata:
name: remote-access-ui
spec:
replicas: 2
selector:
matchLabels:
app: remote-access-ui
template:
metadata:
labels:
app: remote-access-ui
spec:
containers:
- name: ui
image: ghcr.io/inceptionstack/standalone-remote-access-ui:latest
ports:
- containerPort: 80
env:
- name: AUTH_PROVIDER
value: "oidc"
- name: OIDC_AUTHORITY
value: "https://your-idp.example.com"
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
name: remote-access-secrets
key: oidc-client-id
- name: API_BASE_URL
value: "/api"
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 5
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 3
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: remote-access-ui
spec:
selector:
app: remote-access-ui
ports:
- port: 80
targetPort: 80