とーますメモ

Ruby on Rails / Goなどの学習メモ

【Rbenv】Ubuntu18.04上で、Ruby 2.3.1がインストールできない

以下のコマンドでエラーが発生

$ rbenv install 2.3.1
...
...

/usr/include/openssl/x509.h:728:1: note: declared here
 DEPRECATEDIN_1_1_0(ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *crl))
 ^
Makefile:301: recipe for target 'ossl_x509crl.o' failed
make[2]: *** [ossl_x509crl.o] Error 1
make[2]: Leaving directory '/tmp/ruby-build.20200630231630.9214.C0DTvB/ruby-2.3.1/ext/openssl'
exts.mk:208: recipe for target 'ext/openssl/all' failed
make[1]: *** [ext/openssl/all] Error 2
make[1]: Leaving directory '/tmp/ruby-build.20200630231630.9214.C0DTvB/ruby-2.3.1'
uncommon.mk:203: recipe for target 'build-ext' failed
make: *** [build-ext] Error 2

どうやらopenssl系のエラーっぽい。

ピンポイントで素晴らしいQiitaの投稿があったのでそのとおりにやったらインストールできた。
Ubuntu18.04にrbenvを使ってRuby2.3インストールしたらコケた話 - Qiita

Ruby2.4未満のバージョンはoppenssl 1.1と互換性が無いっぽいとのこと。

なのでlibssl1.0-devを入れてあげると良いとのこと。

$ sudo apt install libssl1.0-dev

Vagrant × AnsibleでUbuntu18.04環境を設定してみる - Webサーバ編 -

全体像は、Webサーバ1台、DBサーバ1台をVagrantで設定し、Ansibleでそれぞれのサーバに設定を行う。

インストール

簡単な流れは
1)VirtualBoxをインストール
2)Vagrantをインストール
3)Vagrantfileを編集

1)と2)については以下の記事のとおりに設定。すごい簡単。
Vagrant+VirtualBoxでUbuntu環境構築 - Qiita

3)は以下の設定を行う。

使用するUbuntuのBoxイメージは「bento/ubuntu-18.04」を使用。

$ vagrant init bento/ubuntu-18.04

上記のコマンド実行後に、Vagrantfileが生成されるので、その中身を以下のように変更する。
1)ログイン時にどのホストにログインしているか分かりやすいようにホスト名をつける
2)固定IPを設定することで、Ansibleからアクセスできるようにする。(以下例では192.168.33.10)
3)AnsibleでNginxを設定した際に、http://127.0.0.1:8090/でアクセスしたいので、ポートフォワーディングの設定を行う
4)メモリは実際に想定されるサイズのメモリサイズを設定しておきたいので、とりあえず2GB(2048) を設定。

  config.vm.hostname = "dev-webserver"
  config.vm.network "private_network", ip: "192.168.33.10"

  config.vm.network "forwarded_port", guest: 80, host: 8090, host_ip: "127.0.0.1"

  config.vm.provider "virtualbox" do |vb|
    # Display the VirtualBox GUI when booting the machine
    # vb.gui = true

    # Customize the amount of memory on the VM:
    vb.memory = "2048"
  end

ネットワーク疎通確認は以下のコマンドで行う。

$ ping 192.168.33.10

Vagrant起動

起動

$ vagrant up

状態確認

$ vagrant status

全てのvagrant確認

$ vagrant global-status

シャットダウン

$ vagrant halt

再起動

$ vagrant reload

一時停止

$ vagrant suspend

一時停止から復帰

$ vagrant resume

実行中のマシンを停止し、削除

$ vagrant destroy

UbuntuにSSHでログイン

以下のコマンドでログインする

$ vagrant ssh
または
$ ssh vagrant@192.168.33.10

ログイン先の「/vagrant」は、Vagrantfileのディレクトリと同期しているので
ファイルの出し入れが必要な際はこのディレクトリを使用する。

ログアウトは単純にexitを打つだけ

$ exit

Sandbox環境を作成する

プラグインであるSaharaを使用する。サンドボックス環境を用意することでAnsibleによる試行錯誤(作ったり、壊したり)を行いやすいようにする。
詳細は以下のサイトを参考
VagrantにSaharaを導入 - Qiita

