Run a Worker on a remote VM

August 11, 2026 ยท View on GitHub

Factory keeps its browser and operator API on loopback. Remote VMs connect to a separate HTTPS listener that exposes only enrollment and the Worker lifecycle. The server does not make inbound connections to the VM.

Configure the server

Install a TLS certificate whose names include the address used by the VM. Add the remote listener to ~/.factory/config.toml:

listen = "127.0.0.1:7337"
database = "server/factory.sqlite3"

worker_listen = "0.0.0.0:7443"
worker_tls_cert = "/etc/factory/tls/server.crt"
worker_tls_key = "/etc/factory/tls/server.key"

All three worker_* settings are required together. The local browser API remains available only at 127.0.0.1:7337. Permit inbound TCP traffic to the Worker port only from trusted Worker networks.

Create a one-time enrollment

First print the stable identity on the VM without starting the Worker:

factory-worker identity --config /etc/factory/worker.toml

Then create an enrollment bound to that identity through the local operator API on the server host:

curl --fail-with-body \
  -H 'Content-Type: application/json' \
  -d '{"worker_id":"PASTE_WORKER_ID"}' \
  http://127.0.0.1:7337/api/v1/worker-enrollments

The response contains the bound worker_id, an enrollment_token, and its expiry. It is valid for ten minutes and can be exchanged once by that identity. Transfer that short-lived value to the VM through your normal secret channel.

Configure the VM

server = "https://factory.example.com:7443"
name = "build-vm-01"
runtimes = ["codex", "claude-code"]
max_concurrent = 10
enrollment_token = "factory_enroll_REDACTED"

# Set this for a private certificate authority. Public certificates use the
# operating system trust store and do not need it.
ca_certificate = "/etc/factory/tls/ca.crt"

[labels]
region = "eu-west"
host = "build-vm-01"

Start factory-worker normally. It exchanges the one-time token over TLS and saves the returned Worker credential as worker-credential inside its owner-only data directory. The credential is never printed or placed in the enrollment command. Remove enrollment_token from the TOML after the first successful start.

The VM reuses its protected worker-id and credential after restarts. Deleting the data directory creates a new identity. To rotate a credential, stop the Worker, remove worker-credential and worker-credential.pending, create a new enrollment, update the short-lived token, and restart it.

The saved credential is bound to the exact Factory server origin. Changing the server setting while reusing the data directory fails before making a request, so a credential cannot be disclosed to a different endpoint. Explicitly rotate the credential when intentionally moving a Worker identity between servers.

Connection behavior

Remote and local Workers use the same Jobs, claims, leases, cancellation, event, and completion contract. Labels, capacity, and coding-agent capabilities appear on the Worker profile. A disconnected VM becomes offline after its registration heartbeat expires. An active attempt becomes lost after its lease expires. When the VM reconnects with the same data directory it returns under the same stable Worker identity.

The remote endpoint rejects operator APIs and checks every attempt against the authenticated Worker identity. Factory does not provision VMs, distribute agent or GitHub credentials, or manage Kubernetes pods.