Browser-based remote control (noVNC) with invite links, per-user access control, garagedoor SSO and a persisted client list. The hub proxies RFB rather than pointing the browser at a VNC server. That is what lets it authenticate upstream with a stored password the browser never sees, and enforce view-only by dropping input messages on the client->server stream instead of hiding buttons. Machines are reachable two ways: direct TCP for LAN hosts, or an outbound agent tunnel for anything behind NAT. Node 22's global WebSocket keeps the agent dependency-free, and node:sqlite keeps the image free of native builds. Ships with an end-to-end suite that boots the real server against a fake VNC server and a fake auth service (72 assertions), plus Gitea Actions CI/CD to Portainer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
40 lines
1.3 KiB
YAML
40 lines
1.3 KiB
YAML
# Deployed to Portainer (Swarm endpoint) by .gitea/workflows/deploy.yml.
|
|
# ${IMAGE} and the secrets below are injected as env_data at deploy time.
|
|
#
|
|
# Two constraints this stack cannot break:
|
|
# 1. exactly one replica — agent control sockets and live sessions are held in
|
|
# process memory, so a second replica would not see the first one's agents;
|
|
# 2. pinned placement — the SQLite volume is node-local, so the task has to
|
|
# come back to the same node or it wakes up with an empty database.
|
|
services:
|
|
remote-control-support:
|
|
image: ${IMAGE:-git.mancinas.io/rmancinas/remote-control-support-webapp:latest}
|
|
ports:
|
|
- "8091:8080"
|
|
environment:
|
|
DB_PATH: /data/rcs.db
|
|
TRUST_PROXY: "true"
|
|
AUTH_URL: ${AUTH_URL:-http://192.168.4.208:8000}
|
|
ADMIN_USERS: ${ADMIN_USERS:-}
|
|
ADMIN_LEVEL: ${ADMIN_LEVEL:-}
|
|
ENCRYPTION_KEY: ${ENCRYPTION_KEY:-}
|
|
PUBLIC_URL: ${PUBLIC_URL:-}
|
|
ALLOW_SESSION_INVITES: ${ALLOW_SESSION_INVITES:-true}
|
|
volumes:
|
|
- rcs_data:/data
|
|
deploy:
|
|
replicas: 1
|
|
placement:
|
|
constraints:
|
|
- node.role == manager
|
|
update_config:
|
|
# start-first would briefly run two containers against one SQLite file.
|
|
order: stop-first
|
|
failure_action: rollback
|
|
restart_policy:
|
|
condition: any
|
|
delay: 10s
|
|
|
|
volumes:
|
|
rcs_data:
|