Route53 DNS¶
CWIQ.IO uses split-horizon DNS: public zones for internet-facing records and private zones for internal VPC resolution. All zones live in the shared-services account.
Zone Structure¶
| Zone Name | Type | Account | Hosted In | Purpose |
|---|---|---|---|---|
cwiq.io |
Public | shared-services | Route53 | Root domain, delegated from registrar |
shared.cwiq.io |
Public | shared-services | Route53 | Public records for shared-services services |
shared.cwiq.io |
Private | shared-services | Route53 | Internal VPC records (NLB, Tailscale IPs) |
dev.cwiq.io |
Public | shared-services | Route53 | Public records for dev services |
dev.cwiq.io |
Private | dev | Route53 | Internal dev VPC records |
Management account has orphaned duplicate zones
The management account (921838417607) has stale duplicate Route53 zones for shared.cwiq.io and dev.cwiq.io. Never modify these. Always work in the shared-services account (308188966547).
Split-Horizon DNS¶
A split-horizon (split-brain) setup means the same hostname resolves to different IPs depending on where the query comes from:
| Query Source | Zone Used | Resolves To |
|---|---|---|
| Internet / external | Public zone | ALB DNS name (e.g., GitLab ALB), Tailscale IP |
| Dev VPC instances | Private zone (associated) | VPC private IP or NLB private IP |
| Shared-services VPC | Private zone (owner) | VPC private IP |
Example — nexus.shared.cwiq.io:
- From internet or Tailscale client: resolves to Tailscale IP (
100.x.x.x) - From dev VPC (EKS runner pod): resolves to VPC private IP (
10.0.x.x) via private zone — no Tailscale needed, works over VPC peering
This pattern allows CI/CD jobs running as EKS pods (no Tailscale) to reach shared-services using the same hostname that human operators use via Tailscale.
Cross-Account Private Zone Association¶
The shared.cwiq.io private zone (owned by shared-services) is associated with the dev VPC. This requires resources in both accounts:
Shared-services account — creates authorization:
resource "aws_route53_vpc_association_authorization" "shared_internal_to_dev" {
zone_id = <shared_internal_zone_id>
vpc_id = "<dev_vpc_id>"
}
Dev account — creates association:
resource "aws_route53_zone_association" "shared_internal" {
zone_id = var.shared_internal_zone_id
vpc_id = var.vpc_id
}
After association, dev VPC instances can resolve *.shared.cwiq.io private records without going over the public internet.
DNS Record Inventory¶
Shared-Services Public Zone (shared.cwiq.io)¶
| Record | Type | Target | Notes |
|---|---|---|---|
gitlab.shared.cwiq.io |
A (Alias) | shared-gitlab-alb DNS |
Internet-facing ALB |
registry.shared.cwiq.io |
A (Alias) | shared-gitlab-alb DNS |
Container registry via same ALB |
wiki.shared.cwiq.io |
A (Alias) | shared-gitlab-alb DNS |
GitLab Pages via SNI routing |
vault.shared.cwiq.io |
A | Tailscale IP | Vault server (Tailscale access) |
nexus.shared.cwiq.io |
A | Tailscale IP | Nexus (Tailscale access) |
grafana.shared.cwiq.io |
A | Tailscale IP | Grafana |
prometheus.shared.cwiq.io |
A | Tailscale IP | Prometheus |
loki.shared.cwiq.io |
A | Tailscale IP | Loki |
sonarqube.shared.cwiq.io |
A | Tailscale IP | SonarQube (Tailscale) |
defectdojo.shared.cwiq.io |
A | Tailscale IP | DefectDojo (Tailscale) |
sso.shared.cwiq.io |
A | NLB/Tailscale | Authentik HA |
icinga.shared.cwiq.io |
A | Tailscale IP | Icinga master |
ansible-shared-cwiq-io.* |
— | Tailscale MagicDNS | Managed by Tailscale |
Shared-Services Private Zone (shared.cwiq.io)¶
| Record | Type | Target | Purpose |
|---|---|---|---|
sonarqube.shared.cwiq.io |
A | 10.0.10.8 |
VPC private IP for EKS runner pods |
nexus.shared.cwiq.io |
A | VPC private IP | Docker pull for EKS runner pods |
docker.nexus.shared.cwiq.io |
A | VPC private IP | Docker push/pull |
Dev Zone (dev.cwiq.io)¶
| Record | Type | Target | Notes |
|---|---|---|---|
orchestrator.dev.cwiq.io |
A | 10.1.35.46 (VPC) or Tailscale |
Orchestrator DEV server |
langfuse.dev.cwiq.io |
A | Tailscale IP (100.119.26.88) |
LangFuse (Docker DNS resolution requires Tailscale IP) |
Tailscale MagicDNS¶
Tailscale provides its own DNS layer (*.cwiq-io.ts.net or via MagicDNS hostnames using dashes). This is separate from Route53 and resolves directly to Tailscale IPs.
Use dashes for Tailscale hostnames, never dots
When configuring Alloy, Prometheus, or any service to reach another server over Tailscale, use the dash-format hostname (loki-shared-cwiq-io), not the FQDN (loki.shared.cwiq.io). The FQDN resolves to VPC private IPs that are not routable cross-VPC.
See MagicDNS & Hostname Conventions for the full reference.
Terraform Location¶
DNS records are defined per service module:
terraform-plan/organization/environments/shared-services/ec2-instances/
├── gitlab/
│ └── route53.tf ← ALB alias records for gitlab, registry, wiki
├── nexus/
│ └── main.tf ← Tailscale IP + private zone records
├── sonarqube/
│ └── main.tf ← Tailscale IP + private zone record (10.0.10.8)
└── ...
Related Pages¶
- Multi-Account Setup — Cross-account private zone authorization
- ALB Patterns — ALB alias record setup
- Tailscale MagicDNS — Hostname conventions and when to use each DNS type