今回は、sshでサーバにログイン後、apt update&upgrade後にsandboxをonにした。
これでクリーンな環境にいつでも戻すことができる。

インストール

$ vagrant plugin install sahara

確認

$ vagrant sandbox status

sandboxモード開始

$ vagrant sandbox on

変更を決定

$ vagrant sandbox commit

変更を破棄し、ロールバック

$ vagrant sandbox rollback

sandboxモードを終了(commitしていないものは破棄される)

$ vagrant sandbox off

【Ansible】defaultsとvarsの違いって?使い分ける方法を調べた

vars/main.ymlにも変数が書けることは知っていたが、Ansibleを使い始めてから、ずっとdefaults/main.ymlを使用していた。
ただどのように使い分けるのかは知らないのでいたので、調べた内容をこの記事にまとめてみた。

色調べた結果、以下のサイトの説明が良かった。
Playbookを再利用しやすくするRoleの基本と共有サービスAnsible Galaxyの使い方 (2/4):Ansibleで始めるサーバ作業自動化入門(4) - @IT

defaultsとvarsの違いは読み込まれる変数の優先度です。defaultsはその名前の通り、変数のデフォルト値を意味し、優先度が最も低い変数になり、varsはvars_filesでのファイル読み込みと同じ優先度となります。

そのため、ユーザー名やパスワードのようなロールの利用者によって書き換えられることが望ましい変数はdefaults/main.ymlで定義し、設定ファイルのファイル名のようにロールの利用者が変更するべきではない変数はvars/main.ymlで定義するといいでしょう。

要は優先度。また使い方は上記のように

上書きされることが前提の変数は、最も優先度が低いdefaultsを使用し、
固定値、要は定数として使用したい場合は、優先度が高いvarsを使用する。

多くのroleではバージョン指定だったり、IDやPWなどの変更を許容する変数を使用したほうが使い勝手良いので
defaultsを基本的に使用し、上書き元の変数はhost_varsやgroup_varsで設定する方針にする。

[他参考]
Ansible2 変数の優先度 - Qiita

ムームードメインからNamecheapにドメイン移管してみた。

現在、使用しているレジストラはムームードメインなのだが、できればSSL証明書取得も同じアカウントで管理したり、TTL設定などの細かい設定もしたかったので
経験がてら、ドメイン移管を初めてやってみることにした。

どのレジストラに移管するか?

レジストラを選定するにあたり、以下のサイトを参考にする
Registrar Stats: Top Domain Registrars - DomainState.com

f:id:Thoames1212:20200608084738p:plain

このリストから以下の会社に絞った。

Godaddy (https://jp.godaddy.com/)
あまり評判が良くないのかも?
https://qiita.com/righteous/items/8f0fe26702c6877c05e7

Namecheap (https://www.namecheap.com/)
一番安い!WhoisGuardも永久無料

Name.com (https://www.name.com/)
ネットですごい参考になった記事の作者が使用していたので検討

Gandi.net
知り合いが使用していて、オススメされたので検討
ドメイン名取得するならこれからはGandi.netが良いと思った理由 - Qiita
ドメインレジストラ Gandi.net でリセラーとしてアカウント登録するメリットとデメリット - Qiita


結局、一番金額が安くて欲しかった機能もあるNamecheapを選んだ。
(Godaddyでも良かったが、個人的にはNamecheapのUIのほうが良かった)

ドメイン移管の流れ

以下のサイトさんを参考
ドメインを海外レジストラ「namecheap」に移管する方法(ドメイントランスファー) | From Okayama To Everywhere
ムームードメインからお名前.comへドメイン移管を行う
ドメイン移管の流れについてまとめてみました(ムームードメイン→お名前.com) | 大阪市天王寺区SOHOホームページ制作 | デザインサプライ-DesignSupply.-

1) ムームードメインのWHOIS情報の「情報公開」設定が「弊社情報代理公開」になっている場合は、自分の登録情報(お客様の情報)に変更

2) 1)を行うと表示される認証コード(Auth Code)をメモっておく。
※ ドメイン一覧→ドメインの詳細情報内

