---
id: "8.5"
title: "DNS and domains"
dept: ops-and-infrastructure
status: draft
owner: Param
branded: false
last_verified: 2026-10-26
sources:
  - "brew/.wt-prod/docs/production.md:3, 15"
  - "brew origin/main a559de6: deploy.sh:41, tools/prod-env.sh:7-9, tools/deploy-demo.sh:16"
  - "brand-directions/_tools/deploy-handbook.py:2-18, brand-directions/_tools/deploy-docs.py:8"
  - "memory brew-dns-local, brew-prod-backend, brew-prototype-repo, brew-demo-mode, brand-directions-2026-10-25, brew-handbook, brew-shopify-connector-qa, shopos-feed-any-brand, arata-feed-demo"
---

# DNS and domains

## Answer

Every Brew address lives under joinsquareup.com in Cloudflare, most of them pointing straight at one Google load balancer, and this page lists each record, where it points, and the Mac DNS lesson that turns a false outage into a two-minute check.

## Today

### Records we use

| Address | Points at | Cloudflare mode | Serves | Source |
|---|---|---|---|---|
| feed.joinsquareup.com | A 34.54.65.239, the Google load balancer `squareup-urlmap` | DNS only | Production, `brew-web` behind Cloud Armor | [src: brew/.wt-prod/docs/production.md:15] [src: memory brew-prod-backend] |
| brew.joinsquareup.com | A 34.54.65.239 | DNS only | Staging, `shopos-feed`, host rule `shopos-feed-matcher` | [src: memory brew-prototype-repo] [src: memory brew-dns-local] |
| demo.joinsquareup.com | A 34.54.65.239 | DNS only | Demo, `brew-demo`, host rule `brew-demo-matcher` | [src: memory brew-demo-mode] [src: memory brew-dns-local] |
| docs.joinsquareup.com | CNAME squareup-docs.web.app | DNS only | Shared docs, Firebase Hosting | [src: memory brand-directions-2026-10-25] |
| handbook.joinsquareup.com | Firebase Hosting site `squareup-handbook`, which only rewrites to Cloud Run `handbook-comments`, behind Cloudflare Access | Not yet confirmed | This handbook | [src: brand-directions/_tools/deploy-handbook.py:2-18] [src: memory brew-handbook] |

- The load balancer has its own certificate, so the Brew records skip Cloudflare's proxy; the proxy had added about half a second per request. [src: memory shopos-feed-any-brand]
- Cloudflare's Universal SSL does not cover two-level subdomains such as `v1.arata.joinsquareup.com`; use one level. [src: memory arata-feed-demo]
- DNS changes by script use the Cloudflare token in Secret Manager `CLOUDFLARE_DNS_ONBOARDING_TOKEN`. [src: memory brew-demo-mode]
- production.md says staging's entry is a Cloud Run domain mapping; the 15 and 19 Oct notes say a load balancer host rule. The notes are more detailed; confirm. [src: brew/.wt-prod/docs/production.md:15] [src: memory brew-prototype-repo]

### Where an address is written in code or settings

| Address | Written in | Source |
|---|---|---|
| feed.joinsquareup.com | `PROD_URL`, `PUBLIC_URL` on production; `PROD_URL` on staging | [src: brew/tools/prod-env.sh:7-9] [src: brew/deploy.sh:41] |
| brew.joinsquareup.com | `PUBLIC_URL` on staging; `STAGING_URL`, `SLACK_RELAY_URL` on production | [src: brew/deploy.sh:41] [src: brew/tools/prod-env.sh:9] |
| demo.joinsquareup.com | `PUBLIC_URL` on the demo; `DEMO_URL` on production | [src: brew/tools/deploy-demo.sh:16] [src: brew/tools/prod-env.sh:9] |
| Callback URLs on both sites | Google sign-in, Google Ads and GA4, Meta, Slack consoles | [src: brew/.wt-prod/docs/production.md:73-77] |
| Arata's Shopify own app | redirect `https://brew.joinsquareup.com/shopify/own/callback` | [src: memory brew-shopify-connector-qa] |

### Retired

- arata, arata-v1 and feed-demo records and their services were removed on 15 Oct. [src: memory brew-prototype-repo]
- feed.joinsquareup.com was retired on 15 Oct and came back as production on 25 Oct. [src: memory brew-prototype-repo] [src: memory brew-prod-backend]

### The Mac DNS lesson, 19 Oct

Param saw brew.joinsquareup.com "not working". The site was up; the Mac's router resolver on an IPv6-only network timed out for that one name. [src: memory brew-dns-local]

## Tomorrow

| Item | Version | Tag |
|---|---|---|
| feed.joinsquareup.com as production | v1 | Stays until the name is picked |
| A production domain on the product's own name | v2 | New, waits on the name |
| feed.joinsquareup.com redirecting to the new domain | v2 | Changes |
| Every callback URL listed in one place, checked before a domain move | v1 | New |

## How we do it

### Someone says the site is down

Run these three before calling it an outage. [src: memory brew-dns-local]

```bash
dig +short brew.joinsquareup.com @8.8.8.8
dig +short brew.joinsquareup.com @1.1.1.1
curl -s -o /dev/null -w '%{http_code}\n' --resolve brew.joinsquareup.com:443:34.54.65.239 https://brew.joinsquareup.com/
```

If public DNS answers 34.54.65.239 and the pinned curl says 200, the site is fine. Reconnect Wi-Fi, switch network, or set DNS to 1.1.1.1 or Google DNS64 `2001:4860:4860::6464`.

### Adding a record

1. One level under joinsquareup.com only.
2. For a Cloud Run service: a serverless NEG, a backend, a host rule on `squareup-urlmap`, then an A record to 34.54.65.239, DNS only.
3. Add the new address to every OAuth console that needs a callback.
4. Add the record to the table above.

## Numbers

None; DNS has no metric we track. The proposed uptime check lives in [Monitoring and alerts](/ops-and-infrastructure/monitoring-and-alerts).

## Open

1. **Who owns the Cloudflare account and the joinsquareup.com zone?** No note names it for this zone. Proposal: Param owns it, with Sai as a second admin so a lost login never locks the domain.
2. **When do we move production off feed.joinsquareup.com?** Proposal: when the product name is picked, in one planned change with every callback URL checked from the list above.
