[AWS] LightsailでEMLauncherを動かす - AmazonLinux2編

iOS/Android用の開発中のアプリをチームで共有するための定番ツール「EMLauncher」をAWSのLightsailへインストールします。

基本的にLightsailに存在する機能を中心に設定しますが、一部AWS本体も利用します。

  • ファイルはS3へ保存
  • メール送信はSESを利用
  • S3とSES用のIAMを作成

まぁ…最近はDeployGateなどのクラウドサービスを利用する方が圧倒的に楽ちんなのですが、コストや管理上の問題など、自前で準備しなければならくなった場合に参考にしていただければと。

インスタンスの準備

ダッシュボードへログイン

Lightsailのダッシュボードに入ったら、「インスタンスの作成」ボタンをクリック。

インスタンスを作成

今回はプラットフォームを「Linux/UNIX」、設計図は「OSのみ」にある「Amazon Linux2」を選択しました。そういえばいつの間にかAmazonLinux2が選べるようになってますね。今まで涙を飲んで1を選んでいたのですがw

プランは予算に応じたものを選びます。今回は10ドルのプランを選択しました。最後に「インスタンスの作成」ボタンを押せばインスタンスの作成が始まります。アプリのファイル容量が膨れ上がったり、大人数で高頻度に利用するようであれば、もう1つ上のプランでも良いかもしれません。

独自ドメインを割り当てる

さすがにドメインが設定されてないと運用しずらいと思うので、序盤でやっておきます。

固定IPアドレスを付与

LightsailにもAWS本体で言うElastic IPのように、インスタンスに固定IPを紐付ける機能があります。ダッシュボードの上部のメニューにある「ネットワーキング」から「静的IPの作成」ボタンをクリック。

IPアドレスを付与したいインスタンスを選んだ後に、IPアドレスを管理するための名前を決めます。名前とインスタンス名は似たものを設定しておかないと後々わからなくなりますのでご注意を。最後に「作成」ボタンをクリックすれば完了です。実際に割り当てられたIPアドレスをどこかにメモしておきます。

なおこの固定IPはインスタンスと紐付けている間は無料ですが、インスタンスを削除したあとに固定IPをそのままにしておくと料金が発生します。インスタンスを削除したら忘れずに固定IPを野に放つか、新しいインスタンスに紐づけておく必要があります。

独自ドメインを設定

詳細は割愛しますが、先ほどの固定IPをLightsailのDNS機能か、Route53などで紐付けます。

LightsailにはDNSを(無料で!)設定することもできます。もちろんドメイン自体はどこかで契約し1年毎に対価を払う必要はありますが、ネームサーバ分については料金は発生しません。

もしくはAWS本体のRoute53で設定する方向もあります。こちらは問答無用で料金が発生しますが、よほど大規模なアクセスが無ければコーヒー一杯分にもなりませんので不安になる必要はありません。

SSHでログインする

公開鍵の登録

Lightsailのダッシュボードのインスタンスハンバーガーメニュー(点が3つ縦に並んだボタン)から「接続」を選ぶか、横ある四角いボタンをクリックしブラウザ上から利用できるシェルを起動します。

ログインするローカルの端末でRSA鍵を事前に作成しておき、公開鍵の方をクリップボードにコピーしておきす。あとはEMLauncherインスタンスダッシュボードからログインし~/.ssh/authorized_keysへ公開鍵を追記し保存します。

$ vi  ~/.ssh/authorized_keys
(公開鍵を貼り付ける)

ローカルの端末からログインできるか確認します。ユーザー名は「ec2-user」です。

$ ssh ec2-user@emlauncher.example.com

sshdの設定を変更

ピンポンダッシュを防ぐためにSSHのポート番号をデフォルトの22番から他の番号へ変更しておきます。未定義の49152〜65535番が安全ではあります。

$ sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.original
$ sudo vi /etc/ssh/sshd_config
Port 60022

