1 CLI op
Kyle Mendell edited this page 2026-10-27 15:06:39 -05:00

op is the client. It logs in to obtain a short-lived certificate and connects to nodes through the proxy — analogous to tsh.

A global --insecure flag skips TLS verification of the proxy (for a self-signed development control plane). A global --debug flag logs the routed TLS connection — address, TLS version, negotiated ALPN and certificate fingerprint — to stderr. See Troubleshooting.

op login [proxy-host:port]

Authenticate and store a profile + certificate. Reuses your saved profile when flags are omitted.

Flag Default Purpose
--proxy — proxy address host:port (or pass positionally)
--user $USER username
--oidc — log in via an OIDC connector instead of a password
--grpc auto gRPC address for login: the proxy address itself when the server supports TLS routing, else proxy host :3025
--ttl 8h requested certificate lifetime
op login gate.acme.com:8443 --user alice
op login gate.acme.com:8443 --oidc okta      # browser-based OIDC

op ls

List the nodes you can reach with your current certificate.

op ssh [login@]node [command...]

Open an SSH session to a node through the proxy, or run a single command. When op ssh is run without a target in an interactive terminal, it opens a picker for a reachable node and then a permitted login.

op ssh deploy@web-1
op ssh deploy@web-1 -- systemctl status nginx
op ssh                         # pick a node, then a login

op cp [-r] <src> <dst>

Copy files to or from a node. Exactly one side is remote, written [login@]node:path; a relative remote path resolves against the login's home directory.

Flag Default Purpose
-r, --recursive false copy directories recursively
op cp ./app.tar deploy@web-1:/opt/app/app.tar
op cp deploy@db-1:/var/log/db.log ./db.log
op cp -r ./build deploy@web-1:/opt/app

Transfers use the node's SFTP subsystem, so the node agent must be recent enough to serve it. For anything beyond a straight copy — resumption, deltas, excludes — set up op ssh-config and use rsync or scp directly.

op forward [login@]node [bind:]localport:host:remoteport ...

Forward local TCP ports to addresses reachable from a node, the equivalent of ssh -N -L. Listens on 127.0.0.1 unless a bind address is given, and runs until interrupted. Several forwards can share one connection.

op forward web-1 8080:localhost:80
op forward db-1 5432:localhost:5432 6379:cache.internal:6379

Local forwarding only — the node never listens on your behalf, so there is no remote (-R) or SOCKS (-D) equivalent. Forwarding requires a certificate carrying the port-forwarding permission; if yours predates it, run op login again.

op ssh-config [host-pattern...]

Generate an OpenSSH client configuration so ordinary tools connect through overpass: ssh, scp, rsync, Ansible, and editors that speak SSH such as VS Code Remote.

Flag Default Purpose
--write false write ~/.overpass/ssh_config and include it from ~/.ssh/config
op ssh-config                 # print the block for the nodes you can see
op ssh-config --write         # install it
op ssh-config 'web-*' db-1    # explicit patterns instead of querying the proxy
ssh web-1                     # then just use ssh
rsync -a ./build/ web-1:/opt/app/

The generated block points ProxyCommand at op proxy and reuses the certificate op login already stored, so nothing is duplicated. It also writes a known_hosts file trusting the cluster Host CA, which is how ssh verifies node identity without prompting.

The configuration keeps working across logins, but the certificate inside it expires: when ssh starts refusing to authenticate, run op login again. Re-run op ssh-config --write after enrolling nodes so the new names are covered (or install a wildcard pattern once).

op proxy [login@]node

Bridge stdin/stdout to a node's SSH server. This exists to be used as a ProxyCommand — see op ssh-config, which writes it for you — and is rarely run by hand. stdout carries the SSH byte stream, so all diagnostics go to stderr.

op status

Show the current login: proxy, user, roles, logins and certificate expiry.

op update

Replace this binary with the latest published release. The download is verified against the release checksums before anything is installed, so a failed or tampered download leaves the existing binary untouched.

Flag Default Purpose
--check false report whether a newer release exists, install nothing
--to latest install an exact version instead of the latest
--force false reinstall even when already up to date
--base-url built-in override the release download URL
op update --check
op update
op update --to 0.1.9      # pin, or roll back

opctl update works identically.

Binaries are fetched from the release they were published to. The repository URL is baked into each release build; --base-url or OVERPASS_UPDATE_BASE_URL override it for a private mirror. Only https is accepted (loopback aside), because the checksum that guards the download travels the same channel.

If the binary lives somewhere you cannot write — /usr/bin from a package, for example — the update fails with that explanation rather than a bare permission error. Use your package manager, or re-run with sudo.

Once a day, an interactive op or opctl also notes on stderr when a newer release exists. Set OVERPASS_NO_UPDATE_NOTIFIER=1 to turn that off; it is already skipped for development builds and when output is not a terminal.

op logout

Remove the local certificate and profile.