# Change an external server address

Source: https://docs.imprezahost.com/external-agent-address.html

When an **external server** you connected yourself moves to a new public IP
address, you can replace the address Impreza has registered for it. The
managed DNS records of that server's apps follow the new address.

## Which servers this is for

Only **external servers**: machines outside Impreza that you connected with
the external install command. Their agent has no Impreza service behind it.

The agent on an **Impreza VPS** belongs to that VPS service and follows the
VPS's own address. You cannot change its address with this action; the
request is refused with `EXTERNAL_AGENT_REQUIRED`. This includes an agent
you installed with the external command on an Impreza VPS: it is attached to
that VPS service.

## Who can change it

- In the portal, the **account owner**, signed in, in the **External server
  address** card of the apps page. A team member, or staff viewing the
  account, cannot.
- On the API, an **API key** of the account with the `manage` scope; reading
  the latest change needs `read`. An agent credential or an MCP connection
  is refused with `SCOPE_INSUFFICIENT`.

## Change the address

`POST /v1/platform/agents/{agent_id}/address-changes` with exactly three
fields:

```json
{
  "request_id": "<32 lowercase hex characters you generate>",
  "expected_address": "<the address registered now>",
  "new_address": "<the new public address>"
}
```

- A missing field, or any other field, is refused with `ADDRESS_INPUT`.
- `expected_address` must be the address that is registered **now**. If it
  is not, the change is refused with `ADDRESS_STALE`. Read the current state
  first and send the address it shows.
- `new_address` must be a **canonical public** address. Private, loopback,
  link-local, documentation and other reserved addresses are refused with
  `ADDRESS_INVALID`.
- The same address on both sides is refused with `ADDRESS_UNCHANGED`.
- An address already used by another customer, or reserved by another
  unfinished change, is refused with `ADDRESS_UNAVAILABLE`.
- If a managed DNS record no longer points at the registered address, or the
  ownership of one of the server's managed names cannot be verified, the
  change is refused with `DNS_DIVERGED` or `DNS_LEASE_UNVERIFIED`.
- Only one address change runs at a time. While another one is in progress,
  the request is refused with `ADDRESS_BUSY`; read the latest change before
  retrying.
- **Sending the same `request_id` again returns the saved receipt** and does
  not start a second change. A `request_id` already used for a different
  change is refused with `REQUEST_REUSED`.

These refusals happen before anything changes.

A successful answer is the saved receipt of the operation: its `change_id`,
its `state` (`applied` when it finished), the number of managed DNS records
it moved, and the actions still available for it. It is a record of the
operation, **not a check that the new address answers**.

`GET /v1/platform/agents/{agent_id}/address-changes` reads the latest
operation for that server.

## What follows the new address

- The registered address of the external server.
- The **managed A records** of that server's apps, through the platform's
  address routine.
- The server's WAF allowlist entry moves to the new address. The old entry is
  removed unless something else still needs it.

Not included: the server's own network, its certificates, whether an app
answers on the new address, and DNS names the platform does not manage.

**IPv6:** a new address can be IPv6 only when the server has no managed A
records. Moving a server with managed A records from IPv4 to IPv6, or back,
is refused with `ADDRESS_FAMILY_UNSUPPORTED` before anything changes.

DNS caches can keep answering with the old address for a while after the
change. That is normal and does not mean the change failed.

## If a change stops halfway

DNS and the WAF are not one database transaction. When a record or the WAF
does not confirm, the operation stays **open** and the answer is
`503 RECOVERY_REQUIRED`. Nothing retries in the background, and a
half-finished change is never reported as complete.

1. Read the operation with the `GET` above.
2. Then either **resume** it,
   `POST /v1/platform/agents/{agent_id}/address-changes/{change_id}/resume`,
   or **reverse** it,
   `POST /v1/platform/agents/{agent_id}/address-changes/{change_id}/rollback`.
   Both take exactly the body `{"confirm": true}`; without it they are refused
   with `CONFIRM_REQUIRED`.

If the resume or the reversal cannot finish either, the answer is again
`503 RECOVERY_REQUIRED` and the operation stays open; read it before trying
again.

While an operation is open, a new change for the same server is refused with
`409 RECOVERY_REQUIRED` until you finish or reverse it. Only the latest
operation of a server can be resumed or reversed; an older one is refused
with `ADDRESS_GENERATION_STALE`. Once you start reversing an operation, it
cannot be resumed forward: continue the reversal.

## Reverse a finished change

A change that finished (`applied`) can still be reversed with the same
`rollback` call while it is the latest change of that server: the registered
address and the managed A records go back to the old address. The old
address must still be available; if it is not, the reversal stays open as
described above. You can also make a new change back to the old address.

## Privacy

The request body is not written to the request log, and the activity record
of the change does not store the addresses.

## Limits

- It does not move a server that belongs to an Impreza service.
- It does not adopt a DNS name the platform does not already manage.
- It does not prove that the new address is reachable.