LightsailにはデフォルトでFirewalldもiptablesもいないのですが、ダッシュボードからポートの開放を行う必要があります。インスタンスの管理画面に入り、「ネットワーキング」をクリック。ファイアーウォールの項目にある「ルールを追加」をクリック。

sshd_configに記入したポート番号を入力し「作成」ボタンをクリックします。 

おもむろにsshdを再起動して設定を反映します。この時に今接続しているTerminalは切断しないよう気をつけてください。もし設定を間違えていた場合、二度と接続できなくなる可能性があります。

$ sudo systemctl restart sshd

新しいTerminalを開き、先ほど設定したポート番号でログインできるか確認します。

$ ssh ec2-user@emlauncher.example.com -p 60022 

なお、ポート番号を変更するとこれ以降はダッシュボードからはログイン出来なくなるのでご注意を。……まぁ一度ローカルから接続する設定を終えるとこっちはほとんど使わないのですけどね。

AWSにリソースを準備

S3

バケットの作成

今回はipaやapkなどのファイルはS3へ保存するので、保存先のバケットを準備します。リージョンや細かい設定はお好みで。

ハマり所としては、必ずパブリックアクセスを許可してください。これをしないとEMLauncherからファイルをアップロードする際にPermission deniedで怒られます。

IAMの作成(S3用)

先ほど作成したS3をEMLauncherが触るためのIAMを用意します。

さすがにS3FullAccessは怖いので横着せずに以下のようなJSONを登録します。Resourceの部分は作成したバケットに置き換えてください。

{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "s3:*"
         ],
         "Resource":[
            "arn:aws:s3:::emlauncher.example.com",
            "arn:aws:s3:::emlauncher.example.com/*"
         ]
      }
   ]
}

最後に表示される(ダウンロードできる)「Access key ID」と「Secret access key」のメモをお忘れなく。

SES

今回はメール送信に対応するので、AWSSMTPサーバも準備します。

詳細は以下のページをご覧ください。 blog.katsubemakito.net

最終的に作成したSMTP用のIAMの「Access key ID」と「Secret access key」を必ずメモしてください。

ミドルウェアのセットアップ

さて、ここからが本題です。先ほどのインスタンスミドルウェアの導入と設定を行います。

アップデート

SSH周りの設定が終わったら可及的速やかにアップデートします。

$ sudo yum update

スワップ領域を追加

AWS上でインスタンスを作成すると大抵の場合スワップはいません。アプリサイズが巨大になる場合も考慮しスワップを用意しておきます。

詳細は過去の記事を参照ください。この通りに行います。 blog.katsubemakito.net

まずはスワップ用のファイルを作成し、スワップ領域化します。

$ sudo mkdir /var/swap/
$ sudo dd if=/dev/zero of=/var/swap/swap0 bs=1M count=1024
$ sudo chmod 600 /var/swap/swap0
$ sudo mkswap /var/swap/swap0
$ sudo swapon /var/swap/swap0

正常に認識されているかfreeコマンドなどで確認しておきます。

$ free -h
              total        used        free      shared  buff/cache   available
Mem:           1.9G        350M        371M        688K        1.2G        1.4G
Swap:          1.0G          0B        1.0G

ただこのままだと再起動時に外れてしまうので、/etc/fstabに追記しておきます。ちょっと面倒に感じるかもしれませんがこのタイミングで再起動して正常に動作するか確認しておくことをおすすめします。

$ sudo vi /etc/fstab
/var/swap/swap0 swap swap defaults 0 0

ミドルウェアをインストール

READMEで指定されている物をインストールします。これでPHPMariaDBMemcached、composerが入ります。

$ sudo amazon-linux-extras install lamp-mariadb10.2-php7.2
$ sudo amazon-linux-extras install memcached1.5
$ sudo yum install mariadb-server httpd php-gd php-mbstring php-xml php-pecl-imagick php-pecl-memcached php-pecl-zip git
$ curl -sS https://getcomposer.org/installer | php
$ sudo cp composer.phar /usr/local/bin/composer

