AWSのS3やLambdaを使って、サーバーレスでウェブサイトを公開してみました。付随して使ったサービスやランニングコストを紹介していきます。

  • 機能要件とアーキテクチャ選択
  • アクセス数とランニングコスト
  • 実装概要

機能要件とアーキテクチャ選択

  • ページ数は5ページぐらい
  • お問い合わせフォーム
  • SSL化

サーバーを構築して、ミドルウェアのアップデートやら脆弱性のキャッチアップ、稼働率や死活監視など、気にかけるのが面倒と思ってしまいサーバーレスで作ることを決めました。

ランディングページのように、あまり更新が発生しないので、CMSを導入する必要もないという点も決め手の1つとなりました。

スポンサードサーチ

アクセス数とランニングコスト

アクセス数は、1日あたり50pvぐらいがほとんどです。

月間コストに関しては、$0.79です。日本円だと100円しないですね。使っているサービスごとのコスト利用料を見ると、ほとんどネームサーバー(Route53)の料金です。

仮に月間pv30,000とかになったとしても、金額は変わらなそうでした。

あと、ランニングコストとして忘れてはいけないのが管理費です。OSやらミドルウェア、SSL証明書の更新、コードの管理とかはほとんどかかりません。基本ほったらかしにしてます。。

一度だけAWSからnode.js VersionのEOLのお知らせメールが着て、アップグレードしたぐらいです。証明書はAmazon Certificate Managerを使っています。無料で使えますし、自動で更新されます。

イニシャルコストは、お名前.comで買ったドメインだけです。

実装方法

使った機能とそれぞれの設定手順を紹介します。初めてaws使ったので、もし間違いとかがあれば、お問い合わせよりご指摘下さいませ。

s3でサイトを公開する(Route53/CloudFront/ACM)

ウェブサイト公開用のバケット問い合わせデータ格納先のバケット2つ用意します。公開はバケットのプロパティから「Static website hosting」の設定で行うことが出来ます。

お名前.comで既にドメインを購入していたので、先ほど公開したウェブサイトとドメインの紐付けを行いました。「Route53->ホストゾーン->ホストゾーンの作成」で、ドメイン名を入力します。

次にレコードセットの作成です。名前の枠に「www」入れて作成しました。

後は、この赤字で伏せてあるNSレコードの値を、お名前.com側に入力するだけです。「お名前.comへログイン」→「ネームサーバーの設定」→「対象ドメイン選択」→「他のネームサーバーを利用」で下記画面が出てきますので、そこへ入力します。

s3をCloudFront経由で公開する

s3でホスティングしたウェブサイトを、CloudFront経由で公開し、Amazon Certificate Manager(SSL証明書)を適用させます。

先にAmazon Certificate ManagerでSSL証明書を取得します。「Amazon Certificate Manager」→「証明書のリクエスト」→「パブリック証明書のリクエスト」ドメインを入力して、検証方法を選択して申請します。ワイルドカード証明書も無料なので、ワイルドカードをつけて申請した方が良いです。(*.taneroco.com)

申請が通れば、CloudFrontの設定を進めていきます。CloudFrontから「Create Distributions」を選択します。

Origin Domain Nameの入力枠にフォーカス当てて、公開したいバケットを選択します。

SSL Certificateで「Request or Import a Certificate with ACM」を押下し、先ほど取得したACMの証明書を適用させます。後はTTLを短くしたり、リダイレクトのルールを記載したり、お好みに合わせて設定を進めます。

設定完了後、https通信でアクセスして証明書が適用されているのを確認したら、公開用s3バケットのCROS設定を行います。下記サンプルです。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>https://www.taneroco.com/*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>Authorization</AllowedHeader>
</CORSRule>
</CORSConfiguration>

これで公開用ウェブサイトの完成です。

お問い合わせフォーム(Lambda/Cognito/SES)

ウェブサイトの登録ボタンクリックで、問い合わせデータ格納先のバケットにフォームデータをputさせます。その後putされたイベントを拾ってLambda Functionを動かし、SESでメール通知させます。

SESの設定

「Simple Email Service」→「Email Addresses」→「Verify a New Email Address」で下記画面が開くので、メールアドレスを入力してください。リンクがメールで届くので押すだけで承認されます。

フォームの内容をputさせる処理(Cognito/s3)

アクセスしたユーザに対して、一時的にフォームデータ格納バケットへputできる権限を付与します。

