Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

OpenVSCode SSH Gateway

Single-process gateway for OpenVSCode servers on SSH hosts, with independently managed editor sessions.

Quick start

uv sync
cp .env.example .env
uv run python scripts/create-password-hash.py
uv run uvicorn vscode_gateway.app:create_app --factory --workers 1

The example environment uses local-only HTTP defaults and pins OpenVSCode Server 1.109.5 for Linux x64 and arm64. Set the canonical origin, cookie security, host allowlist, and proxy settings for the deployment environment before exposing the gateway.

The optional server-backed web user-data feature requires the local OpenVSCode fork in openvscode-server/. A validated Linux x64 archive is available at openvscode-server/.build/releases/openvscode-server-v1.109.5-remote-user-data-linux-x64.tar.gz with SHA-256 1ccdcae0da8129852144fd867f9e0d6d0cd32c6bc5b4bfd6afce3e443df9aa44. Host that archive on an HTTP(S) endpoint, configure the matching OpenVSCode version, URL, and digest, then set VSC_GATEWAY_OPENVSCODE_USE_REMOTE_USER_DATA=true. Build and configure a separate arm64 archive before enabling the option for arm64 hosts.

This breaking schema requires a fresh current-schema state/gateway.db; databases from previous schemas are rejected and no prior state is imported. The database, its WAL, and backups contain uploaded private key material, so protect them and their access paths.

Before starting this version, remove the obsolete VSC_GATEWAY_SSH_DIR, VSC_GATEWAY_SSH_CONFIG_PATH, VSC_GATEWAY_SSH_KNOWN_HOSTS_PATH, and VSC_GATEWAY_SSH_KEYS_DIR entries from existing environment files.

Using the gateway

  • Hosts come from literal SSH config Host aliases. Edit the config at /settings/ssh.
  • Under /settings/keys, upload an unlimited number of named, unencrypted private keys for Ed25519, ECDSA, and RSA. The first uploaded key for each type becomes its default; the page also supports promotion and same-name replacement. A configured IdentityFile names uploaded keys exactly, in order, for that target or jump and disables fallback to defaults. When it is absent, the per-type defaults are used. Names are case-sensitive identifiers matching [A-Za-z0-9][A-Za-z0-9._-]{0,63}; none is reserved. IdentityAgent is not supported, while RemoteCommand is supported. Deleting a default does not silently promote another key; assign a replacement default explicitly when fallback authentication should remain available.
  • Click Open on a host card to connect over SSH and start its shared OpenVSCode server. Unknown or changed host keys require explicit fingerprint verification on the card, followed by the existing Retry flow.
  • Once a host is ready, New Session creates a folderless gateway URL to the shared server. Opening a folder records it from OpenVSCode's ?folder= URL. Only one session can own a folder on a host. Folder changes rotate the session URL, and opening the same folder elsewhere revokes its previous URL. Multiple folderless sessions remain allowed.
  • The dashboard keeps working-directory history across host closes and shows whether each directory currently has an editor WebSocket. Open always creates a fresh session and revokes any active or inactive predecessor; Forget removes its history. Folderless sessions are hidden but included in the host's total session count.
  • If authentication fails, use the card links back to SSH Config and SSH Keys to correct the connection settings or manage uploaded keys.

Architecture

One process, one origin, one SQLite file. SQLite is canonical for the SSH config, named key metadata and private/public material, and exact host trust. Hosts are literal SSH config Host aliases. Each open host owns one SSH chain, one tunnel, and one folderless loopback-only OpenVSCode process. Multiple editor sessions share that host runtime and its remote user-data and server-data. The same-origin proxy publishes it at /editor/{session_id}/..., strips that prefix upstream, and advertises it to OpenVSCode with X-Forwarded-Prefix. Session URLs do not expire when browser WebSockets disconnect. Reconnection state is instead retained by OpenVSCode itself for VSC_GATEWAY_OPENVSCODE_RECONNECTION_GRACE_TIME seconds. The Linux memfd config adapter supplies each DB configuration snapshot to AsyncSSH without creating a durable SSH config file. Configured ProxyJump routes are expanded and opened explicitly by SshConnectionService. Every hop uses uploaded keys and DB-derived in-memory host trust, captures host-key challenges, disables ambient authentication, and is owned and cleaned up with the host. Unknown jump and target keys can require sequential Trust/Retry steps; nested and multi-hop routes reject malformed endpoints, cycles, and excessive depth.

Remote state is stored directly under ~/.vscode-gateway: shared runtime installations, user-data, server-data, and UUID-scoped process runs. An atomic remote server.lock prevents different aliases or gateway instances from running concurrent OpenVSCode processes against the same remote state directory.

With VSC_GATEWAY_OPENVSCODE_USE_REMOTE_USER_DATA=true, the fork stores web profiles, settings, keybindings, snippets, and application/workspace SQLite state under ~/.vscode-gateway/user-data/User instead of browser IndexedDB or local storage. Web and remote extension metadata use separate server-side profile manifests. Browser logs and local file handles can still use IndexedDB. Changing this setting does not alter a process already running or recovered by the gateway; explicitly close and reopen each host after changing it. Startup selects the exact configured <version>-<sha256> runtime, so an older installed stock archive cannot be selected accidentally.

The session and dashboard API contracts are the current breaking contract. There are no SSH path environment variables or durable SSH config, host-trust, or key files. Uploaded private keys remain in SQLite, its WAL, and backups; restrict permissions and backup access accordingly.

Named key endpoints are:

GET    /api/ssh/keys
POST   /api/ssh/keys                 multipart: name, private_key
PUT    /api/ssh/keys/{name}          replace private material, same type
PUT    /api/ssh/keys/{name}/default  promote within the key type
GET    /api/ssh/keys/{name}/public
DELETE /api/ssh/keys/{name}

IdentityFile values are exact case-sensitive names. A present list is used in its configured order with no default fallback; an absent list uses the per-type defaults.

Development

uv run ruff check . && uv run ruff format --check .
uv run pyright
uv run pytest

The default integration case launches an ephemeral OpenSSH server on localhost and uses a small synthetic editor artifact while exercising the real API, SSH, SFTP, forwarding, runtime, and proxy paths:

uv run pytest tests/integration -m "not real_editor"

To run the same lifecycle against a real OpenVSCode archive, provide a local release archive:

VSC_GATEWAY_TEST_OPENVSCODE_ARCHIVE=/path/to/openvscode-server.tar.gz \
  VSC_GATEWAY_TEST_OPENVSCODE_VERSION=1.109.5 \
  uv run pytest tests/integration -m real_editor

Alternatively, set VSC_GATEWAY_TEST_OPENVSCODE_URL and VSC_GATEWAY_TEST_OPENVSCODE_SHA256. The real-editor case is skipped when neither source is configured. This case enables VSC_GATEWAY_OPENVSCODE_USE_REMOTE_USER_DATA, so the supplied archive must support the fork's --use-remote-user-data option.

Build the local x64 fork with Node 22.21.1:

cd openvscode-server
npm ci
npm run compile-check-ts-native
npm run gulp compile-build-without-mangling
npm run compile-extensions-build
npm run minify-vscode-reh-web
npm run gulp vscode-reh-web-linux-x64-min-ci
tar --owner=0 --group=0 -czf openvscode-server-remote-user-data-linux-x64.tar.gz \
  -C .. vscode-reh-web-linux-x64

Use vscode-reh-web-linux-arm64-min-ci and an arm64 dependency install to produce the corresponding arm64 artifact.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages