Rollback
Date: 2026-06-26
This guide explains how to safely remove or roll back a BetterNAT deployment.
Use this guide before deleting gateway instances, route tables, EIPs, Auto Scaling groups, or DynamoDB tables by hand. For GCP, use it before deleting gateway instances, routes, regional static addresses, Managed Instance Groups, service accounts, or Firestore records by hand.
Emergency Route Restore
Section titled “Emergency Route Restore”Use this section when private workloads have lost egress and you already know the previous route target.
Set the route table and fallback target:
export AWS_REGION=us-west-2export PRIVATE_RTB_ID=rtb-xxxxxxxxexport FALLBACK_NAT_GW_ID=nat-xxxxxxxxRestore the private default route to the previous NAT Gateway:
aws ec2 replace-route \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --route-table-id "$PRIVATE_RTB_ID" \ --destination-cidr-block 0.0.0.0/0 \ --nat-gateway-id "$FALLBACK_NAT_GW_ID"If the fallback target is an EC2 NAT instance instead:
aws ec2 replace-route \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --route-table-id "$PRIVATE_RTB_ID" \ --destination-cidr-block 0.0.0.0/0 \ --instance-id i-xxxxxxxxIf the fallback target is an ENI:
aws ec2 replace-route \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --route-table-id "$PRIVATE_RTB_ID" \ --destination-cidr-block 0.0.0.0/0 \ --network-interface-id eni-xxxxxxxxVerify the route and egress:
aws ec2 describe-route-tables \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --route-table-ids "$PRIVATE_RTB_ID" \ --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'
curl -fsS https://checkip.amazonaws.comcurl -fsSI https://example.comAfter egress is restored, decide whether to keep BetterNAT running for diagnostics or run Terraform destroy. Do not delete BetterNAT instances, route tables, EIPs, or the coordination table by hand before route state is safe.
What Rollback Means
Section titled “What Rollback Means”BetterNAT sends private-subnet egress through cloud routes such as:
0.0.0.0/0 -> active BetterNAT gateway nodeDuring install, the provider snapshots the previous target for every managed private route table. During destroy, it can restore those routes before deleting BetterNAT-managed resources.
On GCP, BetterNAT owns the tagged static route named by route_name. The
module does not create or delete an existing regional static external IPv4
address used for stable public identity, so that address remains in the calling
Terraform stack or infra-admin stack.
Supported rollback targets include:
- NAT Gateway IDs:
nat-* - EC2 instance IDs:
i-* - ENI IDs:
eni-* - Internet Gateway IDs:
igw-* - Virtual Private Gateway IDs:
vgw-* - Transit Gateway IDs:
tgw-* - VPC Peering Connection IDs:
pcx-* - Egress-only Internet Gateway IDs:
eigw-*
If the previous target is missing or unknown, BetterNAT will not silently destroy the gateway and leave private subnets without a known route unless you explicitly opt in.
Terraform Defaults
Section titled “Terraform Defaults”The relevant module/provider fields are:
resource "betternat_aws_gateway" "egress" { rollback_on_destroy = true allow_destroy_without_rollback = false}Defaults:
| Field | Default | Meaning |
|---|---|---|
rollback_on_destroy | true | Restore captured private route table targets during terraform destroy. |
allow_destroy_without_rollback | false | Refuse destroy if rollback targets are unknown or incomplete. |
Keep these defaults unless you have manually restored the private route table state or you intentionally accept temporary egress loss.
Choose The Right Path
Section titled “Choose The Right Path”| Situation | Path |
|---|---|
| Private egress is down now and the old route target still exists. | Use Emergency Route Restore, then investigate. |
| You are cleaning up a disposable test deployment. | Use Normal Destroy. |
terraform destroy refuses to continue because rollback metadata is missing. | Use If Destroy Refuses To Roll Back. |
| The previous route target was deleted. | Read Stale Rollback Targets before destroying anything else. |
| You are migrating production from NAT Gateway to BetterNAT. | Follow Production Rollback Pattern. |
| You are testing GCP in a disposable VPC. | Use GCP Destroy And Cleanup. |
Normal Destroy
Section titled “Normal Destroy”For a disposable or test deployment, use Terraform destroy:
terraform -chdir=examples/terraform-aws-supplemental destroy \ -var "run_id=$BETTERNAT_RUN_ID" \ -var "region=$AWS_REGION" \ -var "az=$BETTERNAT_AZ" \ -var "betternat_version=$BETTERNAT_VERSION"Expected order:
- Terraform reads
rollback_route_targets_jsonfrom state. - The provider restores the previous target for each managed private route table.
- The provider scales down and deletes BetterNAT Auto Scaling groups.
- The provider deletes launch templates, EIPs, DynamoDB lease table, IAM resources, and the BetterNAT security group.
- Terraform deletes the surrounding fixture resources if the example created them.
Verify Route Restoration
Section titled “Verify Route Restoration”After destroy, inspect the private route tables that BetterNAT managed:
aws ec2 describe-route-tables \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --route-table-ids rtb-xxxxxxxx \ --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]'Confirm that 0.0.0.0/0 no longer points to a BetterNAT gateway node or ENI unless that is the route state you intentionally chose.
Also scan for tagged residual resources:
aws resourcegroupstaggingapi get-resources \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --tag-filters "Key=BetterNATRunId,Values=$BETTERNAT_RUN_ID"Terminated EC2 instances may remain visible briefly. Check direct EC2 state before treating them as live resources.
GCP Destroy And Cleanup
Section titled “GCP Destroy And Cleanup”For a disposable GCP deployment, use Terraform destroy first:
terraform destroyExpected order:
- Terraform removes BetterNAT gateway capacity.
- The provider removes the tagged route it owns.
- The provider removes instance templates, MIGs, service accounts, custom IAM bindings, and Firestore database only when those lifecycles were enabled in the same stack.
- Terraform removes surrounding VPC fixture resources if the example created them.
After destroy, verify no run-scoped resources remain:
gcloud compute instances list --filter="name~<run-id>"gcloud compute routes list --filter="name~<run-id>"gcloud compute firewall-rules list --filter="name~<run-id>"gcloud iam service-accounts list --filter="email~<run-id>"If stable public identity used a regional static external IPv4 address owned by the calling stack, confirm whether that address should remain reserved or be destroyed by its owning Terraform resource. Do not delete a shared address by hand while another route or allowlist still depends on it.
Firestore handover records may outlive a destroyed disposable gateway when the Firestore database is shared. Delete only run-scoped BetterNAT documents after confirming the gateway stack is gone.
If Destroy Refuses To Roll Back
Section titled “If Destroy Refuses To Roll Back”You may see an error like:
Refusing to destroy BetterNAT gateway without rollback targetsThis means:
rollback_on_destroyistrue,allow_destroy_without_rollbackisfalse,- and Terraform state does not contain concrete previous route targets.
Do not immediately set allow_destroy_without_rollback = true.
First inspect the route tables:
terraform -chdir=<your-config-dir> state list | grep betternatterraform -chdir=<your-config-dir> state show <betternat-resource-address>
aws ec2 describe-route-tables \ --profile "$AWS_PROFILE" \ --region "$AWS_REGION" \ --route-table-ids <private-route-table-id>Then decide one of these paths:
- Restore private routes manually to a known-good target, such as the previous NAT Gateway.
- Re-run
terraform destroyafter the route state is safe. - Only if you have already restored or intentionally accepted the route state, set:
allow_destroy_without_rollback = trueThen run destroy again.
Manual Route Restore
Section titled “Manual Route Restore”Manual route restore means replacing the private route table default route with a known-good fallback target, usually the previous NAT Gateway, NAT instance, or ENI. Use the commands in Emergency Route Restore.
After manual restore:
- Verify the AWS route table points to the intended fallback target.
- Verify egress from a private workload.
- Keep BetterNAT resources intact until Terraform state, route ownership, and rollback metadata are understood.
- Run Terraform destroy only after route state is safe.
Stale Rollback Targets
Section titled “Stale Rollback Targets”If the captured previous target no longer exists, the provider skips some stale-target errors during rollback:
- missing ENI,
- missing NAT Gateway,
- missing EC2 instance.
That prevents destroy from being permanently blocked by an already-deleted fallback target, but it also means you must verify the private route table after destroy. A skipped stale target may leave the route table in a state that still needs manual correction.
What Not To Do
Section titled “What Not To Do”Avoid these actions unless you are following a deliberate manual recovery plan:
- Do not delete BetterNAT EC2 instances before route rollback.
- Do not delete the DynamoDB lease table while agents are still running.
- Do not delete EIPs before checking which public identity private subnets should use after rollback.
- Do not delete GCP Firestore records, MIGs, routes, or regional static addresses before route ownership is understood.
- Do not delete route tables managed by another Terraform stack.
- Do not run competing Terraform resources that also manage the same
0.0.0.0/0route while BetterNAT is active.
Production Rollback Pattern
Section titled “Production Rollback Pattern”For production migration from NAT Gateway to BetterNAT:
- Keep the existing NAT Gateway until BetterNAT is verified.
- Use BetterNAT on selected private route tables first.
- Verify private egress and observability.
- Confirm
rollback_route_targets_jsoncontains concrete previous targets. - Keep a manual
replace-routecommand ready for each private route table. - Only remove the old NAT Gateway after the rollback window is over.
Current Limitations
Section titled “Current Limitations”- There is no managed BetterNAT control server for one-click rollback.
- Active flows may reset during route changes.
- Rollback is route-target based; it does not recreate a deleted previous NAT Gateway.
- Destroy is not an upgrade mechanism. For upgrades, prefer the upgrade/replacement guide.