DNS Inventory & Cutover Runbook

Published

September 17, 2026

NoteStatus: draft, unreviewed

Built from a Route53 hosted-zone export for bioconductor.org (166 records, reviewed 2026-09) plus a direct HTTPS probe of every resolvable hostname in it — not just the DNS target, but what each one actually serves today. Satisfies the M1 tasks “decide www./secure. and satellite hostnames” and “cutover runbook page (DNS, verification, rollback)” from the roadmap. Not yet walked with the core team — treat every status and finding below as the reviewer’s read, not a decision. Probes were run from the open internet with no VPN/internal access, so “no response” below means not reachable from outside, not necessarily dead.

Updated 2026-09-17: the apex mechanism is settled — the zone’s nameservers move to Cloudflare — and the migration plan below was added. The plan is a proposal; no step in it has been executed.

What M1 actually changes

Two records carry the entire cutover:

Hostname Type Current target Note
bioconductor.org (apex) A, Route53 Alias d3hzwifbu1gvt4.cloudfront.net. The CloudFront distribution being retired
www.bioconductor.org A, Route53 Alias bioconductor.org. Aliases to the apex, not to CloudFront directly

Both are live and serve the production site (“Bioconductor - Home”) today. Everything else in the zone is satellite: conference sites, mailing-list infrastructure, build machines, DKIM keys. None of it needs to change for the site itself to move — it either already points off AWS, or points at AWS/Jetstream2 resources this cutover doesn’t touch.

The apex is the hard part

Route53 “Alias” records — the mechanism used for the apex today — only resolve to AWS resources (CloudFront, ELB, S3, another record in the same zone, etc.). They cannot target an arbitrary external host like bioc-dev.cancerdatasci.org, and a plain CNAME isn’t legal at a zone apex per the DNS spec. www.bioconductor.org doesn’t have this problem — it’s not the apex, so it can become a normal CNAME to the new edge once the zone is ready. Decision (2026-09-17): move the zone’s nameservers to Cloudflare. Cloudflare flattens a CNAME at the apex, so the apex can target the Worker directly, and AWS leaves the DNS path entirely. The domain registration stays at AWS; only the nameservers change.

Rejected: a thin CloudFront distribution as a pass-through, origin set to bioc-dev.cancerdatasci.org, with the Route53 Alias repointed at it. It moves no records, but keeps AWS in the request path indefinitely and adds a cache-miss origin-fetch charge (~$0.02/GB) on top of viewer egress.

Migration plan

Two separately reversible steps. Step one moves the zone to Cloudflare as an exact copy, apex still resolving to today’s CloudFront distribution — users see nothing, and anything that breaks is a mis-copied record. Step two, later, repoints the apex and www at the new edge — one record each, rolled back by editing them back.

0. A dedicated Cloudflare account, first

The Worker, R2 buckets and dev hostname currently live in a personal account shared with unrelated domains. Recommended: create a Bioconductor-owned account before the zone is added anywhere, because a Worker custom domain must be in the same account as the Worker, and moving a live zone later means a second nameserver change on the production domain plus a data copy under load.

Why separate: Workers and R2 permissions are account-wide (a Bioconductor co-admin would otherwise hold rights over unrelated infrastructure, and vice versa); billing, grants and sponsorships attach to an account; and a project account with 2–3 super administrators survives any one person leaving.

It is a redeploy, not a rebuild — everything is declared in wrangler.jsonc:

Piece Effort Notes
Workers, cron triggers, Workflows (bioc-site, bioc-registry, bioc-prop) minutes Redeploy with the new account ID; code unchanged
Secrets, API tokens ~1 hour Do not transfer; re-set, and reissue CI tokens
R2 buckets bioc-site, bioc-prop ~1 day, mostly waiting No cross-account bucket move exists; copy with Super Slurper or rclone. R2 egress is free, so the cost is write operations — driven by object count, which hasn’t been pulled
Producers writing to R2 1–2 hours The S3 endpoint embeds the account ID; every sync job needs a new endpoint and keys
Analytics Engine dataset bioc_site_requests_v3 not movable History restarts; retention is ~3 months and dev traffic has little value
Logpush job minutes Recreate
In-flight Workflow instances lost Let them finish, or accept a rerun

Order: create the account and add a second super administrator → create buckets and start the copy → deploy Workers to a preview hostname and run the full-crawl diff → repoint producers, then a final sync for anything written since the copy began → add the bioconductor.org zone there.

If the account move is declined, the minimum hedge is a second super administrator on the current account and keeping everything in config, as now.

