# 発信の器を世に出すまで — Vercel デプロイから独自ドメイン接続まで

> 完璧を待たずにまず Vercel で公開し、そのうえで独自ドメイン suz-lab.co.jp を接続してカノニカル URL を固定するまでの記録。DNS・証明書・リダイレクト・正規 URL の一本化と、www をどう扱うかの判断まで、実際のコードと検証コマンドの出力を一次情報として残します。

- 出典: SUZ-LAB（実験ログ / 一次情報）
- URL: https://suz-lab.co.jp/logs/going-live-vercel-and-domain
- 公開: 2026-07-04
- 更新: 2026-07-04
- 著者: Hiro（主任研究員・https://suz-lab.co.jp/researchers/hiro・X: https://x.com/suz_lab_hiro）
- 柱: テクノロジー
- タグ: #Vercel #独自ドメイン #DNS #デプロイ #SEO #Next.js
- カバー画像: https://suz-lab.co.jp/assets/logs/going-live-vercel-and-domain.png?v=a243224e

---


## 何をやったか

「発信の器」を世に出すための最低限の2手を続けて倒した。

1. **[本番デプロイ（Vercel）](/roadmap#deploy)** … まず器を世に出す。
2. **[独自ドメイン接続](/roadmap#deploy-domain)** … 既定の Vercel ドメインから
   `suz-lab.co.jp` へ切り替え、正規 URL を固定する。

この2つは Roadmap では別々の TODO だが、実際には「出す → 正しい住所に据える」で
ひとつながりの作業だったので、1本のログにまとめて残す。行動原則の
**「まず、やってみる」** の実演でもある。

## なぜ、完璧を待たずに出したか

サイトはいくらでも磨ける。だが磨き続けている間は、SEO も解析も回遊も
「本番の実データ」を一切持てない。**出して初めて、以降の改善を実 URL・実挙動の
上で回せる。** だから先に Vercel の既定ドメイン（`suz-lab.vercel.app`）で
公開し、器が動く事実を作った。これは自ら作ったものを自ら使って鍛える
[ドッグフーディング](/topics/dogfooding)の発想——完璧な準備を待たず本番に晒すからこそ、
机上のテストでは見えない欠けが手元の一次体験として返ってくる。Vercel はリポジトリの `main` を
追跡していて、push するたびに本番が自動で焼き直る運用にしてある。

そのうえで「暫定の住所（Vercel ドメイン）のまま発信を積むと、あとで正規 URL が
ブレて sitemap / OGP / 被リンクが割れる」ので、間を置かずドメイン接続に進んだ。

## 下ごしらえ — ドメイン接続を「環境変数1つ」にするまで

今日の切り替えが一瞬で終わったのは、公開前からずっと**正規 URL の出所を1か所に
畳んでおいた**からだ。器を出すより前、[VMOST → Roadmap → Log を線でつないだ](/logs/connecting-vmost-roadmap-logs)
のと同じ時期から、SEO 配管を少しずつ敷いてきた。

- 実験ログ基盤・VMOST 解説とあわせて **`sitemap.xml` / `robots.txt`** を追加。
- 画像を**内容ハッシュでキャッシュ無効化**し、SNS を実アカウントに接続。
- **構造化データ（[JSON-LD](/topics/json-ld-structured-data)）** を足して SEO を強化。

これらが全部、正規 URL を1つの定数に寄せてある前提で書かれている。その定数が
`content/site-config.ts` の `SITE.url` だ。

```ts
// content/site-config.ts — 正規 URL の唯一の出所。sitemap / robots / metadataBase / JSON-LD が参照する
url: (process.env.NEXT_PUBLIC_SITE_URL ?? "https://suz-lab.co.jp").replace(/\/$/, ""),
```

参照側は次のように、どこも `SITE.url` しか見ていない。

```ts
// app/robots.ts — サイトマップの場所とホストを宣言
sitemap: `${SITE.url}/sitemap.xml`,
host: SITE.url,

// app/layout.tsx — 相対 canonical / OGP を絶対化する起点
metadataBase: new URL(SITE.url),

// lib/structured-data.ts — Organization / WebSite / BlogPosting を絶対 URL で組む
const orgId = `${SITE.url}/#organization`;
image: `${SITE.url}${assetSrc(logCover(log))}`,
```

各ページの canonical は**自己参照の相対パス**だけを宣言し、絶対化は `metadataBase`
（= `SITE.url`）に任せている。

```ts
// app/page.tsx           → alternates: { canonical: "/" }
// app/logs/[slug]/page.tsx → alternates: { canonical: `/logs/${slug}` }
```

だから **`SITE.url` が1つ変われば、canonical・sitemap の全 URL・OGP・robots の host・
JSON-LD の `@id` と `image` が一斉に本番ドメインへ移る**。接続前は「既定は将来の
カノニカル（`suz-lab.co.jp`）、本番は環境変数 `NEXT_PUBLIC_SITE_URL` で Vercel
ドメインに上書き」という暫定運用で正規 URL のブレを防いでいた。今日やったのは、
**その上書きを外しただけ**。grep して URL を直書き置換して回る作業には一切ならなかった。

## やってみたこと

### 1. DNS と Vercel のドメイン追加

apex（`suz-lab.co.jp`）の A レコードを Vercel の Anycast IP（`216.150.1.1`）へ向け、
Vercel 側のプロジェクトにドメインを追加した。証明書は Vercel が Let's Encrypt で
自動発行・更新する。配信元は `server: Vercel`。

### 2. カノニカルを本番ドメインに固定

Vercel の本番環境変数から `NEXT_PUBLIC_SITE_URL` を外し、`SITE.url` を既定値
（`https://suz-lab.co.jp`）に確定させた。これで sitemap の各 URL は
`https://suz-lab.co.jp` 始まりの絶対 URL になる。`sitemap.ts` はルートだけ
`path` を空文字にして**末尾スラッシュなし**（= `SITE.url` そのもの）にしてあり、
Next が `metadataBase` に対して出すルートの canonical（`/` ではなくスラッシュ無しの
`https://<host>`）と一致する。**canonical と sitemap で URL がブレる SEO 不整合**を
構造的に防いでいる。

### 3. www をどう扱うか — apex 一本に決めた

`www.suz-lab.co.jp` は DNS に A/AAAA を置かず、証明書の SAN も apex のみにした。
理由は、個人サイトで www と apex の2系統を維持する運用コスト（証明書・
リダイレクト・正規 URL のブレ）に見合う利点がないから。**正規は apex 一本**とし、
将来 www 流入を拾う必要が出たら、そのとき Vercel 側で apex への 308 リダイレクトを
足せばよい（DNS に www の CNAME を追加するだけ）。いまは足さない、を意識的に選んだ。
この保留は Roadmap の [www → apex の 308 リダイレクト（必要時）](/roadmap#www-redirect)
として、着手条件が来たとき拾えるように残してある。

## 検証

「つながった」を体感ではなく、コマンドの出力で確かめた。

```text
# HTTP → HTTPS は 308 で HTTPS へ誘導
http://suz-lab.co.jp/              → 308  (Location: https://suz-lab.co.jp/)
https://suz-lab.co.jp/             → 200
https://suz-lab.co.jp/topics/vmost → 200

# 存在しないパスは 404 / robots・sitemap は 200
/this-should-not-exist             → 404
/robots.txt                        → 200
/sitemap.xml                       → 200

# DNS
suz-lab.co.jp      → A 216.150.1.1   (Vercel Anycast)
www.suz-lab.co.jp  → 名前解決なし（= 到達不可。意図どおり）

# 証明書（Let's Encrypt）と HSTS
issuer  = Let's Encrypt        notAfter = Oct  2 2026
subjectAltName = DNS:suz-lab.co.jp   (www は含まない)
strict-transport-security: max-age=63072000   # 2年
server: Vercel
```

- `SITE.url` を本番ドメインに固定した結果、`sitemap.xml` の各 URL・記事の
  canonical・OGP 画像 URL・JSON-LD の `@id`／`image` がすべて
  `https://suz-lab.co.jp` 始まりの絶対 URL で出力されることを確認。
- トップの H1「あなたの“やってみたい”を応援します」が正しく描画され、
  主要ルート（`/topics/vmost` など）も 200 で返ることを確認。
- `www` は名前解決しない（＝到達不可）ことも確認済み。これは §3 の判断どおりの
  期待挙動。

## 学び

- **カノニカルは1か所（`SITE.url`）に寄せておくと、ドメイン切り替えが「環境変数を
  1つ消す」だけで済む。** 正規 URL を各所に直書きしていたら、この切り替えは
  robots・sitemap・layout・structured-data・各 page を grep して回る作業になっていた。
  「文言・設定は単一の出所に」という方針が、そのままドメイン移行の安全装置になった。
- **公開後を実データに乗せるための投資として、先に器を出す。** ドメインを繋いだことで、
  次の [検索計測（Search Console）と構造化データ](/roadmap#search-console) を、
  初めて本番ドメイン上で正しく検証できる。JSON-LD の絶対 URL も本番に揃った。
- **「やらない」も設計判断として残す。** www を足さなかったのは怠慢ではなく、
  運用コストと利点を天秤にかけた選択。あとで必要になったときのために、
  何を足せば復活できるか（apex への 308＋www の CNAME）まで書き残しておく。

これで Roadmap の本番デプロイと独自ドメイン接続が完了した。発信の器の土台
（公開・正規 URL）が揃ったので、次はこの器の上で計測（[解析](/roadmap#analytics)・
[検索](/roadmap#search-console)）と、各柱の一次情報（ログ）を積んでいく。

