Help us understand the problem. What is going on with this article?

Firebaseのrobots.txtをドメイン単位で振り分けてみる

免責

  • Sparkプランの上でやったことなので、上位プランならもうちょっとスマートな方法があったかもしれません
  • firebase.jsonの設定次第ではもっとスマートな方法があったかもしれません
  • やったことのログがメインとなります

何をやったか

Firebaseで運用しているWebサイトのrobots.txtを、Firebase HostingではなくCloud Functionsを使って、ドメインごとに別の内容を配信するようにしました。

動機

自サイトをFirebaseで運用しています。 静的コンテンツの配信ならFirebase Hostingが一番楽ですが、ここを利用すると最初に次のドメインが割り当てられます。

  • {PROJECT_ID}.web.app
  • {PROJECT_ID}.firebaseapp.com

カスタムドメインを使いたい場合も割と簡単で、Firebaseのコンソール上で指示に従ってドメインを登録すれば割とあっさり運用可能になります。便利ですね。
ただ、ちょっと困ったことがあって、デフォルトのドメインを無効化出来ないっぽいです。1

すると、こんな事件が起きます。

スクリーンショット 2019-12-03 18.54.25.png

デフォルトドメインもクロールされてる...!?

動作確認込みでデフォルトドメインも使ってたとは思うのですが、これは何かカッコ悪い気がします。
というわけで、

  • カスタムドメインでは、サイトマップなどの情報を提供できるrobots.txtを配信
  • デフォルトドメインでは、せめてbot等によるクロールをしないでもらうためのrobots.txtを配信

という対応を取ることにしました。

Firebase Hostingfirebase.jsonではダメなのか?

とりあえず、現時点では以下のような理由で「なんかダメっぽい」と仮置きしています。

ホスティング環境が分断できてない

カスタムドメインもデフォルトドメインも同じホスティングコンテンツを参照するようになってます。
そのため、配置できるrobots.txtは1個だけという判断をしています。
マルチサイト?結局ドメインが増えちゃうので問題解決にならないんじゃないかなと思ってます 2

firebase.jsonは?

firebase.jsonはリクエストに対する振る舞いが結構柔軟なのですが、ドメインによる振る舞い分岐を見つけられていません。
今のところは、多分出来ないんじゃないかなという判断をしてます。

Cloud Functionsで賄う

というわけで、苦肉の策として「/robots.txtだけはCloud Functionsで配信する」という方針を取ることにしました。

実コード

index.ts
import * as functions from 'firebase-functions';

const robotsAllow = `
sitemap: https://example.com/sitemap.xml
`

const robotsDisallow = `
User-agent : *
Disallow : /
`

export const ROBOTS_TXT = functions.https.onRequest((req, res) => {
  const host = req.header('X-Forwarded-Host');
  const robotsTxt = host === 'example.com' ? robotsAllow : robotsDisallow;
  res.type('txt')
    .set('Cache-Control', 'public, max-age=7200, s-maxage=3600')
    .send(robotsTxt.trim())
    .end();
});

やったことの分割整理

複数のrobots.txtを用意する

ファイルに持たさたりするなど、いくつかパターンが有りましたが、ワンソースで雑に解決したかったので、
robotsAllowにカスタムドメイン向けのテキスト」「robotsDisallowにデフォルトドメイン向けのテキスト」と、
変数で管理するようにしました。

アクセスしてきたドメイン名でrobotsTxtを決定

Cloud FunctionのHTTPトリガー処理はリクエストヘッダーとしてX-Forwarded-Hostを受け取ります。
この中身がまさに「アクセスしてきたドメインが何か」を持っているため、この中身をベースに「どちらのrobots.txtを配信するか」を決定します。

レスポンスする

resオブジェクトを使って、粛々と中身をレスポンス。追加で次のことをしています。

  • MIMEタイプを変えるために、type() を呼び出し 3
  • 頻繁に関数を呼び出しされるのもあれなので、とりあえずCache-Controlで多少はキャッシュしてもらう
  • robotsTxtの中身は先頭と末尾に改行がいるので、trim()で整形

振り返り

リライト設定だしHostingがCDN相当の振る舞いをしてくれたりするので、ついCloud Functionsで利用しがちです。
ただ、コストを考えたほうがいいとは思いつつ、「最小限の労力で必要十分な結果を得る」にはこれぐらいの感覚で利用してよいのかなとも思いました。


  1. 無効化出来るに越したことはないので、情報募集中 

  2. TODO 

  3. これをしないばあいは、text/htmlになります 

attakei
東京湾岸にて勤務中。 【公私】主にインフラ・サーバサイドWeb担当。Pythonista 【他】徒歩バカ
nijibox
ニジボックスの開発は、社内のUI/UXデザインチームと連携をとりながらワンストップで行う開発支援サービスです。Reactを始めPHP(Laravel)・Ruby on Rails、Swift・Kotlinを使った開発実績も多く、バックエンドからアプリまで幅広く対応しています。現在、リクルートの大規模サービスでのモダン開発に興味のあるフロントエンドエンジニアを積極採用中です!
https://www.wantedly.com/companies/nijibox
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away