1. Prepare the zone copy (no user-visible change)

  1. Export from Route53 itself, not from the review spreadsheet — the spreadsheet is already stale (the live apex carries a TXT value acevhogcbpv6dssaq15fbe1ek8 it doesn’t list).
  2. Hand-create the Alias records. They don’t survive a zone-file export: the apex (as a flattened CNAME to d3hzwifbu1gvt4.cloudfront.net), www, and testweb.
  3. Import everything DNS-only — nothing proxied. git serves SSH and rabbitmq is a message broker, so proxying breaks both; the GitHub Pages and Netlify CNAMEs need unproxied records to renew certificates; several builder records hold private addresses that can’t be proxied at all.
  4. Keep the three ACM validation CNAMEs. Without them CloudFront’s certificate stops renewing, and CloudFront is the rollback target.
  5. Copy mail records byte for byte — MX, SPF, _dmarc (p=reject), every DKIM selector, the _amazonses verification TXTs. A mistake here drops mail silently.
  6. Lower the NS record TTL in Route53 (currently 172800 s) at least two days ahead.
  7. Diff every record between Route53 and Cloudflare’s assigned nameservers (dig @<cf-ns> vs dig @<aws-ns>, every name and type). Cut over on an empty diff.

Do the agreed deletions before or after the move, never during. Deleting first makes the diff smaller; records tagged “delete end of 2026” get copied across for now.

2. Change the nameservers

  • Change the nameservers at the AWS registrar. Do not transfer the registration — a transfer adds a lock period and buys no safety.
  • DNSSEC is off today (no DS record published), so there is no signing hazard. Enable it on Cloudflare after things settle, not during.
  • Leave the Route53 zone untouched for at least two weeks.
  • Freeze record changes in that window, or make each change in both places.

Rollback: revert the nameservers at the registrar. Works only while the Route53 zone is still correct — hence the freeze.

3. Flip the site (M1 proper)

  • Attach the Worker to a spare hostname in the new zone first and run cutover-diff.sh against it — this catches anywhere the Worker assumes the dev hostname.
  • HTTP behaviour differs today: production answers http:// with a 301 to HTTPS; the new edge answers 200 over plain HTTP. Pick one deliberately — older R clients still request plain HTTP.
  • Point the apex and www at the Worker. Keep CloudFront and master running until M2 retires them.

Rollback: edit the two records back to CloudFront. Minutes.

Found along the way — fix separately, not during the move

  • The spreadsheet lists a TXT record on a literal @.bioconductor.org label carrying v=spf1 include:spf.forwardemail.net -all. It doesn’t resolve publicly — a data-entry mistake for the apex. The SPF actually in force at the apex is v=spf1 a mx include:_spf.mlsend.com ?all: neutral, and omitting forwardemail.
  • The apex TXT value acevhogcbpv6dssaq15fbe1ek8 has no recorded owner.

Core infrastructure, staying put (27)

