Common Pitfalls
Everything below was hit (and solved) in real deployments. Skim this before the deployment window.
GPU quota is 0 in fresh accounts
Symptom: every pod is green except vLLM, which sits Pending; the LlamaFirewall server loops on readiness.
Cause: "Running On-Demand G and VT instances" quota is 0 by default in many accounts, so Auto Mode cannot launch the g5.xlarge node.
Fix: request the quota increase days in advance (see prerequisites §2). Nothing else in the install blocks on it — the GPU workload joins when capacity appears.
DNS delegation missing → certificate stalls
Symptom: deployment sits at the ACM certificate step for 30+ minutes.
Cause: the Route53 zone's NS records were never added at the parent domain, so ACM's DNS validation records aren't publicly resolvable.
Check before the window: dig NS <your-zone> must return the four awsdns name servers.
Reaching an internal NLB
The default ingress is an internal NLB — the service URLs resolve publicly but to private IPs in your VPC. Browsers outside the VPC time out; that's by design, not a fault. Your options, pick one before user testing starts:
- Corporate VPN / Client VPN with a route to the VPC (VPC peering + route table entries + VPN route/authorization for the VPC CIDR). Split-tunnel VPN clients must reconnect after routes change — routes are pushed at connect time.
- VPC peering from an existing internal network.
ingressPublic: trueat deploy time (requires ≥2 public subnets) — then restrict by source ranges.
SES sandbox mode
Even with SES configured, a sandboxed SES account only delivers to verified recipients. Symptoms look like "invitation emails silently lost". Request SES production access early — approval can take a day. No SES at all → install succeeds, email-dependent flows fail (see prerequisites §7).
reCAPTCHA domain allow-list
The site key works only on domains listed in the Google reCAPTCHA admin console. The widget renders regardless — the failure appears at verification time on form submit. Add your OpenBox domain (or its parent) to the key before user testing.
First-install database poisoning
Symptom: after a failed or interrupted first install, every retry crash-loops on Postgres. Cause: a half-initialized Postgres volume persists across reinstalls; the bundled database refuses to re-init a non-empty data directory. Fix (operator runbook): uninstall the release without hooks, delete the Postgres PVC, redeploy. Client action: none — but expect the deployment window to extend ~15 minutes if it happens.
Pinned image tags vs. branch tags
Production installs must run main-<sha> image tags. Branch-built tags (feat-…) are used only during joint debugging and are pruned by registry retention — never leave an install running on one after the session ends.
Kubernetes version support window
The CDK supports minors 1.31–1.36 (kubectl tooling is version-locked). Asking for anything else fails config validation immediately — it's a supported-matrix decision, not a flag to flip.
Region availability
EKS Auto Mode is not in every region. The config validator enforces the allow-list in prerequisites §1; deploying to an unlisted region is a vendor decision (support matrix + testing), not a config override.
Cluster API endpoint mode
clusterEndpointPublicAccess: false (private-only) means all deploy and debug traffic must originate inside your network — the operator needs VPN/bastion access arranged before the window, or the deployment cannot run at all. The default (public+private) avoids this; the API is still IAM-authenticated.
Executor is disabled by default — and that's correct
openbox-executor.enabled=true before its governance Secret exists gives you a pod that starts
but refuses every turn (fail_closed). The obx_key_ credential it needs is minted in-product
after the org is seeded — enablement is inherently two-step (see Deployment Steps). Also note its
inbound caller (ElevenLabs cloud) needs ingressPublic: true; on an internal NLB the endpoint is
VPN-only.
Preflight rejects the VPC (subnet tags / DNS hostnames)
Symptom: the Openbox-Preflight stack fails immediately with openbox preflight failed (N issues) naming missing kubernetes.io/role/internal-elb=1 tags or enableDnsHostnames=false.
Cause: a hand-built VPC. aws ec2 create-vpc leaves enableDnsHostnames=false, and subnet
role tags are never automatic.
Fix: apply the commands in prerequisites §3,
then re-run the deploy. This is the preflight gate doing its job — it fails in ~2 minutes instead
of letting the cluster come up and the ingress silently never get an address 25 minutes later.
Note the stack must be deleted before re-running (a failed CREATE leaves ROLLBACK_COMPLETE,
which CloudFormation cannot update): npx cdk destroy Openbox-Preflight --force.
The allowlist needs your PUBLIC egress IP, not your internal network
Asked for "your network CIDR", people reach for their internal range — 10.x, 172.16-31.x,
192.168.x. On an internet-facing load balancer that matches nothing: AWS accepts the rule,
it never fires, and everyone is locked out of what looks like a broken deployment. The validator
rejects private, CGNAT, loopback and link-local ranges for exactly this reason.
Find the right value from inside your network:
curl -s https://checkip.amazonaws.com
Ask your network team for the full egress range, not just the address you observed. Larger offices egress through several NAT addresses; allowlisting one produces intermittent failures for colleagues — the hardest kind of problem to diagnose remotely.
Locked out of your own deployment
Removing your IP from allowedCidrs cuts your access. Recovery:
- Correct
allowedCidrsand redeploy — the proper fix, ~3-5 minutes. - Emergency stopgap:
kubectl -n ingress-nginx patch svc ingress-nginx-controller -p '{"spec":{"loadBalancerSourceRanges":["<your-ip>/32"]}}'— effective in seconds, but the next deploy reverts it.
Do NOT edit the security group in the AWS console. That SG is owned by the EKS load-balancer
controller (tagged ManagedLBSecurityGroup); it reconciles your change away, so the access
appears to work and then silently disappears minutes later. Config is the source of truth, then
Kubernetes, then AWS — each layer overwrites the one below.
Changing ingressPublic replaces the load balancer
Flipping between public and internal does not reconfigure the existing NLB — AWS creates a brand-new one with a different hostname and deletes the old one. Expect:
- A few minutes of downtime on every openbox hostname while the new NLB provisions and its targets become healthy. Schedule the flip accordingly.
- A DNS reconverge. The deployment rewrites the CNAMEs to the new load balancer automatically; records carry a 5-minute TTL, so allow that long for resolvers to catch up.
- A new security group. Any rule added by hand to the old one is gone. This is another reason
the allowlist belongs in
allowedCidrsand nowhere else.
If hostnames still fail well after the deployment finishes, check what the CNAME actually points at and compare it to the live load balancer:
dig +short openbox-api.<your-domain>
aws elbv2 describe-load-balancers --query 'LoadBalancers[].DNSName' --output text
A CNAME pointing at a load balancer that no longer exists means DNS did not follow the replacement — report it rather than editing Route53 by hand, since the next deployment would overwrite a manual fix.
Public ingress replaces the internal path — VPN users are affected
There is only ever one load balancer. With ingressPublic: true it is internet-facing, so the
internal-only entry point no longer exists, and staff on a VPN no longer reach the application
through the tunnel. Their traffic goes out their normal internet connection instead, arriving
from whatever public address their office or ISP uses — and that address must be in
allowedCidrs or they are blocked like anyone else.
This surprises teams who assume "we're on the VPN" still grants access. Before flipping an existing install to public, collect the public egress address of every site that needs in. The VPN itself keeps working for everything else it does (database access, the Kubernetes API, administrative SSH); it just stops being the way into the application.
Choose ingressPublic: false instead if VPN-only access is what you actually want.
IP allowlists and roaming users
This is solid for fixed offices and server-to-server callers, and poor for anyone on home
broadband, mobile, or hotel wifi — their address changes. For roaming staff, either keep the
install internal (ingressPublic: false) and let them in over the VPN, or route them through a
gateway with a stable public address that you can allowlist. An allowlist alone does not serve
users whose address moves.
Cost expectations while idle
Even an idle install carries a floor cost: NAT gateway ($35–65/mo), the GPU node ($1/hr while LlamaFirewall is enabled), 2–3 general-purpose nodes, and the EKS control plane. If the environment is for evaluation, agree on a teardown or scale-down date up front.