Your machines
A runner is a machine you already have. Surfra does not rent it. The surfra command on that machine heartbeats, pulls the image, and runs one app at a time.
Local runners are free. If a runner serves an app, a later plan charges a flat $5 for that account when the runner was used in the last 30 days. That fee is not charged now.
Log in
Section titled “Log in”surfra loginThis opens the dashboard. Approve the code while you are signed in. The session is stored in ~/.surfra/config.json on that machine.
Register
Section titled “Register”surfra runner registerThe CLI guesses vCPU, RAM, and GPU, then opens a page where you can change those values and name the device. The name is the id you put in an app, for example desk-4090.
Registration binds the runner to the account that approved it. A runner runs apps for that account only. Register again while logged into a different account to move it. surfra runner whoami prints the id, the account, the hardware, and whether an app is using it.
Install Docker
Section titled “Install Docker”surfra runner start does not install system packages. If Docker is missing, it prints the script to run:
surfra runner install cpusurfra runner install gpuThe CPU script installs Docker. The GPU script installs Docker and the NVIDIA container toolkit, so the GPU is visible inside the container. Both scripts need sudo.
surfra runner startWhile this is running, the machine heartbeats and accepts work. It pulls the image and starts it with surfra worker. Registry passwords are sealed to a key that stays in ~/.surfra/runner.json. The image is not encrypted. The parent process inside the container holds the replica token.
One app at a time
Section titled “One app at a time”A runner can be listed on several apps. The first app to get a free runner keeps it until the container exits. Other apps that list it stay queued and try their next provider. That is app-to-app contention: the runner is still a backend, and it does not schedule a second app on top of the first.
autoscale={ "min_replicas": 0, "max_replicas": 1, "providers": [ {"provider": "runner", "runner": "desk-4090", "priority": 1}, {"provider": "runpod", "gpu": "rtx4090", "priority": 2}, ],}Use the runner id from surfra runner whoami if you prefer the id over the name.