今回はメール送信にも対応しますので、Postfixを入れます。

$ sudo yum install postfix

EMLauncherのソースを取得

GitHubに上がっているEMLauncherのコードをcloneしてきます。

$ cd ~
$ git clone https://github.com/KLab/emlauncher.git 

ディレクトリの中に入りサブモジュールを取得します。

$ cd emlauncher
$ git submodule init
$ git submodule update

composerで必要なライブラリを取得します。

$ composer install

今回は/webの下にEMLauncherを配置するので、先ほどのソースをまるっとコピーしちゃいます。場所は/var/wwwの下などでもどこでも良いです。

$ cd ~
$ sudo mkdir /web
$ sudo cp -r emlauncher /web

EMLauncherのソースを修正

.htaccess

AmazonLinux2はPHPをmod_phpではなく、mod_fpm(fastCGI)で動かしているため、.htaccessに書かれているphp_flag, php_valueが解釈できずエラーになります。

そこでこの部分を#コメントアウトして保存します。後ほど/etc/php.iniで同様の設定を行うので安心してコメントアウトしてください。

$ sudo vi /web/emlauncher/web/.htaccess
# php_flag short_open_tag On
# php_value memory_limit "4G"
# php_value upload_max_filesize "4G"
# php_value post_max_size "4G"
# php_value max_execution_time 300
# php_value max_input_time 300

Apacheの設定

今回はVirtualHostで設定を記述しました。/etc/httpd/conf.dの下に新しく設定ファイルを追加します。

$ sudo vi /etc/httpd/conf.d/vhost.conf
<VirtualHost *:80>
  SetEnv MFW_ENV 'ec2'
  ServerName   emlauncher.example.com
  DocumentRoot /web/emlauncher/web
  CustomLog    logs/emlauncher.example.com-access_log combined
  ErrorLog     logs/emlauncher.example.com-error_log
  <Directory /web/emlauncher/web>
    Require all granted
    AllowOverride All
  </Directory>
</VirtualHost>

ついでにセキュリティ関係の設定もしておきます。このあたりは本題ではないのでお好みでどうぞ。

$ sudo vi /etc/httpd/conf.d/header.conf
# サーバー/OS情報を出力しない
ServerTokens Prod
ServerSignature Off
Header always unset X-Powered-By

# 他サイトからFRAME/IFRAMEで呼び出し禁止
Header always append X-Frame-Options SAMEORIGIN

# XSS対策
Header always set X-XSS-Protection "1; mode=block"

# ファイル内容からMIME判定をさせない
Header always set X-Content-Type-Options nosniff

# Traceメソッド禁止
TraceEnable Off

最後にApacheを起動します。またOS起動時に自動的に起動するよう設定をしておきます。

$ sudo systemctl start httpd
$ sudo systemctl enable httpd

MariaDBの設定

まず最初にEMLauncherがDBへ接続する際に利用する、IDとパスワードの設定ファイルを作成しておきます。パスワードの部分は半角英数字などで適当に置き換えてください。

$ sudo echo 'emlauncher:(パスワード)' > /web/emlauncher/dbauth

ではMariaDBを起動します。OS起動時に自動的に起動するよう設定します。

$ sudo systemctl start mariadb
$ sudo systemctl enable mariadb

忘れないうちにセキュリティの設定をしておきます。

$ mysql_secure_installation
Enter current password for root (enter for none):  (このままエンター)
Set root password? [Y/n] Y
Remove anonymous users? [Y/n] Y
Disallow root login remotely? [Y/n] Y
Remove test database and access to it? [Y/n] Y
Reload privilege tables now? [Y/n] Y

DBとテーブル定義が書かれているSQLを流し込みます。

$ mysql -u root -p < /web/emlauncher/data/sql/database.sql
$ mysql -u root -p emlauncher < /web/emlauncher/data/sql/tables.sql

