From 2810fe849c5abb801ebf75de49d8105578737e04 Mon Sep 17 00:00:00 2001 From: Minseong Choi Date: Wed, 1 Jul 2026 15:09:04 +0900 Subject: [PATCH] fix(cfsetup): repoint stale DNS record when routing a tunnel hostname RouteDNS ran `cloudflared tunnel route dns` without --overwrite-dns and swallowed the resulting "record already exists" error as success. When a hostname already had a CNAME from an earlier tunnel that was deleted and recreated, the record stayed bound to the dead tunnel: the setup reported the hostname "routed" while it kept returning Cloudflare error 1033 (the tunnel it pointed at has no connector). Pass --overwrite-dns so the record is repointed at the tunnel just created, making the route idempotent and correct on every re-run, and drop the now-unnecessary "already exists" swallow. INTEGRATION-ONLY (ExecRunner shells out to the real cloudflared binary). --- internal/cfsetup/runner.go | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/internal/cfsetup/runner.go b/internal/cfsetup/runner.go index 43e611f..ee86ddf 100644 --- a/internal/cfsetup/runner.go +++ b/internal/cfsetup/runner.go @@ -145,13 +145,19 @@ func (r *ExecRunner) credentialsPath(id string) string { return id + ".json" } -// RouteDNS runs `cloudflared tunnel route dns `, creating the -// proxied CNAME. It is idempotent on cloudflared's side for an existing record. +// RouteDNS runs `cloudflared tunnel route dns --overwrite-dns `, +// creating (or repointing) the proxied CNAME so hostname resolves to THIS tunnel. +// +// --overwrite-dns is load-bearing, not cosmetic. Without it, when a record for +// hostname already exists — most commonly a stale CNAME left by an earlier tunnel +// that was created and later deleted/recreated on the same box — cloudflared refuses +// with "record already exists" and changes nothing, leaving the name bound to the +// dead tunnel. The old code swallowed exactly that error as success, so a re-run +// reported "routed" while the hostname kept returning Cloudflare error 1033: the +// tunnel it still pointed at had no connector. Overwriting repoints the record at the +// tunnel we just created, making the route idempotent AND correct on every re-run. func (r *ExecRunner) RouteDNS(ctx context.Context, tunnelID, hostname string) error { - _, err := r.runCloudflared(ctx, "tunnel", "route", "dns", tunnelID, hostname) - if err != nil && strings.Contains(err.Error(), "already exists") { - return nil - } + _, err := r.runCloudflared(ctx, "tunnel", "route", "dns", "--overwrite-dns", tunnelID, hostname) return err }