3) NamecheapでTransfer申請を行う。そのときに2)でメモった、Auth Codeを使用する。

すごい簡単。

疑問だったこと

1) ドメイン移管したら残っている期間はどうなるか?
自分の場合148日残っている段階で移管した。この場合、1年契約+残っている期間が適用され、結果的に513日間、ドメインが使用できることになった。

2) ムームードメインで代理公開を解除後、ドメイン移管申請を行うが、申請後からドメイン移管が完了するまでに代理公開に再設定可能か?
Namecheapのサポートに聞いてみたところ、そちら側で可能ならやっても問題ないとのことだったので、ムームードメインの代理公開を行ってみてがエラーが出た。
要はできなかった。

3) 移管元で設定していたDNS設定はどうなるか?
同じ設定がNamecheapでもされていた。素晴らしい。

ドメイン移管後

ドメイン移管後は、ムームードメインのドメイン一覧から移管したドメインが見えなくなるものだと思っていたが、すぐに消えない。
12時間後ぐらいには消えていなかったが、24時間後ぐらいに再度確認したら消えていた。

まとめ

ドメイン移管は思っていたよりすごい簡単だった。また移管してよかったと思うのが、Namecheapはサポートがすごく良かったこと。
ムームードメインは、お問い合わせフォームでしか直接サポートの人に連絡する方法がなく、しかもすぐに連絡が返ってこない。
でもNamecheapはLiveチャットサポートがあるので、チャットウィンドウを開けば30秒ぐらいですぐに対応してくれた。
英語でしか現在は対応してもらえないが、今後日本語のサポートができれば、かなり需要があると思う。

備考

ブラックフライデーや、サイバーマンデーをだとかなり安い金額でドメイン購入や移管ができるっぽい。

【Lightsail × WordPress】メール配信サービスのAmazon SESを使ってみた

基本的には以下のサイトの通りに設定すればOKだが、所々わかりにくい箇所があるので、自分なりにまとめる。
Amazon Lightsail の WordPress で E メール を有効にする | Lightsail ドキュメント

ちなみにWordPressは既にインストール済みであることと、SMTP設定用プラグインは「WP Mail SMTP」を使用する。
(上記のリンクでもこのプラグインを使用している。他のプラグインでも良いだろうが...)

Amazon SESアカウントの作成

以下のサイトを参考に設定を行う。
Amazon Lightsail の WordPress で E メール を有効にする | Lightsail ドキュメント

[注意] アカウント作成時は「サンドボックス」という制限がついた環境設定になっているため
1対多のような任意の受信者にメールを送るためにはこの設定を解除する必要がある。
制限内容は以下。

・「送信元メールアドレス」及び「送信先メールアドレス」は、SESアカウント内で検証済みである必要がある。
・最大で24時間あたり200メッセージしか送信できない
・最大で1秒あたり1メッセージしか送信できない

Amazon SESを使うならサンドボックスの外にいくこと - Qiita
Amazon SES サンドボックスの外への移動 - Amazon Simple Email Service

指定されたメールアドレスにしかメールを送らない簡易なシステム通知ぐらいであればサンドボックス制限は外さないでも良いだろうが
マーケティング系の一斉メールを行いたい場合などは、このサンドボックス制限を外す必要がある。

以下が簡単な流れ。

1)SESコンソールにログイン
2)左側ナビメニューの「SMTP Settings」からSMTPの設定を行う。尚設定内容はメモっておくこと。
3)「送信元」メールのドメイン検証を行う。左側ナビメニューの「Domains」から行う。このときDKIM設定も行う。

DKIM設定をしていないと場合の例
AWS SESで送信ドメイン認証を設定する - Qiita

この設定を行うことで、設定したドメインのどのメールアドレスからでもメールを送信できる。
※MXレコードの設定で引っかかると思うので、上記リンク先のDNSレコードの設定例画像を参考にすること。

4)「送信先」のメールアドレスを認証する。左側ナビメニューの「Email Addresses」から行う。
※ただしサンドボックス制限下でなければ無視しても良い。

5)「WP Mail SMTP」の設定を行う。

