Update a server
A Tarsana server runs one image, built from one spec. To update it, you change the spec, let Tarsana build the new image, create a server from it, and then remove the old server. Your servers stay small, signed and identical to their spec.
Before you start, finish Run it on your provider. You need TENANT, ACCESS_TOKEN, spec.json and the ID of the server you created, in OLD_SERVER_ID.
1. Change the spec
Make your change in spec.json. For example, move to a newer package snapshot to pick up security updates:
"snapshot_id": "20260915T000000Z"
Check it with validate before you submit:
curl -X POST "https://api.tarsana.io/v1/tenants/$TENANT/specs/validate" \
-H "X-Tarsana-Access-Token: $ACCESS_TOKEN" \
-H "X-Tarsana-Tenant: $TENANT" \
-H "Content-Type: application/json" \
--data @spec.json
{
"valid": true,
"spec_hash": "sha256:cdff062988d4722b2ff052c97ebefb8b571858c493ce47b159df73b1c88809b1",
"problems": []
}
2. Submit it
A changed spec has a new hash, so submit returns a new submission ID and starts a new build:
curl -X POST "https://api.tarsana.io/v1/tenants/$TENANT/specs" \
-H "X-Tarsana-Access-Token: $ACCESS_TOKEN" \
-H "X-Tarsana-Tenant: $TENANT" \
-H "Content-Type: application/json" \
--data @spec.json
{
"submission": "sha256:cdff062988d4722b2ff052c97ebefb8b571858c493ce47b159df73b1c88809b1",
"created": true
}
export NEW_SUBMISSION=sha256:paste-the-rest-of-the-new-submission-value
3. Wait for the build
Ask for the status until pipeline.state is succeeded:
curl "https://api.tarsana.io/v1/tenants/$TENANT/submissions/$NEW_SUBMISSION" \
-H "X-Tarsana-Access-Token: $ACCESS_TOKEN" \
-H "X-Tarsana-Tenant: $TENANT"
{
"state": "accepted",
"pipeline": {
"job": "j-bbdde9adc372c296",
"state": "dispatched",
"created": true,
"what": "A sentence about the build's progress."
}
}
4. Create the new server
Create a server from the new submission with create-server. Use a new request_id: the same name returns the server you already created for that submission.
curl -X POST "https://api.tarsana.io/v1/tenants/$TENANT/submissions/$NEW_SUBMISSION/create-server" \
-H "X-Tarsana-Access-Token: $ACCESS_TOKEN" \
-H "X-Tarsana-Tenant: $TENANT" \
-H "Content-Type: application/json" \
--data '{"request_id": "web-2"}'
{
"created": {
"action_id": "ff97f81e3825703462ecab41c1c4ffa3",
"idempotent_replay": false,
"operation_id": "5000",
"state": "provisioning",
"target": {
"id": "1000",
"region": "fsn1"
}
}
}
Wait until the new server has finished its first boot and serves what it should, then move your traffic to it, for example by changing a DNS record or a load balancer target.
5. Remove the old server
Copy anything you still need off the old server first: this cannot be undone. Then decommission-server:
curl -X POST "https://api.tarsana.io/v1/tenants/$TENANT/providers/hetzner/servers/$OLD_SERVER_ID/decommission" \
-H "X-Tarsana-Access-Token: $ACCESS_TOKEN" \
-H "X-Tarsana-Tenant: $TENANT"
{
"decommissioned": {
"state": "destroyed",
"observed": "not-found",
"action_id": "ff97f81e3825703462ecab41c1c4ffa3",
"idempotent_replay": false,
"requested_at": "2026-10-05T02:15:41.166635+00:00",
"completed_at": "2026-10-05T02:15:41.169045+00:00",
"target": {
"id": "1000",
"region": "fsn1"
}
}
}
The old submission and its records stay in your tenant. You can still verify its signature or read its audit trail.
Servers you manage yourself
If you install Tarsana images on servers you created yourself, provision installs a newly built image on one of them. You name the provider, the server and its addresses in a provisioning request; the image always comes from the submission's finished build.
Next steps
- Verify a signature yourself for the new image.
- Errors: what each refusal means and what to do.