Pairing a server
Pairing swaps the usual routine of finding an IP address, opening a port, and pasting a key on a phone keyboard for a single command and a QR code.
The basic flow
On the host, as the user you want to connect as:
onepilot pairIt prints a QR code and a onepilot:// URL below it. Open the Onepilot app, scan the code, and the server appears. If the camera is awkward, the URL on the url: line is the same payload and the app has a field to paste it into.
What the command installs
It generates a fresh key pair and appends a single use entry to the authorized_keys of the user you ran it as. That key is a bootstrap credential and nothing more: the first time the app connects, it replaces the bootstrap key with its own device key.
Common options
| Flag | What it does |
|---|---|
--user U | Connect as a different user than the one running the command. |
--port N | Advertise a non standard SSH port. Defaults to 22. |
--label L | Name the server as it appears in the app. Defaults to the hostname. |
--host H | Override the advertised address when autodetection picks the wrong one. Accepts a comma separated list. |
--multi | Print a reusable code so several devices or accounts can pair from it. Stays valid until you clean it. |
--no-qr | Print the URL only. Useful over a connection that mangles block characters. |
onepilot pair --user deploy --port 2222 --label "Build box"Direct or tunneled
Pairing decides how your phone will reach the machine, and tells you which it chose.
- Answers from the internet already. A server with a public address that accepts SSH is registered as is, with no tunnel. It says so, and mentions that you can add a tunnel later if the machine ever moves behind a router.
- Behind a router or on a LAN. The common case for a home machine or an office box. The host takes a relay port and dials out to hold a tunnel open, then prints the address it is reachable at. Nothing is forwarded on your router and no inbound port is opened.
The relay carries encrypted SSH traffic and cannot read the session. It is a path, not a participant.
Messages about the tunnel
Pairing waits for the tunnel to actually come up before it claims the server is reachable, and it reports what it found:
- Tunnel attached. Everything is up and the code carries the remote address.
- Still connecting. The code includes the tunnel and the app waits for it. Normal on a slow or busy host.
- Local network only. The tunnel could not start, so the code pairs over the LAN. The server stays registered and keeps trying, so this often resolves itself. See debugging if it does not.
Surviving a reboot
For the tunnel to come back after a restart, it needs to run as a service. On macOS, pairing may ask whether to install it for all boots, which needs an administrator. Say no and the tunnel still works, it just will not return on its own until you log in.
Pairing a Docker container
Run this on the container's host, not inside the container:
onepilot pair --container my-containerThe container needs no SSH server, no published port, and no changes of its own. Access rides the host, and the container shows up in the app as its own entry that you can open in one tap.
Removing access
| Command | Effect |
|---|---|
onepilot pair --clean | Removes pairing codes that have not been used yet. Paired devices keep working. |
onepilot pair --clean-devices | Removes the device keys too. Every paired phone must pair again. |
onepilot pair --container NAME --clean-container | Removes the keys installed for that container. |
Reach for --clean when you printed a code and did not use it, and --clean-devices when a phone is lost or someone leaves. Neither touches the CLI itself; see cleanup and uninstall to remove everything.
When pairing does not work
| What you see | What to do |
|---|---|
| No reachable address found | Autodetection found nothing usable. Pass the address yourself with --host. |
| Pairs over the local network only | The tunnel could not start. Your phone can still pair on the same network, and the host keeps retrying. Check debugging. |
| This binary will be deleted | The CLI is running from a temporary directory, which will not survive. Install it properly with npm install -g onepilot and pair again. |
| Running inside a container | Use onepilot pair --container NAME from the host. |