From Emailには3)で設定したドメインのメールであれば、どのメールアドレスでも設定可能
SMTP Host、SMTP Username、SMTP Passwordには2)でメモしておいたものを設定する。
全て設定後、「WP Mail SMTP」の「Email Test」タブで、4)で設定した送信先メールアドレスを入力し、「Send Email」を押してメールが届けば設定がうまく行っている。

[参考]
AWS SES メール送信環境のセキュリティを解剖する (2020年版) - Qiita

サンドボックス制限を解除する

上記でも説明したように、この制限を解除することで、メール認証したメールアドレス以外のメールアドレスにもメール送信が可能になる。

以下のサイトさんの説明を参照
Amazon SES 制限解除申請(Amazon SES編 その3) - Laravel学習帳
Amazon SES でドメイン検証してメールを送信してみた - michimani.net
SES送信制限解除申請 (SES Sending Limits) | Developers.IO

バウンス(エラー)メールや苦情(スパム)メール対応

恐らくSESを使う中で、この設定が一番面倒。

詳細は以下のサイトさんを参照
AWS SESをちゃんと使うためにやるべきこと - Qiita
AWSのSESでバウンスメール(bouncemail)対策。3つの方法とメリット・デメリット | ブログ|ベトナムでのオフショア開発とスマートフォンアプリ開発のバイタリフィ
Amazon SESの掟 – サーバーワークスエンジニアブログ
Amazon SES経由のバウンスメールをWebアプリで受け取る - Qiita
Amazon SNS での Amazon SES 通知 - Amazon Simple Email Service

比較的Amazon SNSを使用して、メールを飛ばすやり方が簡単か・・・

バウンスレート管理していないと起こる問題について参考
[AWS] Amazon SESのアカウントが止められちゃった話 - Qiita

バウンスレートを下げる方法もある。以下のサイトを参考
Amazon SESのバウンスレート上昇時の対策 - Qiita

開封率やクリック追跡

以下のサイトさんを参照
Amazon SESで開封やクリックのトラッキングが可能になりました。 | Developers.IO

ただしすごい面倒くさそう。
WordPressなら「WP Offload SES」というAmazon SESだけに特化したプラグインがある。
このプラグインを使えば、メール送信ログや開封率、クリック追跡もできる。

Send Your WordPress Emails via Amazon SES with WP Offload SES - Delicious Brains Inc
Top 3 SMTP Plugins for WordPress Compared (and How to Fix Emails Not Sending) - MailPoet

SESでメール受信

[注意] 特定リージョンでしか現在サポートされていない。

Amazon SES doesn't support email receiving in the following Regions: Asia Pacific (Mumbai), Asia Pacific (Sydney), Canada (Central), Europe (Frankfurt), Europe (London), South America (São Paulo), and AWS GovCloud (US).

詳細は以下
Amazon Simple Email Service endpoints and quotas - AWS General Reference
https://forums.aws.amazon.com/thread.jspa?threadID=314983

基本的に以下のサイトのとおりにやればOKっぽいが、Gmailで受信するような感じでメールを見れるわけではない
[新機能]Amazon SES でメール受信が出来るようになりました! | Developers.IO

所感

指定されたメールアドレス宛てに送る緊急性を要さないシステム通知など用途で使用するなら楽で良いが、大量のユーザに送るケースは、バウンスレートに注意する必要がありそのためにいろんな設定が必要だし、メールの開封率やクリック追跡などの分析が必要な場合は正直、かなり不便だと感じた。

コスパは断トツで良いが、機能面が他のメール配信サービスと比べてまだまだな印象なので、現在のところ本番環境での使用は考えない。

【Ubuntu】ユーザ管理の方法について、ちゃんと調べてみた

Linux上でユーザやグループを追加したり、権限を付与する方法については知っているが、プロダクション環境などのシビアな環境でのユーザ管理法についても学んで起きたいと思ったのでここに調べた内容を書き起こす。

ユーザ追加

ユーザ追加するコマンドは以下の2つが存在する。

1)useradd
2)adduser