MariaDBCLIからログインしパスワードの設定を行います。この時のパスワードは/web/emlauncher/dbauthと同じ物を指定します。database.sql内にパスワード設定欄があるのでそこを書き換えても良いのですが、あっちこっちにパスワードが記録されるのも気持ち悪いので、手動で設定します。

$ mysql -u root -p
MariaDB [(none)]> SET PASSWORD FOR 'emlauncher'@'localhost' = PASSWORD('パスワード');

Memcachedの設定

設定ファイルを確認します。特にOPTIONSが以下のようにローカルからだけ参照する設定になっているか必ず確認。LightsailのFirewallが防いでくれますが念には念を入れておきます。

$ cat /etc/sysconfig/memcached 
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="64"
OPTIONS="-l 127.0.0.1,::1"

設定に問題なければMemcachedを起動、OS起動時に自動的に起動するよう設定します。

$ sudo systemctl start memcached
$ sudo systemctl enable memcached

PHPの設定

/etc/php.iniを読み込んでいるようなので、このファイルを編集していきます。

$ php -r 'phpinfo();' | grep php.ini
Configuration File (php.ini) Path => /etc
Loaded Configuration File => /etc/php.ini

最初にオリジナルのファイルをバックアップしておきます。元に戻す時に楽なのとdiffで変更点を見比べられます。

$ sudo cp /etc/php.ini /etc/php.ini.original

php.iniの変更点は以下の通り。.htaccessコメントアウトした箇所を3〜8行目で指定しました。他の箇所はお好みでどうぞ。

$ sudo vi /etc/php.ini
expose_php = Off
max_execution_time = 300
max_input_time = 300
mail.add_x_header = Off
memory_limit = 1G
post_max_size = 2G
upload_max_filesize = 2G
date.timezone = Asia/Tokyo
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none
mbstring.func_overload = 0

設定を反映させるために、ApacheではなくPHP-FPMの方を再起動します。

$ sudo systemctl restart php-fpm

Postfixの設定

最初に設定ファイルのバックアップを取ります。

$ sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.original

SESのSMTPサーバを経由してメールを送信するので、AWSのドキュメントの内容を参考にしながら設定します。myhostnameはSESの設定時に認証したドメインを、relayhostの値はリージョンによって変更してください(以下は東京リージョンです)。smtp_で始まる項目は存在しませんのでrelayhostの下あたりに追加します。

$ sudo vi /etc/postfix/main.cf
myhostname = emlauncher.example.com