「Cognito」→「新しいID Poolを作成」を選択します。その後、任意のプール名を入力し、認証されてないIDに対してのアクセスを有効にします。ロールに関しては、初期入力値のままで大丈夫です。

「作成したID Poolを選択」→「サンプルコード」を押下し、javascriptを選択し、サンプルコードをそのまま使います。

ホスティングされているウェブサイトのコードです。

<head>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.3.8.min.js"></script>
<script>
var $id = function(id) { return document.getElementById(id); };
AWS.config.region = "リージョン";
AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: "リージョン:cognitoのサンプルコードからそのままペースト"});

// s3にputするfanction
function putForm() {
    var now = new Date();
    AWS.config.region = 'リージョン';
    var formDataBucket = 'フォームデータ格納用バケットネーム';
    var s3 = new AWS.S3({params: {Bucket: formDataBucket}});
    var url = location.href;
    
    // s3にputするデータを格納
    var object = {
        "name":$id("name").value,
    	"mail":$id("mail").value,
    	"contents":$id("contents").value,
    	"date": now.toLocaleString(),
    	"url": url
    };
    // 文字列からblobを生成
    var blob = new Blob([JSON.stringify(object, null, 2)], {type:'text/plain'})
    // 格納先にput
    s3.putObject({Key: "formdatas/" +now.getTime()+".txt", ContentType: "text/plain", Body: blob, ACL: "authenticated-read"},
	function(err, data){
	    if(data !== null){
    	        alert("お問い合わせ完了しました。");
    		location.reload();
    	    }else{
        	alert("お問い合わせできませんでした。¥n再度お試しください。");
    	    }
	}
    );
}

</script>
</head>
<body>
<div class="section">
<h2 class="major">Contact</h2>
<form method="POST" id="postForm">
    <div class="field half">
        <label for="name">* Name</label>
        <input type="text" name="name" id="name" />
    </div>
    <div class="field half">
        <label for="email">* Email</label>
        <input type="email" name="mail" id="mail" />
    </div>
    <div class="field">
        <label for="message">* Message</label>
        <textarea name="contents" id="contents" rows="4"</textarea>
    </div>
        <ul class="actions">
            <li><input onClick="putForm()" type="button" value="Send Message" class="button special"/></li>
        </ul>
    </form>
</div>

登録ボタンクリックで、フォームの内容をフォームデータ格納用バケットにputします。

フォームデータ格納用バケットのCROS設定を行います。s3put攻撃を避けるためにリファラーの設定しましょう。AllowedOriginにputするサイトのURLを記載します。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>https://taneroco.com</AllowedOrigin>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Lambdaファンクションの作成とメール送信

「lambda」→「関数の作成」でファンクションを作成します。

好きな関数名を入力して、アクセス権限を設定します。AMIロールを作成し、ポリシーをアタッチします。今回はメール送るだけなので、「AmazonSESFullAccess」があれば動くはず。

関数の作成をしたらトリガーの設定をします。s3をトリガーのところにドラック&ドロップして、フォームデータ格納用バケットを選択し、putイベントを選択します。

あとは、Lambdaのコードを記載し保存します。下記はサンプルコードです。

var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var ses = new aws.SES({apiVersion: '2010-12-01', region: 'リージョン' });
exports.handler = function(event, context) {
    var bucket = event.Records[0].s3.bucket.name;
    var key = event.Records[0].s3.object.key;
    s3.getObject({Bucket: bucket, Key: key},
    function(err, data) {
        if (err){
            context.done('error', 'error getting file' + err);
        } else {
            var message = JSON.parse(data.Body);
            var datas = {
                    Destination: {
                        ToAddresses: ["送信先メールアドレス"]
                    },
                    Message: {
                        Body: {
                            Text: {
                                Data: "メールアドレス:" + message.mail+ "\n" + "名前:"+ message.name + "\n" + "お問い合わせ内容:"+ message.contents
                            }
                        },
                        Subject: {
                            Data: "【HPからのお問い合わせです】"
                        }
                    },
                    Source: "送り主メールアドレス"
                };
            // SESでメール送信
            ses.sendEmail(datas);
        }
    }
}

あとはウェブサイトから実際にフォーム入力してみて、メールが届くのを確認してください。

まとめ

連携するサービスや設定項目が多くて結構大変だけど、安いからやる価値あるかもしれません。クラウドサービスは使った分だけ課金されてしまうこともあり、怯えながら作成しました。時間あるときもう少し綺麗にまとめようかと思ってます。。

スポンサードサーチ