上記のコマンドはLinuxのディストリビューション毎に違いある。
CentOSだとadduserはuseraddのシンボリックリンクだが、Ubuntuだとuseraddはバイナリファイルであり、adduserは裏でuseraddを利用するPerlスクリプトである。
またadduserは対話式でユーザを作成し、ホームディレクトリを自動作成し、パスワードも同時に設定可能だが、
useraddは-mオプションを付けない限り、ホームディレクトリを作成しないし、パスワードを設定するには別途でpasswdコマンドを使い必要がある。

なのでUbuntu上でユーザ作成する際は、必ず「adduser」を使うことにする。

[参考]
What is the difference between adduser and useradd? - Ask Ubuntu
adduserとuseraddの違い - DUNNO-CLEARブログ3.0

ユーザは複数のグループに所属できるが、まずは1つのグループに所属する必要があり、その必須なグループをプライマリグループと呼び、
それ以外のグループをセカンダリグループ(追加グループとか補助グループとも呼ばれる)と呼ぶ。

[参考]
[Linux] ユーザ管理と設定ファイル - Qiita

ユーザ削除

ユーザ追加と同じようにuserdelとdeluserがあるが、実行してみた感じだとdeluserを使用した場合、ログが表示されるが、userdelの場合は実行しても何も表示されない。
またUbuntuを使用する場合はdeluserを使うべきだと公式に書いてある。

userdel is a low level utility for removing users. On Debian, administrators should usually use deluser(8) instead.

Ubuntu Manpage: userdel - delete a user account and related files

なのでadduserと同じように、Ubuntu上でユーザ作成する際は、必ず「deluser」を使うことにする。

$ sudo deluser --remove-home username

--remove-homeオプションを付けると、ユーザのホームディレクトリも削除される

sudo権限の付与

sudo権限を付与するには、以下の3つのやり方がある

1)デフォルトでsudo権限がついているグループにユーザを追加(Ubuntuならsudoグループ、CentOSならwheel)
2)/etc/sudoersファイルにsudo権限を付けたいユーザまたはグループを設定
3)/etc/sudoers.d/内にファイルを作り、このファイル内にsudo権限を付けたいユーザまたはグループを設定

一般的には1)が一番簡単。

$ gpasswd -a user_name sudo

1)を行うのにusermodを行う方法もある。gpasswdとusermodの違いは、gpasswdがグループ管理のみ目的としたコマンドに対して
usermodは他にもいろんな機能を提供していることっぽい。
Adding user to a group (usermod or gpasswd)

usermodを使う場合はオプションに「-aG」を付ける必要があるが、gpasswdは単純に「-a」だけなのでわかりやすいため、gpasswdを使うほうが良いだろう。

2)のやり方を選ぶ場合は、基本的にはvisudoコマンドを使用してファイルを編集する。
別にviでも良いが、visudoを使用した場合、保存時に文法に不備があるとエラー箇所を教えてくれるからだ。
visudoでコマンドを打って、設定を書き込んだら「ctrl + X」で終了すれば良い。※保存などのコマンドはない。
どうしてもviが良い場合は、編集終了時に「visudo -c」で書式チェックをしておくと良いだろう。

設定は以下の感じで設定する。書式は「ユーザ名 ホスト=(誰々として) コマンドパス」。ユーザ名の頭に%をつければグループ名として指定できる。
また通常、sudoコマンド実行時にはパスワード入力を求められるが、パスワード入力を要求しないようにするNOPASSWDを設定することもできる。

# rootユーザに対して全てのコマンド実行を許可
root ALL=(ALL) ALL

# adminグループに対して全てのコマンド実行を許可
%admin ALL=(ALL) ALL

# adminグループに対して全てのコマンド実行を許可し、パスワードを要求しない
%admin ALL=(ALL) NOPASSWD:ALL

[参考]
一般ユーザでもroot権限が必要なコマンドを実行できるようにする方法 - Qiita


3)のやり方は/etc/sudoersをいじらなくてもsudo実行ができるようになるため、細かくコマンド毎に許可設定を行いたい場合などに
メンテナンス性が向上するのでよい。ファイル名は何でもよく、ファイル内の書式は2)と同じ。
編集終了時に「visudo -c」で書式チェックをしておくと良いだろう。