relayhost = [email-smtp.ap-northeast-1.amazonaws.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_tls_security_options = noanonymous
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_use_tls = yes
smtp_tls_security_level = encrypt
smtp_tls_note_starttls_offer = yes

SESを設定した際に作成したSMTP用ユーザーの「Access key ID」と「Secret access key」を以下のようにファイルに1行で書きます。

$ sudo vi /etc/postfix/sasl_passwd
[email-smtp.ap-northeast-1.amazonaws.com]:587 (Access key ID):(Secret access key)

先ほどのファイルを元にPostfixが利用するファイルフォーマットへ以下のコマンドで変換し「/etc/postfix/sasl_passwd.db」を作成します。無事に生成されたら先ほどの元となったファイルは削除して大丈夫です。

$ sudo postmap hash:/etc/postfix/sasl_passwd

最後にPostfixを起動、OS起動時に自動的に開始するよう設定します。

$ sudo systemctl start postfix 
$ sudo systemctl enable postfix

EMLauncherの設定

長い道のりでしたw ようやく本体の設定です。

サーバ情報

GitHubからcloneしたファイルの中に設定のサンプルファイルがあるので、これをコピーします。

$ cd /web/emlauncher/config
$ sudo cp mfw_serverenv_config_sample.php mfw_serverenv_config.php

ここで書き換えるのはauthfileの部分だけです。MariaDBのユーザーIDとパスワードを記録したdbauthのパスを記入します。

$ sudo vi mfw_serverenv_config.php
/**
 * Database設定
 */
'database' => array(
        /** DBの ユーザ名:パスワード が書かれたファイル */
        'authfile' => '/web/emlauncher/dbauth',

EMLauncher自身の設定

こちらもサンプルファイルをコピーします。

$ sudo cp emlauncher_config_sample.php emlauncher_config.php

主に変更した箇所のみ掲載します。

$ sudo vi emlauncher_config.php
$emlauncher_config = array(
    'ec2' => array(
        // 送信メールのFrom用
        'mail_sender' => 'no-reply@emlauncher.example.com',

        // SSL対応(あとでtrueにします)
        'enable_https' => false,

        // GoogleとAzureの認証は利用しないのでfalseに変更
        'login' => array(
            'enable_google_auth' => false,
            'enable_azuread_auth' => false,
         ),

        // 今回はS3を利用するのでそれぞれ入力
        'storage_class' => 'S3',
        'aws' => array(
            'key' => '(Access key ID)',
            'secret' => '(Secret access key)',
            'region' => 'ap-northeast-1',
            'bucket_name' => 'emlauncher.exmaple.com',
        )

ユーザー登録

最後にユーザーをMariaDBへ登録します。ユーザーの数だけメールアドレスをINSERTしてください。

$ mysql -u emlauncher -p emlauncher
MariaDB [emlauncher]> INSERT INTO user_pass (mail) VALUES ('katsubemakito@gmail.com');

これ管理画面とか無いんですね。人の出入りがある度に依頼が来るヤツだw

ログインする

いよいよEMLauncherをWebブラウザから触ります。

設定したドメインにブラウザでアクセスし、ログイン画面が表示されたら「forget password」リンクをクリック。その後メールアドレスを入力するフォームが登場しますので、MariaDBへINSERTしたメールアドレスを入力します。

メールが届いたらリンクをクリック、パスワードを設定します。

その後はメールアドレスと先ほど設定したパスワードを利用してログインが切るようになりますので、各機能が正常に動作するかチェックしてください。

SSLに対応する

会社などで利用する場合は機密情報を扱うわけですので、SSL対応は必須。ここではLet's Encryptを利用します。

ポートを開放

忘れないうちにLightsailの管理画面からSSHのポートを開放したときと同じ手順で、今度はSSL用のポート(443番)を開放します。

80番はLet's Encryptが利用するのでそのまま残しておきます。

mod_sslcertbotのインストール

mod_sslは一発で入るのですが、問題はcertbotの方です。

$ sudo yum install mod_ssl

certbot-autoを直接ダウンロードしパーミッションの設定をしますが、このままだとAmazonLinux上では動きません。

$ sudo curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto
$ sudo chmod 700 /usr/bin/certbot-auto

以下のページの内容に沿ってcertbot-autoを修正します。 qiita.com

vimなどで開き前者のコードを後者に書き換えます。マジかw

$ sudo vi /usr/bin/certbot-auto
elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then
 ↓
elif grep -i "Amazon Linux" /etc/issue > /dev/null 2>&1 || \
   grep 'cpe:.*:amazon_linux:2' /etc/os-release > /dev/null 2>&1; then

certbotを実行

ではcertbot-autoを実行し証明書を取ってきます。

$ certbot-auto certonly --webroot -w /web/emlauncher/web -d emlauncher.example.com --email katsubemakito@gmail.com -n --agree-tos --debug

以下の様なファイルが生成されていれば成功です。

$ ls /etc/letsencrypt/live/emlauncher.example.com/
cert.pem  chain.pem  fullchain.pem  privkey.pem  README

Apacheの設定

mod_sslをインストールすると/etc/httpd/conf.d/ssl.confが作成されますので、このファイルを開き、以下の箇所を先ほど取得したファイルに置き換えます。またvhost.confに書いた内容をこちらにも記載します。

$ sudo vi /etc/httpd/conf.d/ssl.conf
<VirtualHost *:443>
  ### 既存の設定を変更
  SSLCertificateFile /etc/letsencrypt/live/emlauncher.example.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/emlauncher.example.com/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/emlauncher.example.com/chain.pem

  ### 新規に追加
  SetEnv MFW_ENV 'ec2'
  ServerName   emlauncher.example.com
  DocumentRoot /web/emlauncher/web
  CustomLog    logs/emlauncher.example.com-access_log combined
  ErrorLog     logs/emlauncher.example.com-error_log
  <Directory /web/emlauncher/web>
    Require all granted
    AllowOverride All
  </Directory>
</VirtualHost>

最後にApacheを再起動します。

$ sudo systemctl restart httpd

ここまで終わったらWebブラウザhttpsでアクセスし、正常に動作するかチェックします。

EMLauncherをSSL専用に

HTTPSで正常に動作しているのを確認したら、先ほど設定したemlauncher_config.phpのenable_httpsをtureにします。これでHTTPでアクセスされても自動的にHTTPSの方へリダイレクトしてくれます。

EMLauncher側の設定

$ sudo vi emlauncher_config.php
$emlauncher_config = array(
    'ec2' => array(
        // SSL対応
        'enable_https' => true,

ただこの設定が有効なのはログインページだけみたいですね。ログイン状態で他のページへHTTPでアクセス出来てしまいます。

Apache側の設定

先ほどの設定だけでは不完全なので、Apache側でも制御します。 vhost.confを開き以下の設定を追加します。/.well-known以下へのアクセスはLet'sEncryptが証明書の更新で利用するので対象外にしています。

$ sudo vi /etc/httpd/conf.d/vhost.conf 
<VirtualHost *:80>
  # 中略

  RewriteEngine on
  RewriteCond %{HTTPS} off
  RewriteCond %{REQUEST_URI} !(^/\.well-known/)
  RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

Apacheを再起動して設定を反映します。

$ sudo systemctl restart httpd

SSL証明書をcronで自動更新

rootのcronにcertbot-autoを登録します。AmazonLinux2はデフォルトだとUTCなので20:00は日本時間でAM5:00ですね。

$ sudo su -
# crontab -e
00 20 * * * root /usr/bin/certbot-auto renew --post-hook "systemctl restart httpd"

バックアップ

スナップショット

ひとしきり設定が終わったら忘れないうちにスナップショットを取っておきます。

必要に応じてこの下にある1日1回スナップショットを取る設定をオンにします。

おまけ

検索エンジンやボットを拒否

悪意のあるボットには無視されるでしょうが、一般的な検索エンジンにインデックスされるのをrobots.txtで防止します。

$ sudo vi /web/emlauncher/web/robots.txt
User-agent: *
Disallow: /

パスワードの文字数の下限を指定する

簡易的な方法です。 セキュリティ的に短いパスワードを設定されないよう、最低文字数を設定します。

テンプレートを開き入力フォームにminlengthを設定します。指定文字数未満だと送信ボタンを押した際に怒られます。IE以外の主要なブラウザは対応しています。

$ sudo vi /web/emlauncher/data/templates/login/password_reset.php 
<input class="form-control" type="password" id="password" name="password" minlength="16">

メールが届かない?

正常にメールが送信されているかまずはPostfixのログを確認します。

$ sudo cat /var/log/maillog 

Email address is not verified

554 Message rejected: Email address is not verified. The following identities failed the check in region AP-NORTHEAST-1

上記のようなエラーが出ていた場合、Postfixのmyhostnameの設定か、SESのドメイン認証が正しく行われていない可能性があります。

SESは送信するメールヘッダの内容を厳しくチェックしています。FromやReturn-Pathに含まれるメールアドレスのドメインが、SESに事前に登録した物で無い場合はこのようにリジェクトされてしまいます。

参考ページ