# GitHub Pages のサイトにお問い合わせフォームを追加する

> GitHub Pages ではサーバーコードが動かず、フォームの POST は 405 Not Allowed になります。フォームバックエンドに送信し、プロジェクトサイトのリダイレクトを正しく設定しましょう。

公開日 2026-10-25 · https://ikiform.com/ja/guides/contact-form-static-site/github-pages

GitHub Pages は静的ファイルしか配信しないので、自分のサイトに送信するフォームは `405 Not Allowed` になり、メッセージは失われます。フォームの `action` を Ikiform のエンドポイントにし、`username.github.io` と独自ドメインを **Allowed domains** に追加して、プロジェクトサイトのパスを含むサンクスページにリダイレクトします。リポジトリも Pages の設定も変わらず、公開リポジトリにシークレットが入ることもありません。

## GitHub Pages ならではの違い

GitHub Pages が公開するのは、リポジトリか Actions のワークフローがビルドしたものだけです。Jekyll を使うならビルド時に動き、その結果はファイルになります。リクエストを処理する仕組みがないので、何をコミットしても PHP の `mail()`、Node のスクリプト、Python の CGI フォームは動きません。

失敗はターミナルで確認できます。Pages のサイトのどのページに POST しても、次の結果になります:

`ターミナル`:

```bash
curl -i -X POST -d "message=hello" https://ada.github.io/notebook/contact.html
```

`応答`:

```http
HTTP/2 405
server: Varnish
content-length: 131

<html>
<head><title>405 Not Allowed</title></head>
```

Pages には他の静的ホストと違う点がさらに 4 つあり、どれもお問い合わせフォームに関わります:

| Pages の特徴 | フォームへの影響 |
| --- | --- |
| プロジェクトサイトは `username.github.io/repo/` のようにパスの下に置かれる | `/thanks.html` というサンクスページの URL は、プロジェクトではなくユーザーサイトを指す。どの URL にも `/repo/` の部分が必要 |
| カスタムのレスポンスヘッダーを設定できない | Content-Security-Policy は、ページ内の `<meta>` タグでしか指定できない |
| リポジトリは公開されていることが多い | 中身はすべて公開される。フォーム ID なら問題ないが、シークレット API キーやメールのパスワードは絶対に置かない |
| GitHub は、パスワードやクレジットカード番号の送信など機密性の高い取引に Pages サイトを使うべきではないとしている | お問い合わせフォームはお問い合わせ専用にする。カード情報やアカウントのパスワードを集めない |

図: GitHub Pages が実行するものと、お問い合わせフォームの送信先

1. Pages の公開元のブランチに push します。
2. Jekyll か Actions のワークフローがサイトを 1 回ビルドします。
3. Pages はその結果を、github.io か独自ドメインで静的ファイルとして配信します。
4. 訪問者がお問い合わせフォームを送信します。action が自分のサイトを指していると、Pages は 405 Not Allowed を返します。
5. action を Ikiform のエンドポイントにすれば、Ikiform がメッセージを保存してメールで通知します。
6. Ikiform はブラウザーをサンクスページにリダイレクトし、Pages はそれを他のファイルと同じように配信します。

コードが GitHub で実行されるのは push ごとに 1 回だけです。訪問者が送信を押したときに動くあなたのコードはないので、送信は github.io の外へ出す必要があります。

## フォーム

手書きのサイトなら、`index.html` の隣に `contact.html` を追加します。この例は `ada.github.io/notebook` のプロジェクトサイト用なので、リダイレクト先に `/notebook/` が含まれます:

`contact.html`:

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; form-action 'self' https://ikiform.com; connect-src 'self' https://ikiform.com"
    />
    <title>Contact</title>
  </head>
  <body>
    <h1>Get in touch</h1>
    <form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
      <label for="name">Name</label>
      <input id="name" name="name" autocomplete="name" required />

      <label for="email">Email</label>
      <input id="email" name="email" type="email" autocomplete="email" required />

      <label for="about">What is it about?</label>
      <select id="about" name="about">
        <option value="question">A question about the project</option>
        <option value="hire">Work together</option>
        <option value="other">Something else</option>
      </select>

      <label for="message">Message</label>
      <textarea id="message" name="message" rows="6" minlength="10" required></textarea>

      <input type="hidden" name="page" value="docs-home" />
      <input type="hidden" name="_redirect" value="https://ada.github.io/notebook/thanks.html" />
      <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
      <button type="submit">Send</button>
    </form>
  </body>
