Skip to main content
A multi-region setup in Ravion is a copy of your regional stack per region plus one global DNS layer that decides which copy a user reaches. Modules aren’t region-aware: every instance has an aws_region, so you run one set of instances per region and tie them together with a Route 53 module using latency routing. Route 53 answers each query with the region closest to the resolver and skips regions whose load balancer is unhealthy. This guide builds on Custom domains.

Choose a topology

The Route 53 records are the same in every topology — only the record name changes. Latency routing needs a hostname Route 53 owns, so if your public domain is managed elsewhere, delegate a subdomain such as origin.example.com to a Route 53 hosted zone and use the CloudFront topology.

Step 1: Duplicate the regional stack

Add one copy of your network, certificate, cluster, and web service per region. Use region-suffixed givenIds and set aws_region on the modules that take it. Give each web service build_source: ecr so Ravion manages an ECR repository in that region without a per-region build; the pipeline in the next section pushes the image to all of them.
ravion.yaml
Two rules that are easy to miss:
  • Certificates are regional. An ALB’s ACM certificate must be issued in the ALB’s region, so each region needs its own rvn-acm-certificate. A wildcard keeps one certificate valid for the public hostname and any origin hostname you add later.
  • Every region gets the same host_header_values. Whichever region a request lands in, the listener rule must match the hostname users typed — or, with CloudFront, the hostname CloudFront forwards.
Apply the config:

Step 2: Build once, deploy everywhere

Use a single pipeline: one build:image step pushes the same image to every region’s ECR repository, then a deploy step per region releases that one digest. Each service’s repository ARN is the ecr_repository_arn output of its stack.
pipeline.yaml
Make the deploys sequential instead of parallel if one region should act as a canary. There is no atomic multi-region switch: while the deploy steps run, regions briefly serve different versions.

Step 3: Create latency records

Route 53 alias records need each region’s load balancer DNS name and hosted zone ID. Both are outputs of the module that owns the ALB; read them from the module’s Outputs tab or ravion stack get <stack-id> --json.
Today you copy these values into the Route 53 module by hand — the records input doesn’t yet accept a moduleGivenIdRef. If you recreate a load balancer, update the alias values too.
Add an rvn-route53 module with one A alias record per region, all sharing the same name. Three fields turn an alias into a latency record: routing_policy: latency, a unique set_identifier, and latency_routing_policy_region set to the region the load balancer is in.
ravion.yaml
Set alias_evaluate_target_health: true on every record. Route 53 then reads the ALB’s own target health — no extra health check needed — and stops returning a region whose targets are unhealthy, so users fail over to the next-closest region within a minute or two. Repeat the records with type: AAAA if you serve IPv6.
Route 53 evaluates an ALB alias per target group: one unrelated service on a shared cluster ALB with zero healthy tasks marks the whole region unhealthy. If several services share the ALB, give the multi-region service its own load balancer, or replace alias_evaluate_target_health with a Route 53 health check on your /healthz path via health_check_id.
If a regional target isn’t an AWS load balancer (a Cloudflare tunnel, another provider’s endpoint), use a CNAME record instead: target_type: standard, the hostname in record_value, a low ttl, and a Route 53 health check in health_check_id — CNAMEs can’t use alias_evaluate_target_health.
Skip to Step 5 if you’re using the load-balancer-only topology.

Step 4 (optional): Put CloudFront in front

Keep the latency records from Step 3 but rename them to an origin hostname, then add a CloudFront distribution and a public record that points at it.
1

Rename the latency records

Change name on each latency record from api.example.com to origin.example.com. Everything else stays the same.
2

Add a CloudFront module with a custom origin

Point origin_domain_name at the latency-routed hostname. CloudFront needs its own certificate in us-east-1:
ravion.yaml
CloudFront forwards the viewer’s Host header (api.example.com) to the origin, so keep it in each region’s host_header_values. The wildcard certificate from Step 1 covers both names.
3

Point the public hostname at CloudFront

In Route 53, add a plain alias for api.example.com:
ravion.yaml
If the public zone is with another DNS provider, create a CNAME to the distribution domain there instead. Only origin.example.com needs to live in Route 53.
Each CloudFront edge resolves origin.example.com itself, so Route 53 answers with the region closest to that edge: a viewer in Frankfurt reaches eu-west-1, a viewer in Chicago reaches us-east-2. Regional failover still comes from alias_evaluate_target_health on the origin records.

Step 5: Verify routing

1

Test each regional endpoint directly

A TLS error means the regional certificate doesn’t cover the hostname; a 404 or 421 means host_header_values doesn’t match.
2

Ask Route 53 what it answers from another location

Route 53 honors EDNS client subnet, so you can query an authoritative name server as if you were a resolver elsewhere:
In the CloudFront topology, query origin.example.com instead.
3

Rehearse a failover

Scale one region’s service to zero tasks, watch dig +subnet for that region flip to the other one within a couple of minutes, then roll back.

What multi-region doesn’t solve

Latency routing spreads stateless compute. Everything else needs its own plan:
  • Databases and caches are regional. Either accept cross-region latency to a single primary, or use a replicated store (Aurora Global Database, DynamoDB global tables) and point each region’s service at its local endpoint.
  • Parameter Store is regional; Secrets Manager isn’t. Replicate a Secrets Manager secret to every region and use the regional replica ARN in each service’s valueFrom. Parameter Store has no replication, so create parameters per region. See Managing secrets.
  • Sessions and uploads. Anything on the instance or in a single-region bucket won’t follow a user routed elsewhere. Use tokens for sessions and S3 Cross-Region Replication, or one bucket behind CloudFront, for objects.

Troubleshooting