Skip to main content

Sitecard

Issue temporary SSH access cards for development sites and workspaces.

This directory holds only the static sanitized README staged into the generated sitecard distribution. The distributable package itself is generated by scripts/build-sitecard-dist.sh and never checked in.

What it is

Sitecard opens temporary SSH access to a selected development workspace for remote debugging and compatibility testing. The site is the workspace host; the card is the short-lived access path. Fresh Sitecard sessions allow public access by default because they are disposable. Pass --no-public-access to require credentials.

  • Distribution name: sitecard
  • Version: 0.1.6
  • Description: Issue temporary SSH access cards for development workspaces
  • Requires Python >=3.10
  • Console script: sitecard = sitecard.commands:main

What it is not

The generated distribution contains no deployment helpers, local secrets, target addresses, assessment keys, tests, or unrelated files.

Build

From the repository root:

sh scripts/build-sitecard-dist.sh

Artifacts land in dist/sitecard/. The build fails if any case-insensitive occurrence of the internal project name remains in staging files, archive entry names, or archive file contents.

Authenticated access (--no-public-access)

Public mode is the default and needs no keys.

For --no-public-access with a non-Upterm provider, provision two operator-supplied public key files inside Sitecard state (the pre-existing 0700 state directory: $SITECARD_STATE_DIR/sitecard when SITECARD_STATE_DIR is set, otherwise $XDG_STATE_HOME/sitecard, falling back to $HOME/.local/state/sitecard):

STATE="${SITECARD_STATE_DIR:-${XDG_STATE_HOME:-$HOME/.local/state}}/sitecard"
umask 077
mkdir -p "$STATE"
chmod 700 "$STATE"
printf '%s\n' 'ssh-ed25519 AAAA...primary-operator-key primary' > "$STATE/authorized_keys"
printf '%s\n' 'ssh-ed25519 AAAA...distinct-recovery-key recovery' > "$STATE/recovery_authorized_keys"
chmod 600 "$STATE/authorized_keys" "$STATE/recovery_authorized_keys"

Rules:

  • authorized_keys is the primary operator key file.
  • recovery_authorized_keys is the independent recovery key file.
  • Both files hold public keys only, mode 0600, one OpenSSH public key per line.
  • The recovery key must be a distinct operator-supplied public key. Never copy the primary key into the recovery file and never generate a private key the operator cannot access.
  • Recovery is optional; when the file is absent or empty only the primary file is used.
  • Recovery applies to authenticated non-Upterm transports only. It is not used with the upterm provider, which authenticates via relay-issued certificates.
  • Authenticated non-Upterm sessions launch the gateway with --authorized-keys <state>/authorized_keys and --recovery-authorized-keys <state>/recovery_authorized_keys.
  • Host SSH files such as ~/.ssh/authorized_keys or the root host SSH file are never read or written for authenticated Sitecard sessions.

Use

sitecard -h
sitecard serve --help
sitecard serve .

serve is a true alias of start with identical arguments.

Dev Tunnel hosting

Reverse WebSocket mode for outbound-only workspaces

When the remote workspace can reach a public HTTPS/WebSocket endpoint but cannot host a tunnel, expose the relay from the local machine. For Dev Tunnel, provision an HTTP port with anonymous connect access, then run locally:

sitecard relay-host --port 8080 --public-url https://PUBLIC-8080.REGION.devtunnels.ms --tunnel-id TUNNEL_ID

Omit --tunnel-id if devtunnel host TUNNEL_ID is already running locally. Use --devtunnel-token-file FILE with --tunnel-id if local login is absent; the host token is passed on stdin, never argv. The relay listens only on 127.0.0.1:8080 and prints a fresh unguessable wss://.../relay/TOKEN URL. Treat the URL as a secret. Keep the local command running.

Alternatively, expose the same local relay through srv.us. Start the relay without --tunnel-id and forward its port from the local machine:

ssh srv.us -R 1:localhost:8080
sitecard relay-host --port 8080 --public-url https://PUBLIC.srv.us

Run these in separate terminals, using the HTTPS hostname printed by srv.us as PUBLIC. Both commands must stay running. Verify the public endpoint supports WebSocket upgrades before using it.

On the remote workspace, install the matching Sitecard version and run the printed command. By default, add the local operator's SSH public key to Sitecard's state-owned authorized_keys and require key authentication:

sitecard serve . -t ws-relay -e 'wss://PUBLIC-8080.REGION.devtunnels.ms/relay/TOKEN'

Pass --accept instead of --no-public-access to allow SSH without credentials. Anyone with the relay URL can then open a shell. Keep the URL private and stop the relay when done. Password authentication remains disabled. The remote origin makes an outbound wss:// connection over port 443. The remote command stays in the foreground and needs no child-process tracking. Keep it running; Ctrl-C stops it. Locally, use sitecard proxy URL as the OpenSSH ProxyCommand, with a pinned SSH host key and the corresponding private key. The local broker accepts one origin and one client at a time; disconnecting either closes the pair. No Cloudflare Worker, remote Dev Tunnel CLI, or devtunnel connect is involved.

Remote-hosted mode