Marked “keep” in the source review, not touched by the M1 apex/www flip. Visited each directly (curl -sI https://<host>/) rather than assuming from the hostname.

master.bioconductor.org

A → 52.71.54.154. Live — full production bioconductor.org mirror. This is the legacy master webserver being retired by the M1/M2 migration.

staging.bioconductor.org

A → 52.4.245.79. No public HTTPS response. Confirmed elsewhere in this repo (see the decommission plan) that no web server listens here — this is the legacy build host, not a public site.

git.bioconductor.org

A → 34.192.48.227. Confirmed live: gitolite3 v3.6.6 serving the package git repos directly (admin/…, packages/ABAData, …) — this is the canonical package source, not a redirect target.

chat.bioconductor.org

A → 34.192.48.227. Same redirect target as zulip.bioconductor.org — an alias into the same Zulip Cloud instance.

zulip.bioconductor.org

A → 34.192.48.227. Redirects to the team’s hosted Zulip Cloud instance (community-bioc.zulipchat.com) — the real chat entry point.

www.zulip.bioconductor.org

A → 34.192.48.227. No public response. Shares its target IP with zulip/chat/git/packages — routing for www.-prefixed vhosts on that box looks inconsistent.

www.chat.bioconductor.org

A → 34.192.48.227. No public response, same shared-IP pattern as www.zulip.

packages.bioconductor.org

A → 34.192.48.227. Redirects to the Open Storage Network archive bucket — a convenience alias so people don’t need the full OSN URL to browse package archives.

support.bioconductor.org

A → 54.164.10.157. Live — the Bioconductor Support Forum (Django app, Biostars-derived).

issues.bioconductor.org

A → 52.4.116.154. Responds but the body is literally “Nothing to see here” — currently a stub. Worth checking whether the real issue tracker moved elsewhere, or this is mid-decommission.

code.bioconductor.org

A → 194.94.45.72. No public HTTPS response — purpose unconfirmed from outside; worth a direct look.

rabbitmq.bioconductor.org

A → 52.20.79.236. No public HTTPS response — a message broker (STOMP/AMQP), expected to not answer on plain HTTPS; the SPB build-results pipeline depends on it (see the decommission plan).

pkgmaintainers.bioconductor.org

A → 44.218.162.37. Live — “API Summary,” a maintainer-facing API service.

annotationhub.bioconductor.org

A → 52.73.93.102. Live — “BiocHub Server API,” the AnnotationHub backend.

experimenthub.bioconductor.org

A → 52.73.93.102. Live — same BiocHub Server API, serving ExperimentHub instead of AnnotationHub.

nebbiolo1.bioconductor.org

A → 155.52.47.135. No public HTTPS response — a dedicated Linux package-build machine (release), not a webserver.

nebbiolo2.bioconductor.org

A → 155.52.47.146. No public HTTPS response — same role as nebbiolo1, devel branch.

kjohnson3.bioconductor.org

A → 172.24.216.75. No public HTTPS response — a macOS package-build machine.

workshop.bioconductor.org

A → 149.165.171.210. No public HTTPS response — workshop compute cluster, likely gated (auth or VPN) rather than dead.

workshopauth.bioconductor.org

A → 149.165.154.124. No public HTTPS response — the auth front-end for the workshop cluster above.

webr.bioconductor.org

A → 149.165.154.124. No public HTTPS response despite “keep” status — serves a WebR package repository; each version needs its own path (e.g. /3.23) rather than a splash page at the root, which may explain the empty response at /.

run.webr.bioconductor.org

A → 149.165.154.124. No public HTTPS response — reserved for a planned in-browser WebR demo page (fully client-side, eventually movable to GitHub Pages).

discourse.dev.bioconductor.org

A → 149.165.153.32. No public HTTPS response despite “keep” status — a dev/staging Discourse instance; may only answer on a non-standard port or be gated.

isee.bioconductor.org

A → 149.165.171.200. Live Shiny app — linked to the Bioconductor/isee.bioconductor.org GitHub repo. The wildcard *.isee.bioconductor.org is kept for the same app; check with the app’s maintainer before touching either.

hubsingest.bioconductor.org

A → 149.165.171.200. No public HTTPS response — an ingestion endpoint, not a browsable site. Kept for an active hub-ingestion workflow; confirm it’s still in use before any change.

certs.bioconductor.org

A → 149.165.171.200. Live — the BiocCertificate Shiny app for issuing training certificates.

workinggroups.bioconductor.org

CNAME → bioconductor.github.io. Live — GitHub Pages site for Bioconductor Working Groups.

training.bioconductor.org

CNAME → bioconductor.github.io. Live, but the page title is just “index” — likely a generic template; content itself may still be fine, the title tag just isn’t descriptive.

contributions.bioconductor.org

CNAME → bioconductor.github.io. Live — “Bioconductor Packages: Development, Maintenance, and Peer Review,” the package contribution/review site.

blog.bioconductor.org

CNAME → bioconductor.github.io. Live — the community blog, GitHub Pages.

Undecided — needs an owner (18 with live content or a clear guess; 24 more listed in the appendix table are wildcards or mail/cert plumbing)

testweb.bioconductor.org

A → d3h1507zzd6849.cloudfront.net.. No public HTTPS response. Points at a second, separate CloudFront distribution (d3h1507zzd6849.cloudfront.net, different from production) — worth checking what that distribution is before the main cutover, in case it needs retiring alongside it.

testinggit.bioconductor.org

A → 44.207.152.77. No public HTTPS response — looks like a test git host, name suggests safe to retire once confirmed unused.

support.test.bioconductor.org

A → 44.210.209.116. No public HTTPS response — test instance of the support forum.

slack.bioconductor.org

A → 34.192.48.227. Serves a generic “Countdown with Embedded Blog” template — not Slack-branded content. Whatever this vhost used to do, it no longer matches its hostname; worth a direct look before deciding keep/delete.

posters.bioconductor.org

CNAME → bioconductor.github.io. No public HTTPS response despite pointing at GitHub Pages — check whether the underlying Pages site still exists.

pm-bounces.bioconductor.org

CNAME → pm.mtasv.net. No public HTTPS response — mailing-list bounce handling (Postmark), not meant to be browsed.

osca.bioconductor.org

CNAME → bioconductor.github.io. Live — redirects into “the OSCA book” (Orchestrating Single-Cell Analysis), an external teaching resource.

osca-dev.bioconductor.org

CNAME → bioconductor.github.io. Same pattern as osca, development version.

new.bioconductor.org

A → 52.71.54.154. Live, and resolves to the same IP as master.bioconductor.org, serving an identical “Bioconductor - Home” page. Looks like a leftover alias rather than a distinct site — worth confirming with the team before assuming it can be dropped.

meet.bioconductor.org

A → 54.82.236.113. No public HTTPS response — purpose unconfirmed; hostname suggests a meeting/scheduling tool.

gitdevtest2.bioconductor.org

A → 149.165.171.129. No public HTTPS response — second test git host, same IP as the first.

gitdevtest.bioconductor.org

A → 149.165.171.129. No public HTTPS response — test git host.

federated-packages.bioconductor.org

A → 149.165.155.146. No public HTTPS response — purpose unconfirmed; name suggests an experimental federated package-serving effort.

courses.bioconductor.org

A → 52.54.47.64. No public HTTPS response — purpose unconfirmed.

core-sops.bioconductor.org

CNAME → victorious-wave-0b018b710.4.azurestaticapps.net. Live, redirects to a /login/ page — internal SOPs site (Azure Static Web Apps), access-gated as expected.

cfp.bioconductor.org

A → 3.139.155.94. No public HTTPS response — hostname suggests a call-for-proposals form, possibly tied to a past conference and safe to retire, but unconfirmed.

auth.bioconductor.org

A → 149.165.153.78. No public HTTPS response — likely an internal auth service (the wildcard *.auth.bioconductor.org mirrors it). Undecided status suggests this needs an owner check.

anvil.bioconductor.org

CNAME → bioconductor.github.io. Live — BiocAnVIL project pages, part of the AnVIL cloud-genomics collaboration.

Already off AWS — no action (27, one table)

Event-site CNAMEs (bioc20{18..26}, biocasia20{20..26}, eurobioc20{19..26}, gbcc2025) plus dev.status, and fe-bounces — all confirmed live, all pointing at GitHub Pages, Netlify, or forwardemail.net. None resolve through CloudFront, master, or staging — the cutover is invisible to them.

Delete candidates (25) — confirmed unreachable

Every host in this list returned no public HTTPS response in the probe, consistent with being retired already: tokay1/2, merida1/2, malbec1/2, machv2, celaya2, monitor, docbuilder, kjohnson1, k8slaunch, js2launch, bbr (×2), yescure(cluster), prodaks — plus seven tagged “delete end of 2026” (workshopk8s, workshopcluster, prodk8s, hsdsdev, cloudman.kubeinstall, ci-mirror, biocworkshop), presumably tied to a class or grant ending. The probe is supporting evidence for the delete call, not proof — “no public HTTPS” doesn’t rule out an internal-only service still in use.

Mail/cert plumbing and wildcards, undecided (24)

Not individually probed — none of these are meant to serve HTTP content. ACM certificate-validation CNAMEs (_....acm-validations.aws.) and DKIM selector CNAMEs need re-verification against whatever currently sends mail as bioconductor.org, not assumption of obsolescence. The wildcard records (*.workshop, *.auth, *.bbr, …) mirror a decision already made on their base hostname above but weren’t themselves tagged — worth confirming they’re meant to inherit it rather than being reviewed independently.

Open questions for the core team

  • Apex mechanism — settled 2026-09-17: nameserver migration to Cloudflare, see the migration plan.
  • Dedicated Bioconductor Cloudflare account: agree, and name the super administrators and the billing owner.
  • R2 object count for bioc-site and bioc-prop — sizes the account-move copy (time and write-operation cost).
  • Plain-HTTP behaviour on the new edge: redirect to HTTPS like production, or serve 200?
  • Which SPF record is intended at the apex, and who owns the unlisted apex TXT value?
  • new.bioconductor.org mirrors master.bioconductor.org exactly (same IP, same content) — leftover alias or intentional?
  • slack.bioconductor.org serves a generic template unrelated to its name — check what this vhost is actually for.
  • issues.bioconductor.org responds with a bare “Nothing to see here” — confirm whether the real tracker moved.
  • Confirm the 18 undecided hosts above, especially the stale-looking test hosts (testweb, testinggit, gitdevtest, gitdevtest2, support.test) and the second CloudFront distribution behind testweb (d3h1507zzd6849.cloudfront.net, distinct from production — does it need retiring too?).