</html>
```

- `<meta>` の Content-Security-Policy は任意です。すでにあるなら残し、`form-action` と `connect-src` に `https://ikiform.com` が含まれていることを確認してください。Pages は代わりにヘッダーを送れません。
- `about` のセレクトボックスで、メッセージを開く前に問い合わせの理由がわかります。選択肢は、実際に届く問い合わせの内容に合わせて変えてください。
- hidden の `page` 入力欄は、フォームが置かれていたページを記録します。同じフォームを複数のドキュメントページに置くときに便利です。
- フィールド名は `email` のままにしてください。通知メールはこれを reply-to アドレスとして使います。

同じ HTML を複数のパスにデプロイする場合や、最終的なパスがわからない場合は、ページ自身のアドレスからブラウザーでリダイレクト先を組み立てます。フォームの後にこれを置きます:

`contact.html`:

```html
<script>
  document.querySelectorAll('input[name="_redirect"]').forEach((input) => {
    input.value = new URL("thanks.html", document.baseURI).href;
  });
</script>
```

Jekyll を使っていますか？それなら URL をハードコードする必要はありません。[Jekyll ガイド](https://ikiform.com/ja/docs/guides/jekyll.md)に、`absolute_url` で URL を組み立てる include があり、プロジェクトサイトでは `baseurl` を付けてくれます。Astro、Vite、Hugo を Actions のワークフローでビルドしているなら、フォームのアセットが読み込まれるようにフレームワークのベースパスを `/repo/` に設定し、フォーム自体は [Hugo](https://ikiform.com/ja/docs/guides/hugo.md) や各フレームワークのガイドに従ってください。

## github.io での許可ドメイン

自分のユーザー名で `ada.github.io` を追加します。プロジェクトサイトは同じホストを共有するので、これでユーザーサイトとすべてのプロジェクトサイトをカバーできます。独自ドメインを使っているならそれも追加します。`example.com` は `www.example.com` もカバーします。

`github.io` だけを追加してはいけません。他人のサイトにあるあなたのフォームのコピーも含め、すべての Pages サイトが一致してしまいます。許可ドメインを設定していれば `https://ada.github.io/notebook/thanks.html` への `_redirect` に従いますが、設定していなければ Ikiform はそれを無視し、自身がホストするサンクスページを表示します。

> リポジトリの Pages 設定で **Enforce HTTPS** をオンにします。Ikiform が従うのは `https:` で始まる `_redirect` の値だけで、証明書がまだない独自ドメインは `http:` でページを配信します。

## mailto: リンクを置き換える

多くの Pages サイトは、フッターの `mailto:` リンクから始まります。これをフォームに置き換えれば、新たなスクレイパーにページからアドレスを読み取られなくなり、メールアプリを設定していない訪問者も連絡できるようになります。削除する前に知っておくべきことが 2 つあります:

- アドレスはリポジトリの履歴や、古いページのフォークやアーカイブに残ります。フォームが役立つのはこれからの分で、何年も公開されていたアドレスが非公開に戻るわけではありません。
- 返信は自分の受信トレイから行います。通知メールは送信者を reply-to アドレスに設定するので、**Reply** を押せば、`mailto:` リンクと同じことを逆側から行えます。

Ikiform は訪問者にメールを送らないので、いつごろ返事が届くかをサンクスページに書いておきましょう。メールで返しきれないほどメッセージが届くなら、Webhook で 1 件ずつ [Slack](https://ikiform.com/blog/form-submissions-to-slack.md) や [Discord](https://ikiform.com/blog/form-submissions-to-discord.md) に送ることもできます。

## 動作を確認する

これは公開中の `github.io` のアドレスで実行してください。Pages にはプレビューのデプロイがないので、まずローカルサーバーでテストします。

1. **Allowed domains** に `localhost` と `username.github.io`、独自ドメインがあればそれも追加します。
2. `contact.html` と `thanks.html` をコミットし、リポジトリの **Actions** タブで Pages のデプロイが終わるのを待ってから、公開中のページを開きます。
3. フォームを送信します。アドレスバーにプロジェクトのパスが入った、自分の `thanks.html` に移動するはずです。
4. ダッシュボードで **Submissions** を開きます。送ったすべてのフィールドを含む新しい送信データがあります。
5. 通知の受信者それぞれの受信トレイを確認します。各自にフィールド入りのメールが届き、フォームに `email` フィールドがあれば **Reply** の宛先は送信者になります。
6. 何も届かない場合は、ダッシュボードのステータスフィルターを **Spam** に切り替えてください。スパムにも本物の送信と同じ成功の応答が返ります。

## ハマりどころ

| 問題 | 対処 |
| --- | --- |
| 送信を押すと `405 Not Allowed` になる | デプロイされたフォームがまだ自分のサイトに送信しています。github.io でページのソースを表示して `action` を確認してください。古いキャッシュのビルドが数分間残っていることもあります。 |
| 自分のページではなく Ikiform のサンクスページが表示される | `_redirect` の値にリポジトリのパスがない、`http:` になっている、またはフォームに許可ドメインがありません。`username.github.io` を追加し、完全な `https:` の URL を使ってください。 |
| `403 origin_not_allowed` が返るか、すべての送信がスパムになる | ページのドメインがフォームの **Allowed domains** にありません。ドメインと、ローカルのテスト用に `localhost` を追加してください。登録済みドメインのサブドメインは許可されます。 |
| ローカルでは送信できるのに、github.io ではコンソールに CSP エラーが出る | レイアウトの `<meta>` の Content-Security-Policy で、`form-action` か `connect-src` に `https://ikiform.com` がありません。 |

## よくある質問

### GitHub Pages でフォームの送信を処理できますか？

できません。GitHub Pages は静的ファイルを配信するだけで、訪問者がフォームを送信してもコードは実行されないため、Pages の URL への POST は 405 Not Allowed になります。代わりにフォームの action をフォームバックエンドに向けてください。

### フォームのエンドポイントを公開リポジトリにコミットしても安全ですか？

はい。フォーム ID はどのみち公開される HTML に含まれます。許可ドメインとスパムチェックでフォームを守り、シークレット API キーは絶対にコミットしないでください。静的サイトにはそれを安全に保管する場所がありません。

### プロジェクトサイトでサンクスページへのリダイレクトが違うページに行くのはなぜですか？

/thanks.html のようなパスは、プロジェクトではなく username.github.io のルートを指します。リポジトリのパスを含む完全な URL を使うか、ブラウザーで document.baseURI から組み立ててください。

### GitHub Pages に独自ドメインを追加した後もフォームは動きますか？

はい。ページをどのドメインで配信しても、フォームは Ikiform に送信されます。Allowed domains に username.github.io と並べて独自ドメインを追加し、HTTPS を強制したら _redirect の値も独自ドメインに更新してください。

### Ikiform は無料ですか？

いいえ、無料プランはありません。テストは無料で、支払いの前に localhost から月 50 件のテスト送信ができます。本番運用するには、月 $6 で 500 件からの Pro を選ぶか、1 回払いで 10,000 件 $49 または 50,000 件 $149 を購入できます。クレジットに有効期限はありません。

## その他のガイド

- [静的サイトのお問い合わせフォーム](https://ikiform.com/ja/guides/contact-form-static-site.md): サーバーなしで静的サイトに動くお問い合わせフォームを追加します。POST の送り先、スパム、メールでの返信、各ホストとフレームワーク向けのコードまで。
- [Netlify](https://ikiform.com/ja/guides/contact-form-static-site/netlify.md): Netlify Forms を使わずに、Netlify のサイトでお問い合わせフォームを運用します。ビルド時の検出なし、React からの JSON 送信、デプロイプレビュー用の別フォーム。
- [Cloudflare Pages](https://ikiform.com/ja/guides/contact-form-static-site/cloudflare-pages.md): Function を書かずに Cloudflare Pages にお問い合わせフォームを追加します。フォームバックエンドに送信し、_headers でヘッダーを設定し、自分の Turnstile キーを使います。
- [ポートフォリオサイト](https://ikiform.com/ja/guides/contact-form-static-site/portfolio-website.md): 初回の打ち合わせで聞くことを尋ねるポートフォリオのお問い合わせフォーム。案件、予算、時期、リンクを、サーバーなしで受け取り、受信トレイから返信できます。
- [Vercel](https://ikiform.com/ja/guides/contact-form-static-site/vercel.md): Vercel の静的ページはフォームの POST に 405 Method Not Allowed を返します。その理由と、代わりにバックエンドへフォームを送る方法を説明します。
- [Amazon S3](https://ikiform.com/ja/guides/contact-form-static-site/aws-s3.md): S3 のウェブサイトエンドポイントは平文 HTTP の GET と HEAD しか受け付けません。お問い合わせフォームはフォームバックエンドに送信し、リダイレクトは CloudFront で正しく扱います。
