NEW Bare Metal Servers with 20G Dedicated Unmetered Bandwidth 20G Dedicated Unmetered Servers Read more STATUS

Reinstall a server from CI

Sep 22, 2026 5 min read

A reinstall is a single authenticated call, which makes it a natural fit for a pipeline: rebuild a server on a schedule, on a tag, or on a button in your CI. This walks through a GitHub Actions job that reinstalls one bare-metal server, applies a saved disk layout and post-install script, and waits for it to come up. Read Getting started with the Amóni API first if you have not made a key yet.

Before the pipeline: the allow-list

Every API key is locked to the source addresses you give it, and this is the one part of CI that needs thought. A GitHub-hosted runner has no fixed egress address, so it cannot sit on an allow-list. You have two honest options: run the job on a self-hosted runner whose egress IP you know, or send the calls through a proxy or bastion with a static address. Put that one address on the key. Then the key is both narrowly scoped and pinned to a machine you control.

The key itself needs read and servers.write, nothing more. Store it as a repository or environment secret named AMONI_API_KEY; never commit it.

Find the ids once

A reinstall is addressed by numbers: the server id, an OS profile id, and optionally a saved disk layout and post-install script. Look them up once and keep them in your workflow. The server id is in its portal URL and in GET /v1/servers. The rest come from the server's profiles:

curl -s https://api.amoni.app/v1/servers/955/profiles \
  -H "Authorization: Bearer $AMONI_API_KEY"
{
  "success": true,
  "data": {
    "profiles":      [ { "id": 12, "name": "Ubuntu 24.04", "os_slug": "ubuntu-24.04" } ],
    "disk_layouts":  [ { "id": 1, "name": "web-raid1-lvm", "scope": "client" } ],
    "scripts":       [ { "id": 1, "name": "harden-ssh", "scope": "client" } ]
  }
}

Saved disk layouts and scripts are your own, created once on the Install Profiles page. A custom layout or script has to be active before a reinstall can use it, so create and let it activate before you wire it into CI.

The workflow

This job reinstalls the server, then polls until the install reports complete. It runs on a self-hosted runner so its egress is on the key's allow-list.

name: Reinstall server
on:
  workflow_dispatch:        # a button in the Actions tab

env:
  AMONI: https://api.amoni.app/v1
  SERVER_ID: "955"

jobs:
  reinstall:
    runs-on: self-hosted    # fixed egress, on the key's allow-list
    steps:
      - name: Start the reinstall
        env:
          KEY: ${{ secrets.AMONI_API_KEY }}
        run: |
          curl -sf -X POST "$AMONI/servers/$SERVER_ID/reinstall" \
            -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
            -d '{
                  "profile_id": 12,
                  "hostname": "web1.example.com",
                  "disk_layout_id": 1,
                  "script_ids": [1]
                }' | tee reinstall.json
          jq -e '.success' reinstall.json

      - name: Wait for it to come up
        env:
          KEY: ${{ secrets.AMONI_API_KEY }}
        run: |
          for i in $(seq 1 60); do
            sleep 30
            body=$(curl -sf "$AMONI/servers/$SERVER_ID/provision-status" \
              -H "Authorization: Bearer $KEY")
            echo "$body" | jq -r '.data | "\(.status) \(.step // "")"'
            if [ "$(echo "$body" | jq -r '.data.complete')" = "true" ]; then
              echo "Install complete."; exit 0
            fi
          done
          echo "Timed out waiting for the install."; exit 1

The reinstall call answers at once:

{ "success": true, "data": {
    "message": "Reinstall started. This can take several minutes.",
    "notice": null,
    "applied": { "os": "Ubuntu 24.04" }
} }

It is not finished when this returns; it has started. Progress is on GET /v1/servers/{id}/provision-status, which reports complete, a status and a step. There is no percentage while it runs, so poll on complete, not on a number.

Getting the root password

If you did not send a password, the installer sets an auto-generated one. Read it once the install is done with GET /v1/servers/{id}/root-password. It answers 404 with code root_password_unavailable when there is nothing to hand back, so treat that as “use your SSH key” rather than an error. Better still, pass ssh_key_ids in the reinstall so the machine comes up with your key already on it and no password to fetch. Manage those keys with the API or in the portal.

Let a webhook tell you instead

Polling is fine for one server in one job. Across a fleet, subscribe a webhook and let the operation.succeeded event for server.reinstall tell you when each one lands, rather than every job holding a runner open on a sleep loop.

Questions we get

  • Why will my GitHub-hosted runner not work? Its egress address is not fixed, so it cannot be on the key's allow-list. Use a self-hosted runner or a static-IP proxy.
  • Do I have to give a disk layout and script? No. With only profile_id the reinstall uses the image's default partitioning and no post-install step.
  • How many scripts can I run? Up to five per reinstall, in the order you list them. Each runs once, as root, after the OS is installed.
  • Can I reinstall a cloud instance this way? That is a rebuild, not a reinstall. Cloud instances use POST /v1/vms/{account}/{id}/rebuild and cloud-init.
  • Something was refused mid-install. The response notice says so in plain terms, for example that your key could not be applied. Read it, do not assume the request went on exactly as sent.

Still stuck?

Open a support ticket with the server id and the reinstall.json your job saved. We can see the operation and what the installer did with it.

Built for production

Why teams stay with Netrouting

We connect you to the Internet using network engineers (and not order takers) and hardware and infrastructure that is built to last, so we can pick up where you left off when you need us.

  • Expert-Level Support Our staff is available 24 hours a day, 7 days a week to handle network administration and systems management issues as they occur.
  • Scalable Solutions Build whatever depth or breadth your infrastructure needs and then scale as required.
  • Enhanced Security Enable 2-factor authentication and also limit by IP address from the control panel to secure your account.
  • Cost-Efficient Infrastructure You will always receive the best value from your investment as you will be optimized for budget without any compromise on Quality.