Run sessions on your own workers
Your organization can run its dev sessions on Linux hosts in your own network instead of on hosts Ciresk runs. You enrol each host with a secret, the host dials out to Ciresk's control plane in eu1, and from then on your sessions, their workspaces and their checkpoints live on your hardware. This page covers what such a worker is, what it needs, how to enrol, drain and revoke one, and what still passes through Ciresk.
What a customer-run worker is
A worker is the machine a session runs on. Every worker serves exactly one organization: it is enrolled into it, and it can only ever be given that organization's sessions.
With your own workers:
- your host runs the sessions, their containers, the workspace files, the session's egress proxy and its read-only package registry cache;
- checkpoints go to your own S3-compatible bucket, or stay on the host's disk;
- the host only makes outbound connections. Ciresk never connects to it: its health endpoint (
127.0.0.1:9471) and its registry cache (127.0.0.1:9473) listen on loopback only.
Ciresk's control plane in eu1 still decides: sign-in, policy, the session queue, placement, leases, tunnel tickets, the session journal and the audit log.
What leaves your network and what Ciresk sees
| Part | Where it is |
|---|---|
| Sessions, containers, workspace files, the session egress proxy, the registry cache | Your host |
| Checkpoints | Your bucket, or the host's disk |
| The worker's credentials | Your host, readable by root only |
| Identity, policy, the queue, leases, tickets, the audit log | Ciresk, eu1 |
| The session journal | Ciresk, eu1: the commands run (secret-looking arguments redacted), paths and exit codes, never their output or file contents |
| Session secrets | Stored by Ciresk, handed to your worker for the session it holds; the session sees placeholders (see secrets.md) |
| The tunnel relay and the browser gateway | Ciresk, eu1 |
The relay and the browser gateway are Ciresk's today. The bytes your developers' tunnels and previews carry (sync, logs, exec, the browser view, VS Code in the browser) pass through them, readable by the relay except
ciresk dev sshandciresk dev codestreams, which are SSH end to end; the browser gateway shows the diff and the terminal, so it sees them in clear. So the workspace and its checkpoints stay in your network; the traffic between a developer and the session does not yet.
Models are not available on your own workers: a session there gets no model access, whatever models.allow says.
Requirements
The host:
- Linux, arm64 or x86_64, with systemd. Ciresk prepares its own hosts on Ubuntu 24.04.
- The worker runs as root.
podman, with the systemd cgroup manager (podman info --format '{{.Host.CgroupManager}}'printssystemd), so session containers survive a worker restart.- Overlay filesystems and network namespaces.
- The data directory,
/var/lib/ciresk-ciby default, on XFS mounted withprjquota. - Two rows in both
/etc/subuidand/etc/subgid:containers:2147483647:2147483648for podman, andciresk-sessions:1342177280:131072, the range the worker gives each session its own host user from. The worker refuses to start sessions when another row or account overlaps that range. keyutils, andfs.inotify.max_user_watchesof at least 524288 so each session can run a dev server.
A host that lacks one of root, podman with the systemd cgroup manager, network namespaces, overlay or XFS project quotas registers but takes no sessions, and its log says so.
Network:
- Outbound HTTPS (443) to
api.eu.ciresk.comandget.ciresk.com, directly or through your proxy. Nothing inbound. - Your image registry, to pull the session image by digest.
- Your checkpoint bucket's endpoint, when you set one.
Enrol a worker
Enrolling, listing, draining and revoking workers needs the dev:workers.admin scope, which owners and admins hold. A person or an API key carrying the scope may do it; an agent never can.
1. Keep your sessions on your own workers
Set workers to customer in the dev policy before your first session:
ciresk dev policy show --json # copy the "policy" object to policy.json, raise "version" by one
ciresk dev policy set policy.json{
"version": 2,
"workers": "customer"
}| Value | Where your sessions run |
|---|---|
cell (default) | hosts Ciresk starts for your organization, and any host you enrolled |
customer | only hosts you enrolled; Ciresk never starts a host for your organization |
Changing the policy needs dev:policy.write (see admin.md). Switching to customer revokes nothing: a Ciresk host already enrolled for your organization keeps its sessions until it idles out or you revoke it (Revoke a worker).
2. Install the worker
On the host, install the worker binary and its session guest from the signed release. The installer verifies the release's signature and writes the systemd unit ciresk-ci-worker:
curl -fsSL https://get.ciresk.com/install/worker.sh | sudo shLeave out --enrol: that flag joins Ciresk CI, which this host does not use. The installer writes an empty /etc/ciresk-ci/egress.yaml, so nothing leaves the host until you add the rows in step 5.
3. Issue the enrolment secret
From any machine signed in as an admin, issue the host's enrolment secret. The name is lowercase letters, digits and hyphens, at most 63 characters, and must be the name in the host's worker.toml:
ciresk dev admin enrol-worker acme-dc1-01It prints the dve_ secret once, and as its next line the command that stores it on the host. The console's Workers page does the same. Run that line on the worker's host and paste the secret at its silent prompt, so the secret reaches neither a shell history nor a command line:
sudo install -m 0600 /dev/null /etc/ciresk-ci/dev-enrolment && read -rs DVE && printf %s "$DVE" | sudo tee /etc/ciresk-ci/dev-enrolment >/dev/null && unset DVEWith --json, data.file names that file and data.store holds the same line.
| Credential | What it is | Lifetime |
|---|---|---|
dve_ enrolment secret | Lets the worker of that name register. Reusable by that worker, so a host that was off longer than its token registers again by itself | No expiry: until a new enrol-worker of the same name rotates it, or you revoke the worker |
dvw_ worker token | Issued at each registration in exchange for the dve_; every earlier token of the worker stops working | 24 hours, renewed by the worker |
Both reach only your organization's sessions. Enrolling a name again rotates its secret and keeps the same worker; a registration under a different name than the secret was issued for is refused.
4. Write worker.toml
name = "acme-dc1-01"
ci_enabled = false
release_url = "https://get.ciresk.com/worker"
[dev]
sessions = true
api_url = "https://api.eu.ciresk.com"
control_plane = "remote"
enrolment_secret = "file:/etc/ciresk-ci/dev-enrolment"
base_image = "registry.acme.internal/ciresk/dev-base@sha256:<digest>"
memory_bytes = 60129542144
cpus_milli = 14000
sessions_max = 4| Field | Default | What it does |
|---|---|---|
name | the name you enrolled | |
ci_enabled | true | false: the host takes no Ciresk CI tasks and needs no CI enrolment |
release_url | none | where the worker verifies its session guest against the signed release; required on a host with ci_enabled = false |
public_cache_bytes | 50 GiB | the size of the read-only package registry cache; 0 turns it off |
[dev] sessions | false | true runs sessions |
[dev] api_url | https://api.eu.ciresk.com | the dev control plane |
[dev] control_plane | cell | remote on your host: the control plane and the relay are rows of the host's egress.yaml and honour its proxy |
[dev] enrolment_secret | none | where the dve_ is read: file:<path> or aws-sm:<name> |
[dev] base_image | none, required | the session image, ciresk/dev-base@sha256:..., from a registry the host can pull |
[dev] ide_image | none | the VS Code in the browser image, ciresk/dev-ide@sha256:...; without it that view is refused |
[dev] memory_bytes, [dev] cpus_milli | none, required | the share of the host sessions get: its memory and CPUs less a reserve for the host itself |
[dev] cpu_overcommit_milli | 2000 | how far sessions' CPU reservations may exceed cpus_milli (2000 is twice) |
[dev] sessions_max | 4 | sessions the host holds at once |
The images are not public. Mirror ciresk/dev-base (and ciresk/dev-ide) into your own registry, or ask Ciresk to admit your AWS account to pull from its registry.
Checkpoints (optional) go to your bucket when the unit's environment names it, with the host's own credentials (an instance profile, or the AWS SDK's usual chain):
[Service]
Environment=CIRESK_CI_STORE_BACKEND=s3
Environment=CIRESK_CI_STORE_BUCKET=acme-dev-checkpoints
Environment=CIRESK_CI_STORE_REGION=eu-central-1CIRESK_CI_STORE_ENDPOINT points at an S3-compatible store other than AWS. Without a bucket, checkpoints stay on the host, and a session moved to another host cannot resume from its checkpoint (checkpoint_unavailable). A bucket that is set but does not open stops the worker; it never falls back to the disk silently.
5. Allow what the host must reach
Add these rows to /etc/ciresk-ci/egress.yaml, and allow the same destinations on outbound 443 in your firewall:
- host: api.eu.ciresk.com
purpose: the dev control plane (registration, lease, heartbeat, reports, session secrets) and the relay
products: [ci]
- host: get.ciresk.com
purpose: the signed release the session guest is verified against
products: [ci-worker]Behind a mandatory proxy, add one proxy row; the worker's HTTPS calls and the relay connection go through it, and a TLS-inspecting proxy needs its CA in the host's trust store:
- proxy: proxy.acme.internal
ports: [3128]
purpose: the only way out of acme's networkWhat a session itself may reach is your rows for product dev-session, narrowed by the template's egress rows and your organization's ceilings (see egress.md). With no dev-session rows, sessions reach nothing outside. No session reaches api.eu.ciresk.com: that row names ci, never dev-session. With the registry cache on, it reads through the public registries (index.crates.io, static.crates.io, registry.npmjs.org, proxy.golang.org, sum.golang.org, pypi.org, files.pythonhosted.org, repo1.maven.org), so allow them in your firewall where you need them.
The worker reads /etc/ciresk-ci/egress.yaml unless CIRESK_EGRESS_FILE in the unit's environment names another file.
6. Start it and check
sudo systemctl enable --now ciresk-ci-worker
journalctl -u ciresk-ci-worker -fThe log says dev-only host: no ci registration, then registered with the dev control plane. A refused egress row names the destination and the product. A host that cannot run sessions says why, and the unit fails, so systemd restarts it.
Then, from a developer's machine in your organization, run ciresk dev up in a repository with a template; ciresk dev status names the worker and its release.
How sessions are placed
A pending session goes to one of your organization's workers that is online, takes sessions, is not drained and has room for the session's size: memory within memory_bytes, CPUs within cpus_milli times the overcommit, disk above the free-space floor (workspace_min_free_bytes, 20 GiB by default), and fewer sessions than sessions_max. Among those, the worker that held the session before comes first, then one that already has the repository warm, then the one with the most free memory.
When none can take it, ciresk dev up says why:
| Reason | Meaning |
|---|---|
no_capacity | your workers are online but every one is full or drained |
no_worker | none of your workers is online; with workers: customer, Ciresk starts none for you, and next tells you to start an enrolled worker (sudo systemctl start ciresk-ci-worker on its host), then run ciresk dev up again |
Operate a worker
| Task | Command |
|---|---|
| Enrol, or rotate a worker's secret | ciresk dev admin enrol-worker <name> |
| Drain before a restart or upgrade: no new sessions, the running ones go on | ciresk dev admin drain-worker <name> |
| Take sessions again | ciresk dev admin drain-worker <name> --undrain |
| Revoke | ciresk dev admin enrol-worker <name> --revoke |
A drained worker stays drained across its own restarts until you undrain it. The console's Workers page lists every enrolled name with its state (online, offline, drained, revoked), last heartbeat and release, and enrols and revokes too.
Upgrades: nothing updates your host by itself. Run the installer again for the new release and restart the unit. Sessions survive a worker restart: their containers outlive it and the worker takes them back.
If the host loses contact with Ciresk, each session's egress stops 30 seconds after its last renewed heartbeat, and the session waits; its content stays on your host.
Revoke a worker
ciresk dev admin enrol-worker acme-dc1-01 --revokeIn one step:
- the worker's
dve_anddvw_stop working, and it is marked offline; - every live session it held moves to a new epoch, so the relay refuses every ticket, stream and worker connection of the old one at once;
- a session started from the repository (
ciresk dev up --remote) with a checkpoint goes back to the queue and resumes from that checkpoint on another of your workers; - any other session is marked lost (reason
worker_revoked); its owner's nextciresk dev upstarts it again on another worker and syncs the worktree again; - a session that was already stopping ends;
- the audit log records
dev.worker.revokewith the sessions it moved.
People's device grants stay, and their next tickets carry the new epoch. The worker shows as revoked until you enrol its name again, which lets it back in under the same worker.
Ciresk can also cut off every worker of your organization at once, for an emergency rotation of credentials; you then enrol each host again.
Not available yet
- The relay and the browser gateway in your network: today developer traffic to your sessions passes through Ciresk's in
eu1. - Models in sessions on your own workers.
- Ciresk CI tasks on the same host, worker pools with settings of their own, single-use enrolment secrets and tokens bound to the host's key.
- Automatic updates of your workers, and a factory that starts your hosts on demand.
- Listing workers from the CLI: use the console's Workers page or the API (
GET /v1/dev/workers/enrolments, see /api/dev). - A self-hosted control plane and air-gapped installs.