Core concepts
Resilient deployments
Keep a stopped cloud standby machine ready to take over when your on-prem deployment goes down, and pay only for storage while it's idle.
This guide configures a stopped cloud standby machine that starts automatically if your primary deployment becomes unreachable, using AWS, Azure, or Google Cloud. See /docs if you're new to Nethera.
Note
Pro required. Cold cloud failover uses multi-machine endpoints and service-failure actions, which are available on the Pro plan.
Important
This covers compute only. Nethera fails over the service, not its data - it does not replicate Docker volumes, local databases, or other on-disk state between machines. If your app writes data locally (SQLite, uploaded files, and similar), that data does not exist on the standby machine when it starts. See Failing over stateful services below before using this with anything that isn't stateless or backed by shared external storage.
Why cold cloud failover
Self-hosting normally leaves you with two unappealing options when your primary machine goes down: accept the downtime, or run a second machine at full price around the clock just in case. Neither is great - on-prem hardware doesn't come with a cloud provider's uptime guarantees, but paying for standby compute you almost never use eats into the whole reason you're self-hosting.
A cold standby splits the difference. It sits stopped, so you pay for storage rather than compute, and only starts when your primary is actually unreachable. Because it's paired with the same Nethera workspace as your primary, there's no separate deploy pipeline to maintain for the failover path - it just reconciles to your latest revision when it wakes up.
How it works
- Nethera attempts to route a request to a healthy backend.
- If at least one backend is reachable, traffic is served normally.
- If no backend is reachable, Nethera invokes your service failure webhook.
- Your cloud provider starts the standby machine.
- The Nethera agent on the standby reconnects and reconciles to the latest deployment revision.
- Nethera begins routing traffic as soon as the service port responds.
The request that triggered failover receives:
503 Service Unavailable
Retry-After: 30Clients should retry until the standby is ready. Startup time depends on your cloud provider, machine size, and how long your container takes to become healthy.
Before you start
You'll need:
- A Nethera app already deploying to your primary machine.
- A standby machine paired with Nethera and added to
targets. - A service failure webhook configured on the service.
appName: inference-apiappId: <generated by neth init> targets: - office-gpu - cloud-gpu services: api: image: ghcr.io/acme/inference-api:latest nethera: public: 8000 auth: token onServiceFailure: after: 60s emails: - owners webhookSecrets: - FAILOVER_WEBHOOKSet the webhook secret before your first deploy:
$neth secrets set FAILOVER_WEBHOOKDeploy once while the cloud machine is running, to confirm it works, then stop or scale it down. When it starts again later, either from real failover or manually, the agent reconciles to the latest deployment revision automatically rather than replaying old jobs.
Set up the standby machine
AWS
1. Prepare the standby EC2 instance
Create an EBS-backed EC2 instance with:
- Docker
- the Nethera agent
- NVIDIA drivers and the NVIDIA Container Toolkit, if required
- enough persistent EBS storage for container data and model caches
Pair the instance with Nethera and add its machine name to the app's targets.
Deploy while the instance is running and verify that it becomes a healthy backend.
Stop the instance after verification. EC2 does not charge for instance usage while an EBS-backed instance is stopped, but EBS volumes and some attached resources remain billable.
2. Create the Lambda
Create a Lambda function that calls StartInstances for the standby instance.
Example:
import {
EC2Client,
StartInstancesCommand,
} from "@aws-sdk/client-ec2";
const client = new EC2Client({});
export const handler = async () => {
await client.send(
new StartInstancesCommand({
InstanceIds: [process.env.INSTANCE_ID!],
}),
);
return {
statusCode: 202,
body: JSON.stringify({ starting: true }),
};
};Set:
INSTANCE_ID=i-0123456789abcdef0Grant the Lambda permission only to start the selected instance.
3. Expose the Lambda
Expose it using either:
- a Lambda Function URL; or
- API Gateway.
Store the resulting HTTPS URL as the Nethera webhook secret:
$neth secrets set FAILOVER_WEBHOOK4. Test failover
With the primary unavailable and the EC2 standby stopped, request the Nethera endpoint.
Confirm that:
- Nethera invokes the webhook after the configured delay.
- EC2 enters the
pendingand thenrunningstate. - The Nethera agent reconnects.
- The current deployment revision is reconciled.
- The service becomes healthy.
- Nethera resumes routing.
5. Stop the standby again
After the primary has recovered and the standby is no longer serving requests, stop the EC2 instance manually or through separate automation.
Do not stop it while requests are still active.
Optional: use an Auto Scaling warm pool
For more advanced setups, an Auto Scaling Group can keep a pre-initialized instance in a stopped warm pool. The failover webhook sets desired capacity from 0 to 1.
This requires:
- a launch template;
- automatic Nethera agent enrolment or reusable pairing credentials;
- lifecycle hooks for initialization;
- persistent storage planning;
- instance reuse on scale-in.
Use this only when you need ASG-managed replacement or faster repeated scale-out.
Azure
1. Prepare the standby VM
Create an Azure VM with:
- Docker
- the Nethera agent
- GPU drivers if required
- persistent managed disks for Docker data, application data, and model caches
Pair it with Nethera, add it to targets, deploy once, and verify that it serves traffic.
Deallocate the VM after testing. Use deallocate, not merely operating-system shutdown, because deallocation releases the compute allocation and stops compute billing.
2. Create the Azure Function
Create an HTTP-triggered Azure Function.
Give its managed identity permission to start only the standby VM.
The function should invoke the Azure Compute API start operation for:
subscription
resource group
VM nameConceptually:
await computeClient.virtualMachines.beginStartAndWait(
resourceGroupName,
vmName,
);Return 202 Accepted once the start request has been submitted. Do not wait for Nethera or the application to become healthy inside the function.
3. Configure the webhook
Expose the Function through HTTPS and store its URL:
$neth secrets set FAILOVER_WEBHOOK4. Test failover
Confirm that the webhook:
- starts the deallocated VM;
- allows the existing Nethera agent identity to reconnect;
- causes deployment reconciliation;
- results in the backend returning to rotation.
5. Deallocate after recovery
When the primary is stable and the standby is idle, deallocate the VM again. A powered-off but allocated VM may still incur compute charges; verify that its state is Stopped (deallocated).
Google Cloud
1. Prepare the standby VM
Create a Compute Engine VM with:
- Docker
- the Nethera agent
- GPU drivers if required
- Persistent Disk storage for Docker data, application state, and model caches
Pair it with Nethera, add it to targets, and deploy once while it is running.
Stop the VM after verification. A stopped VM does not incur VM usage charges, but Persistent Disk and reserved static IP resources may remain billable.
2. Create the webhook receiver
Create either:
- a Cloud Run service; or
- an HTTP Cloud Run function.
Give its service account permission to start only the selected VM.
When called, invoke the Compute Engine instances.start operation for the configured project, zone, and instance.
Conceptually:
await instancesClient.start({
project,
zone,
instance: instanceName,
});Return 202 Accepted after the start operation has been requested.
3. Configure Nethera
Store the receiver URL as:
$neth secrets set FAILOVER_WEBHOOK4. Test failover
Confirm that the VM starts, the existing agent reconnects, the deployment reconciles, and the service returns to rotation.
5. Stop after recovery
Stop the VM after the primary is stable and the standby has no active traffic.
Failing over stateful services
Cold failover works most cleanly for stateless services. Both machines run the same image, and either instance can handle a request without depending on files or data stored only on its local disk.
For a stateful production service, the primary and standby need access to the same data, or you need a separate replication and recovery plan. Nethera starts replacement compute and routes traffic to it; it does not replicate application data.
Common approaches include:
- Use a shared managed database. Run Postgres, MySQL, or another database somewhere both the on-prem and cloud instances can reach. The application instances can then fail over without creating separate copies of the database.
- Store files in object storage. Put uploads, generated files, and other durable objects in S3, Azure Blob Storage, Google Cloud Storage, or another S3-compatible service instead of a machine-local Docker volume.
- Use database-native replication. For stricter availability requirements, configure replication and promotion using the database's own tooling or a managed high-availability database service.
- Restore from backups or snapshots. For workloads that can tolerate some data loss, define a recovery point objective and restore the latest known-good snapshot before allowing the standby to serve traffic.
Persistent disks on the standby are still useful for Docker images, model weights, package caches, and other data that can be prepared ahead of time. They should not be treated as a copy of data written to the primary machine.
Important
A Docker volume with the same name on two machines is not shared storage. Each machine receives its own independent volume, and requests may see different data.
Before enabling automatic failover for a stateful service, decide:
- Where the authoritative data lives.
- How the standby accesses or restores it.
- How much data loss is acceptable.
- Whether both instances may write concurrently.
- When the standby is safe to place into service.
FAQ
Does failover replicate my data automatically?
No. This guide fails over compute only. If your service writes local data, see Failing over stateful services above before relying on this for anything other than stateless workloads.
What does the standby cost while it's idle?
Typically only storage and other reserved resources. You're not billed for compute until the webhook actually triggers a start.
How fast does failover happen?
Depends on machine size and how long your container takes to report healthy. A warm pool avoids full cold-boot time (image launch, driver init), but there's still a real startup window, this is cold failover, not instant high availability.
Does the standby need its own deployment step?
No. It's a normal Nethera machine in targets. When it starts, whether manually or via failover, the agent reconciles to your latest deployed revision automatically.
Notes
- This is cold failover, not instant high availability, expect a real gap while the standby starts.
- Large models or datasets should live on persistent disk on the standby, not be re-downloaded on every start.
- Standby machines stay paired with Nethera while stopped, and converge to the latest deployment on reconnect.
- Scaling the standby back down after recovery is a manual step in every provider section above. Automating it fully is reasonable for stateless services; for stateful ones, confirm data has synced back before scaling to zero.