JOURNAL コラム
2023.08.02 エンジニア

CloudFlareに静的ファイルをデプロイしておまけでBASIC認証をかける

Web屋さんとは切っても切り離せない存在のWebサーバー。もちろん私も業務で毎日触っています。その中でもステージングで確認用に使用しているサーバはついこの前まで社内ネットワークに設置されたPCが担当していました。しかし、先日のオフィス引っ越しもあり、いい機会だからと別の環境を構築することになり現在は絶賛検討中です。

今回は候補としてあがっているCloudFlareのデプロイ方法とBASIC認証のかけ方について書いていこうと思います。また弊社では現状Bitbucketを使用しているため、CloudFlareで用意されたGitHub/GitLabを用いた方法は使用できないので、今回はCLIで実施していきたいと思います。

CLIインストール

まずはアカウントの作成ですが、こちらは通常のWebサイトと変わらないため今回は省略します。次にデプロイに使用するコマンドラインツールを用意します。

$ npm install wrangler
$ wrangler login

上記でツールのインストールとアカウントとの紐づけログインを行っています。ログインのコマンドを実行するとPCに設定されているデフォルトブラウザでCloudFlareアカウントの承認画面が表示されます。表示された承認画面でAllowを選択すればログインが完了しアカウントに対してコマンドを実行することができるようになります。

プロジェクト作成

次にデプロイ先となるプロジェクトを作成します。作成には下記のコマンドを実行します。[project name]の部分を適宜書き換えてから実行してください。

$ wrangler pages project create [project name]
$ wrangler pages project list

プロジェクトが作成できたかは2行目のlistのコマンドかCloudFlareの管理画面の左メニューのWorkers & Pagesで確認することができます。

デプロイ

いよいよデプロイです。ここまでも簡単でしたが、デプロイも下記のコマンドを実行するだけなので簡単です。今回も[project name]の部分を先程作成したプロジェクト名に書き換えてから実行してください。

$ cd [path/to/documentRootDir]
$ wrangler pages deploy . --project-name [project name]

ここでは、デプロイするファイル群のルートディレクトリに移動してからデプロイを実行していますが、もしプロジェクトディレクトリ内のdist以下のみデプロイしたい場合は、

$ wrangler pages deploy dist --project-name [project name]

上記のように deployの後ろでデプロイ対象にするディレクトリを指定することもできます。

デプロイが完了するとターミナル上でhttps ://[ランダム文字列].[project name].pages.devこのような形のURLが発行されているため、アクセスしてみると先程デプロイしたページを確認することができます。これで作業は完了です!

BASIC認証をかける場合

おまけとしてBASIC認証を書ける場合の手順も紹介しておきます。

BASIC認証を行うためにはCloudFlareのPages Functions機能を使います。Functionsは簡単にサーバレスなAPI処理などを設置することができる便利な機能です。Functionsの機能を使うのも簡単で、ドキュメントルート直下にfunctionsというディレクトリを作成し、そこにスクリプトファイルを格納しデプロイするだけです。

今回はBASIC認証をさせるためAPIよりもミドルウェアとして設置する必要があります。ミドルウェアとして設置する場合はfunctions以下に_middleware.jsという名前のファイルを設置してこの中に必要な処理を記述してあげれば大丈夫です。

BASIC認証をかけるためのスクリプトはWorkers用のものが公式で用意されているため、これをFunctions用に書き換えます。
参考 「HTTP Basic Authentication」: https://developers.cloudflare.com/workers/examples/basic-auth

const BASIC_USER = 'admin'
const BASIC_PASS = 'admin'

async function errorHandling(context) {
  try {
    return await context.next()
  } catch (err) {
    return new Response(`${err.message}\n${err.stack}`, { status: 500 })
  }
}

async function handleRequest({ next, request }) {
  // authenticated時にAuthorizationヘッダーが送信されます。
  if (request.headers.has("Authorization")) {
    const Authorization = request.headers.get('Authorization')
    // 認証に失敗した場合に例外をスローします。

    const [scheme, encoded] = Authorization.split(' ')

    // AuthorizationヘッダーはBasicで始まり、スペースが続きます。
    if (!encoded || scheme !== 'Basic') {
      return new Response(`The Authorization header must start with Basic`, {
        status: 400,
      })
    }

    // base64値をデコードしてUnicode正規化を実行します。
    const buffer = Uint8Array.from(atob(encoded), (character) =>
      character.charCodeAt(0)
    )
    const decoded = new TextDecoder().decode(buffer).normalize()

    // ユーザー名とパスワードは最初のコロンで区切られます。
    //=> 例: "username:password"
    const index = decoded.indexOf(':')

    // ユーザー名とパスワードは最初のコロンで区切られ、制御文字を含んではなりません。
    if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) {
      return new Response('Invalid authorization value.', { status: 400 })
    }

    const user = decoded.substring(0, index);
    const pass = decoded.substring(index + 1);

    if (BASIC_USER !== user || BASIC_PASS !== pass) {
      return new Response('Invalid credentials.', { status: 401 })
    }

    // 例外が発生しなかった場合にのみこのレスポンスを返します。
    return await next()
  }

  // 認証されていません。
  return new Response('You need to login.', {
    status: 401,
    headers: {
      // ユーザーに資格情報の入力を促す。
      'WWW-Authenticate': 'Basic realm="my scope", charset="UTF-8"',
    },
  })
}

export const onRequest = [errorHandling, handleRequest]

今回は簡単のためBASIC認証のID/PWはファイルの先頭で設定しています。適宜書き換えてからデプロイしてください。

デプロイ方法は先程のコマンドと同じです。しかし、deployコマンドを打つときのカレントディレクトリ内にfunctionsディレクトリが無いとFunctionsとしてデプロイされません。ドキュメントルート直下にfunctionsディレクトリが入っていれば良いというわけではないので注意が必要です。

正常にFunctionsが設定された場合はコマンドの実行結果に✨ Uploading Functions bundleといった記述が出力されているので、ページにアクセスしてもうまく動作しなかった方はそこで確認してみてください。

おわりに

さて、今回はCloudFlareへのデプロイとBASIC認証をやってきました。弊社では現在ステージング環境を絶賛検討中なのですが、以前はFTPクライアントで接続してファイルをドラッグアンドドロップ…というところからだいぶ進化しました。
静的ホスティングできるサービスとしては他にもFirebase HostingやS3、Git系サービスのPagesなど候補は色々あるので検討を加速していきたいと思います。

CCG WORKING HEADSでは、サイト制作やウェブデザインなど、デジタル領域のクリエイティブを軸に、お客様の想いをカタチにします。
お問い合わせから、お気軽にご連絡ください。

このコラムに関連するタグ

Share

  • facebook
  • twitter
  • B!
  • Feedly