Install Microsoft's devtunnel CLI on the host before starting. Sitecard does not download tools, create tunnels, or change their access policies. Provision HTTP port 8081 with anonymous connect access on an authenticated machine. Transfer a fresh host-scoped token as an exact private file to the remote host if it cannot perform OAuth login. Keep mode 0600 and refresh before expiry.

Run on the remote workspace host:

sitecard serve . -t ms -i "$TUNNEL_ID" -k "$HOST_TOKEN_FILE" --accept

ms aliases devtunnel. The token goes through stdin, never argv. Sitecard starts a loopback SSH gateway plus a WebSocket bridge, then hosts the existing tunnel without creating ports again. --accept allows SSH without credentials. It prints the HTTPS SSH URL and a single OpenSSH command with sitecard tunnel-proxy as ProxyCommand. Install Sitecard on the SSH client; no client Microsoft CLI, devtunnel connect, or local forwarded port is needed.

The Dev Tunnel service stays in the foreground and uses retained child handles, not /proc, ps, PID files, or the detached supervisor. Ctrl-C stops its own children. Rerun the command to restart; the detached-mode stop/status/restart commands do not manage it. Other providers retain their existing lifecycle.

Public model API and optional config

Also provision HTTP port 8080 with anonymous connect access, then run:

sitecard serve . -m -p 8080 -t ms -i "$TUNNEL_ID" -k "$HOST_TOKEN_FILE" -a --accept

This prints a public /v1 base URL for the Responses API, forwarding through the host's HTTPS_PROXY and trusting its SSL_CERT_FILE or REQUESTS_CA_BUNDLE. Clients need no proxy configuration or private CA copying. -a allows model requests without credentials. Add --no-ssh for models only. The model can be selected in JSON, ?model=..., or /model/<model>/v1/responses. Chat Completions conversion is not supported. Pi should use openai-responses.

sitecard serve . -c sitecard.toml loads equivalent [relay], [tunnel], and [ssh] settings with explicit CLI overrides. TOML needs Python 3.11+; CLI flags work on Python 3.10. The checked-in RELAY_GUIDE.md, also included in the source distribution, covers provisioning, TOML contents, Pi config, SSH, and token renewal. Anonymous URLs expose workspace/model access to anyone who obtains them; the model relay does not forward arbitrary upstream URLs.

Remote model proxy access

When a model works only through the remote machine's managed HTTP proxy, copying a token does not reproduce that access. First test ordinary forwarding:

ssh -N -L 127.0.0.1:43706:127.0.0.1:43705 -p 4822 "$SSH_TARGET"

Replace the destination with the proxy address actually reachable from the gateway. --tcp-forwarding enables this route; it is enabled by default. Loopback refers to the gateway's network namespace, not another container's. If a remote SSH command can reach the proxy but direct-TCP/IP forwarding cannot, try the SSH exec fallback on the client:

sitecard forward "$SSH_TARGET" --ssh-port 4822 --listen-port 43706

This uses the remote SSH command's HTTPS_PROXY, connects there using existing python3, and streams binary traffic over SSH stdin/stdout. No remote package or CLI downloads are needed. Use --proxy-env http_proxy for a different environment variable. It supports an http:// proxy without URL credentials, including HTTPS destinations via CONNECT. It does not support TLS-to-proxy or SOCKS proxy URLs. SSH key authentication and a previously verified host key are required because each connection uses noninteractive SSH. The local listener is loopback-only; each connection opens one remote SSH command.

Point the model client at http://127.0.0.1:43706 as its HTTP proxy, preserving the original model endpoint URL and destination port. For clients honoring environment variables, set HTTPS_PROXY and HTTP_PROXY; ensure NO_PROXY does not bypass the intended destination. This forwards access, not credentials, and does not change the model protocol or automate model requests. If Python in the SSH exec context cannot reach the proxy either, this fallback cannot cross that namespace boundary; run the gateway there or expose a reachable proxy address. Do not publish the proxy as an anonymous public tunnel.

Metadata

Release files for sitecard 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sitecard 0.1.6
File Size Uploaded
sitecard-0.1.6.tar.gz 61.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sitecard 0.1.6
File Interpreter ABI Platform
sitecard-0.1.6-py3-none-any.whl Python 3 none any Details

Total release size: 125.9 kB

Release files / sitecard-0.1.6.tar.gz

Download URL sitecard-0.1.6.tar.gz
Size 61.5 kB
Tags Source
SHA-256 checksum
How to use checksums
982bc9a3fb87e25869f285839e0685a7584f3d610413d6a36646b7282af61b26
BLAKE2b-256 checksum
How to use checksums
d8c0be1a07c7bc53f14d66bd3e4df831233dd91d409951f493c9dc1cc598613a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / sitecard-0.1.6-py3-none-any.whl

Download URL sitecard-0.1.6-py3-none-any.whl
Size 64.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f4cd95992e7f350ec51841873f37d0127fe575134ad5aa0dfbb5e9522d41cbbc
BLAKE2b-256 checksum
How to use checksums
3a441e65904f643f29f1d36d84ae858263fc6c4e68e5809c0663e28c3c87f0e1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.23 {"installer":{"name":"uv","version":"0.12.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.6 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page