[参考]
sudoを/etc/sudoers.d/fileで許可する - Qiita
sudoの権限を設定するvisudoコマンド【Linuxコマンド集】


上記の3つのやり方を見てみた中で、しっかりユーザ管理したい場合は、3)の方法がよいと思う。
NOPASSWDの設定は1)の方法では使えないし、多数のユーザを管理する必要が出てきた場合に、
毎回/etc/sudoersの設定をいじるのは、メンテナンス性が良くない。
3)のやり方ならばユーザ毎にファイルを作れば管理も楽だし、ユーザを削除する場合も単純にファイルを消すだけで良い。

なので自分は3)のやり方を使用する。

ユーザ一覧の確認

$ cat /etc/passwd
もしくは
$ getent passwd

グループおよびグループの所属ユーザの確認

$ cat /etc/group
もしくは
$ getent group

ユーザが所属するグループの確認 (※usernameは任意の名前)

$ groups username

[参考]
Ubuntuユーザ追加とsudo権限付与。ユーザ/グループ操作まとめ | WWWクリエイターズ

【PHP】エラーログが出たら、Slackに通知を送る設定

SwatchやLogwatchなんかを使うのが定番っぽいが
Swatchは監視対象が複数ある場合は、複数のプロセスが常時立ち上がるのと
長い間更新されていないのが不安だったので断念。
Logwatchの場合は、別にこれでも良かったが、Postfixがデフォルトでインストールされるのが嫌だったので、自作のシェルスクリプトをcronで回すことにした。

WEBHOOK_URLとPHP_LOG_PATHは、任意のものを指定し、CHANNELやICONなんかも必要に応じて変更する。

#!/bin/bash

# 件名
RE_LOG_LEVEL="WARNING|ERROR|ALERT"
MAIL_SUBJECT="[Notification] Found PHP Error! ($RE_LOG_LEVEL)"

# 本文に使用する一時ファイルを指定する
MESSAGEFILE=$(mktemp -t webhooks.XXXX)

# 終了時に一時ファイルを削除
trap "
rm ${MESSAGEFILE}
" 0

# 本文を生成
PHP_LOG_PATH='/var/log/php7.2-fpm.log'
sudo tail $PHP_LOG_PATH >> $MESSAGEFILE

INFO='good'
WARN='warning'
ERROR='danger'

CHANNEL="#general"
ICON=":rotating_light:"

TS=`date "+%s"`
TODAY=`date "+%d-%b-%Y"`
RE_TODAY=`echo ${TODAY//\-/\\\-}`
MESSAGE=`cat ${MESSAGEFILE} | grep -E "^\[$RE_TODAY.*?\] ($RE_LOG_LEVEL)"`

WARNING_COUNT=`cat ${MESSAGEFILE} | grep -c "WARNING"`
ERROR_COUNT=`cat ${MESSAGEFILE} | grep -c "ERROR"`
ALERT_COUNT=`cat ${MESSAGEFILE} | grep -c "ALERT"`

WEBHOOK_URL="https://hooks.slack.com/services/XXXXX....."

if [ -n "$MESSAGE" ]; then
  data=`cat << EOF
    payload={
      "text": "$MAIL_SUBJECT",
      "channel": "$CHANNEL",
      "username": "$HOSTNAME",
      "icon_emoji": "$ICON",
      "link_names": 1 ,
      "attachments": [{
        "fallback": "[Notification]",
        "title": "[WARNING]: $WARNING_COUNT    [ERROR]: $ERROR_COUNT    [ALERT]: $ALERT_COUNT",
        "pretext": "\\\`AUTO MESSAGE\\\`",
        "text": "$MESSAGE",
        "color": "$ERROR",
        "mrkdwn_in": ["text", "pretext"],
        "footer": "created at",
        "footer_icon": "https://platform.slack-edge.com/img/default_application_icon.png",
        "ts": $TS
      }]
    }
EOF`

  # メッセージ送信
  curl -X POST --data-urlencode "$data" $WEBHOOK_URL
fi

exit 0;

あとはこのスクリプトをcron設定すればOK
thoames.hatenadiary.jp