# はじめかた

> Deploy to Cloudflare ボタンでサイトを用意し、最初の管理者を作るまでの手順です。

この手順で、スターターキットの private なコピーを作り、シークレットを入力し、独自ドメインを追加し、[Turnstile](https://goodnight-web.dev/ja/docs/glossary.md#turnstile) を設定して、最初の管理者を作ります。

## 必要なもの

- Cloudflare のアカウント。小さなWebサイトなら無料プランで足ります。
- GitHub のアカウント。
- 独自ドメインで公開するなら、そのドメイン名。[Passkey](https://goodnight-web.dev/ja/docs/glossary.md#passkey) を登録する前に決めてください（[ドメインを追加する](#custom-domain)を参照）。

<Steps>

<Step>

### Deploy to Cloudflare ボタンを押す

ボタンは、スターターキットの README にあります。押すと Cloudflare の設定フォームが開き、GitHub との連携を求められます。同じフォームで次の手順のシークレットも入力するので、入力してから先へ進んでください。そのあとは、Cloudflare が次の作業を自動で進めます（[Cloudflare: Deploy buttons](https://developers.cloudflare.com/workers/platform/deploy-buttons/)）。

- starter を、あなたのアカウントの新しいリポジトリにコピーする
- [D1](https://goodnight-web.dev/ja/docs/glossary.md#d1) データベースを作る
- [Workers Builds](https://goodnight-web.dev/ja/docs/glossary.md#workers-builds) で [Worker](https://goodnight-web.dev/ja/docs/glossary.md#workers) をビルドしてデプロイする

設定フォームでは **「Create private Git repository」にチェックを入れてください**。リポジトリは private にする必要があります。理由は[配布と更新のしくみ](https://goodnight-web.dev/ja/docs/distribution.md#private-repository)にあります。

public で作られてしまったら、GitHub で **Settings > General > Danger Zone > Change visibility** を開き、private を選びます。private にするまで、starter の公開範囲チェックのワークフローは push のたびに失敗します。

</Step>

<Step>

### 設定フォームに入力する

前の手順と同じ設定フォームで、次の値を入力します。必須の値は `APP_SECRET` と `ADMIN_EMAILS` の 2 つです。シークレットは、Worker に保存する秘密の値です。後から Cloudflare のダッシュボードで、Worker の設定の変数とシークレットから設定や変更もできます。

| 名前                 | 必須か                     | 何のための値か                                                                                                                                                                                                              | 作り方                                                                                       |
| -------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `APP_SECRET`         | 必須                       | 最初の管理者を作るときに、ご自身がサイトの持ち主であることを確かめます。管理画面のログインセッションに署名する鍵と、IP アドレスをハッシュにする鍵もこの値から作るため、セットアップ後も使い続けます。                       | 32 文字以上のランダムな文字列。コマンドは下にあります。                                      |
| `ADMIN_EMAILS`       | 必須                       | 管理者になれる、なり続けられるメールアドレス。複数ならカンマで区切ります。最初の Passkey を登録するとセットアップが閉じるため、今は管理者を 1 人しか作れません（[Passkey でのログイン](https://goodnight-web.dev/ja/docs/how-it-works/passkeys.md)）。 | ご自身のメールアドレスを入れます。                                                           |
| `TURNSTILE_SECRET`   | お問い合わせフォームに必要 | Turnstile のシークレットキー。                                                                                                                                                                                              | Cloudflare ダッシュボードで Turnstile のウィジェットを作り、シークレットキーをコピーします。 |
| `TURNSTILE_SITE_KEY` | お問い合わせフォームに必要 | Turnstile のサイトキー。公開される値で、秘密ではありません。                                                                                                                                                                | シークレットキーと同じウィジェットで作ります。                                               |
| `SLACK_WEBHOOK_URL`  | 任意                       | 新しい問い合わせの通知を Slack に送ります。通知に名前やフォームの内容は入りません。                                                                                                                                         | Slack で Incoming Webhook を作ります。                                                       |
| Project name         | フォームの項目             | Worker の名前です。`workers.dev` のアドレスの一部になります。                                                                                                                                                               | 短い小文字の名前を付けます。                                                                 |
| D1 データベース      | フォームの項目             | 問い合わせと、Passkey を含む管理者アカウントを保存します。                                                                                                                                                                  | フォームが作ります。選ぶのは名前だけです。テーブルは `deploy` スクリプトが作ります。         |

次の表は、各項目をいつ入れるか、失くしたとき・消したときに何が起きるかをまとめたものです。

| 名前                 | 入れる時期                                                                                                                                                      | 失くしたとき・消したときの影響                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `APP_SECRET`         | フォームで入れます。最初の管理者を作るときに、`/admin` でもう一度入力します。                                                                                   | セットアップ後も削除や変更をしないでください。未設定または短すぎる: セットアップ、ログイン、管理画面、お問い合わせフォームが 503 を返します。変えた場合: すべての管理者がログアウトされ、Passkey でログインし直します。新しい IP アドレスのハッシュも古いものと一致しなくなります。Cloudflare は保存したシークレットを二度と表示しないので、パスワードマネージャーなどに控えを保管してください。[失くした Passkey を復旧する](https://goodnight-web.dev/ja/docs/how-it-works/passkey-recovery.md)ときにも、この値を使います。 |
| `ADMIN_EMAILS`       | フォームで入れます。                                                                                                                                            | Worker はリクエストのたびに読みます。外したアドレスは、次のリクエストで 403 になります。リストが空の間は、セットアップが閉じたままです。                                                                                                                                                                                                                                                                                                                                                           |
| `TURNSTILE_SECRET`   | 後でも構いません。今は空のままにして、[Turnstile を設定する](https://goodnight-web.dev/ja/docs/setup/turnstile.md)で入れます。                                                             | 未設定: お問い合わせフォームは「まだ利用できません」と表示し、送信を拒否します。保存済みの問い合わせは残ります。                                                                                                                                                                                                                                                                                                                                                                                   |
| `TURNSTILE_SITE_KEY` | フォームでは空のままにします。ウィジェットを作ったら、`wrangler.jsonc` に書いてコミットします。ダッシュボードだけで設定した値は、次のデプロイで置き換わります。 | 空: `TURNSTILE_SECRET` が未設定のときと同じです。                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `SLACK_WEBHOOK_URL`  | いつでも構いません。                                                                                                                                            | 未設定: 通知が届かないだけです。問い合わせは保存され、管理画面の一覧に出ます。                                                                                                                                                                                                                                                                                                                                                                                                                     |
| Project name         | フォームで入れます。                                                                                                                                            | あとで `wrangler.jsonc` の `name` を変えると、次のデプロイで別の Worker ができます。古い Worker のシークレットとドメインは引き継がれません。                                                                                                                                                                                                                                                                                                                                                       |
| D1 データベース      | フォームで入れます。                                                                                                                                            | データベースを削除すると、すべての問い合わせと管理者アカウントが消えます。空の新しいデータベースでは、セットアップと Passkey の登録をやり直します。                                                                                                                                                                                                                                                                                                                                                |

設定フォームは、これらの値を作りません。32 文字より短い値は、設定していないのと同じ扱いです。その値を使う機能は止まります。同じ文字や短い文字列の繰り返しのように、明らかにランダムでない値も同じ扱いで、セットアップの画面に置き換えるべきシークレットの名前が表示されます。

手元のパソコンのターミナルで次のコマンドを実行すると、条件を満たす 44 文字のランダムな文字列を作れます。

```sh
openssl rand -base64 32
```

1 つの値を 2 つのシークレットに使い回さないでください。シークレットはリポジトリにコミットしないでください。

Worker は、Web Crypto の [HKDF](https://goodnight-web.dev/ja/docs/glossary.md#hkdf) を使って `APP_SECRET` から 2 つの鍵を作ります。1 つは管理画面のログインセッションの署名に、もう 1 つは IP アドレスのハッシュに使います。用途ごとに決まったラベルを使うので、一方の鍵がわかっても `APP_SECRET` やもう一方の鍵はわかりません。鍵をご自身で設定したい場合は、[鍵を個別に設定する](#separate-keys)を参照してください。

</Step>

<Step>

### 最初のデプロイを確かめる

Workers Builds に表示されるアドレスでサイトを開き、ページが表示されることを確かめます。

データベースのテーブルもできています。`deploy` スクリプトが、デプロイの前に D1 のマイグレーションを適用するからです。

</Step>

<Step>

### Passkey を登録する前にドメインを追加する [#custom-domain]

Passkey は、登録したときのドメインでしか使えません。`workers.dev` のアドレスで登録した Passkey は、管理画面を独自ドメインに移すと使えなくなります。

セットアップは最初の Passkey を登録した時点で閉じるので、新しいドメインで登録し直すこともできません。セットアップを開き直すには、データベースを手で書き換える必要があります（[Passkey が使えないとき、失くしたとき](https://goodnight-web.dev/ja/docs/how-it-works/passkey-recovery.md)）。そのため、最初の管理者を作る前に独自ドメインを追加してください。

1. Cloudflare のダッシュボードで、Worker にカスタムドメインを追加します。
2. `wrangler.jsonc` の `"workers_dev": true` を `"workers_dev": false` に変えて、コミットします。その後のデプロイで `workers.dev` のアドレスが無効になり、管理画面には独自ドメインからしか入れなくなります。ダッシュボードの切り替えは使わないでください。デプロイのたびに `wrangler.jsonc` が適用され、`workers.dev` がまた有効になります。プレビュー URL は starter で最初から無効です（`"preview_urls": false`）。

</Step>

<Step>

### Turnstile を設定する

Turnstile のウィジェットを作ります。ウィジェットのホスト名には、サイトを公開するドメインを入れます。サイトキーは `wrangler.jsonc` の `TURNSTILE_SITE_KEY` に、シークレットキーはシークレット `TURNSTILE_SECRET` に入れます。

設定するまで、問い合わせフォームは「お問い合わせフォームは準備中です」と表示し、送信を受け付けません。手順は [Turnstile を設定する](https://goodnight-web.dev/ja/docs/setup/turnstile.md)を見てください。

</Step>

<Step>

### 最初の管理者を作る

管理画面は `https://` でだけ動きます。

1. `https://<独自ドメイン>/admin/` を開きます。管理者がまだいないので、セットアップ画面（`/admin/setup`）が開きます。
2. **セットアップトークン** に `APP_SECRET` の値を、**メールアドレス** に `ADMIN_EMAILS` に入れたアドレスを入力し、**次へ** を選びます。
3. **Passkeyを登録** を選び、ブラウザやパスワード管理アプリで Passkey を作ります。保存先は、端末の間で同期されるもの（iCloud キーチェーン、Google パスワードマネージャー、パスワード管理アプリなど）を選んでください。2 つ目の Passkey を追加する画面は、まだありません（[Passkey でのログイン](https://goodnight-web.dev/ja/docs/how-it-works/passkeys.md)）。お使いのブラウザやパソコンで Passkey を保存できないときや、失くしたときは、[Passkey が使えないとき、失くしたとき](https://goodnight-web.dev/ja/docs/how-it-works/passkey-recovery.md)を見てください。

<AdminScreen
  name='setup'
  alt='セットアップトークンとメールアドレスを入力した、最初の管理者の登録画面'
  caption='セットアップの 1 段階目。次の段階で Passkey を登録します。'
/>

最初の Passkey を登録するとセットアップは完了し、セットアップ画面はそれ以降使えなくなります。シークレットの `APP_SECRET` は残してください。サイトはログインと IP アドレスのハッシュにこの値を使い続けます。`SETUP_TOKEN` を設定していた場合（[鍵を個別に設定する](#separate-keys)）は、ここで削除します。決まりは[最初の管理者の作成](https://goodnight-web.dev/ja/docs/how-it-works/first-admin.md)にあります。

</Step>

<Step>

### 任意: 管理画面の前に Cloudflare Access を置く

Cloudflare Access で、ログインをもう 1 段増やせます。たとえば、メールで届くワンタイムコードです。50 ユーザーまで無料です。

推奨しますが、必須ではありません。Access があってもなくても、管理画面には必ず Passkey でのログインが必要です。

Access のアプリケーションは、次のパスに設定します。

- `/admin`、`/admin/*`
- `/api/admin/*`
- `/api/setup`
- `/api/auth/*`

`/api/contact` は公開したままにしてください。訪問者は問い合わせフォームからここに送信します。

Worker にも Access のトークンを確かめさせるには、変数を 2 つ追加します。

- `ACCESS_AUD`: アプリケーションの **Application Audience (AUD) Tag**
- `ACCESS_TEAM_DOMAIN`: たとえば `your-team.cloudflareaccess.com`

2 つは両方設定するか、両方とも設定しないでください。片方だけだと、管理用のパスは 503 を返します。詳しくは[セキュリティモデル](https://goodnight-web.dev/ja/docs/security.md#cloudflare-access)を見てください。

</Step>

<Step>

### サイトを編集する

サイトには日本語と英語のページがあります。両方を編集します。

- 会社の情報とテーマの 3 色: `site.config.ts`
- ページ: `src/pages`
- 記事: `src/content`

問い合わせフォームの項目はコードにはありません。管理画面で変えます（[お問い合わせフォームの項目を変える](https://goodnight-web.dev/ja/docs/contact-form.md)）。

プライバシーポリシーの雛形は、公開する前に専門家に確認してもらってください。雛形の内容は[プライバシーについて](https://goodnight-web.dev/ja/docs/privacy.md)にまとめています。

</Step>

</Steps>

## 鍵を個別に設定する [#separate-keys]

通常は `APP_SECRET` だけで足ります。鍵を 1 つずつ管理したい場合は、次のシークレットを Cloudflare のダッシュボードか `npx wrangler secret put` で設定することもできます。Deploy to Cloudflare の設定フォームでは入力を求められません。

| 名前                 | 置き換えるもの                                                                                                               |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `SETUP_TOKEN`        | セットアップ画面で入力する値。設定すると、セットアップ画面では `APP_SECRET` を受け付けません。セットアップ後は削除できます。 |
| `BETTER_AUTH_SECRET` | 管理画面のログインセッションに署名する鍵。                                                                                   |
| `IP_HASH_SECRET`     | IP アドレスをハッシュにする鍵。                                                                                              |

どれも 32 文字以上のランダムな文字列にしてください。設定した値は、`APP_SECRET` から作る値より優先されます。短すぎる値を設定した場合は `APP_SECRET` に切り替わらず、その値を使う機能が止まります。この 3 つをすでに設定しているサイトは、これまでどおり動きます。

運用中のサイトで `BETTER_AUTH_SECRET` や `IP_HASH_SECRET` を追加または削除すると、その鍵が変わります。影響は `APP_SECRET` を変えたときと同じです。

## Deploy ボタンを使わない場合

`npm create cloudflare`（C3）でもプロジェクトを作れます。C3 が作るのは手元のプロジェクトだけです。GitHub のリポジトリはご自身で作るので、**private で作ってください**。
