EC2の不要なインスタンスの消し方

とても単純な話なのですがかなり迷ったので備忘録的に残しておきます。

「インスタンスの削除」的なメニューがあるもんだと思ってずっと探していましたが、
実際には 「インスタンスの終了」 がそれにあたります。 (削除という文言がないのでなかなか気づきませんでした。)

消したいインスタンスを右クリックし、「インスタンスの状態」 => 「インスタンスの終了」 と選択することで消せます。
消してもしばらくはコンソール上に残るようです。

「終了保護」が設定されていると、終了ができないので、本当に消したい場合は事前に外しておきましょう。

boto3でEC2インスタンスを起動してIPアドレスを取得する

EC2のインスタンスを操作するとき、(会社ではCLIのバッチファイルを手元に持ってるのですが)私物の環境ではいつもコンソールにログインして起動/停止していたので、
これもバッチ化することにしました。
AWS CLIではなく、 Pythonライブラリの boto3で作ってみます。

職場の環境と異なり、自分の学習環境のEC2はIPアドレスを固定していません。(お金かかるから。)
なので、毎回コンソールから起動して、IPアドレスを確認し、そのIPアドレスに接続する、という作業を行っていました。
これを短縮するため、起動したらIPアドレスを取得して表示できるようにします。

ドキュメントはこの辺りが参考になります。
ec2.html#instance

以下のように、ec2インスタンスのオブジェクトを用意します。


import boto3

ec2 = boto3.resource('ec2')
instance = ec2.Instance('{インスタンスID}')

そして、startで起動してwait_until_running()で起動完了を待ち、
public_ip_addressを取得すれば良いです。

完成したバッチファイルの中身は次のようになります。
これを.pyファイルとして保存して、実行できるように権限を744にします。


#!/usr/bin/env python
import boto3
instance_id = "{インスタンスID}"

ec2 = boto3.resource('ec2')
instance = ec2.Instance(instance_id)
print("インスタンス起動開始")
instance.start()
instance.wait_until_running()
print("インスタンス起動完了")
ip = instance.public_ip_address
print(f"IPアドレス: {ip}")

実行するときちんと、
インスタンス起動開始
インスタンス起動完了
IPアドレス: xx.xxx.xxx.xxx
が表示されました。

ついでですが、停止バッチは次のようになります。


#!/usr/bin/env python
import boto3
instance_id = "{インスタンスID}"

ec2 = boto3.resource('ec2')
instance = ec2.Instance(instance_id)
print("インスタンス停止開始")
instance.stop()
instance.wait_until_stopped()
print("インスタンス停止完了")

Amazon Aurora Serverlessを使ってみる

ずっと前から気になっていたまま、使ったことがなかったのですが重い腰を上げて Aurora Serverless を触ってみることにしました。

用途は仕事ではなく、自分の趣味と勉強でとあるデータを蓄積するDBです。
AWSのアカウント持っていてDBが必要なら、RDSを使うのが順当なのですが、
通常のRDSは個人で使うにはちょっとお高いので、これまではEC2に導入したMySQLを使っていました。
そこにAurora の Serverless が登場ということで、自分の分析作業時のみの課金で使えるとなれば非常にお得な気がします。
完全に移行できるかとコストはトータルどうなるか、といった懸念は残りますが、まずは一度触ってみることにしました。

Aurora Serverless にはいくつか制限事項があるようです。
それを満たせるように事前に準備を進めていきます。

詳細はこちらを参照: Aurora Serverless の制約事項

1. VPC (Virtual Private Cloud)

Aurora Serverless にパブリックなIPアドレスを割り当てることはできず、おなじVPC内からしかアクセスできないそうです。
なので、ローカルの端末から踏み台等使わずに直接繋ぐことはできなさそうですね。
また、EC2インスタンスををクライアントにする場合は、おなじVPCの中に置いておく必要があります。
(僕はVPCはデフォルトの1個しか使っていないので、この制限は特に意識することはありませんでした。
VPCを複数使っている人は注意が必要です。)

2. AWS PrivateLink エンドポイント

僕がこの辺りの用語に疎いので、ドキュメントをそのまま引用します。
各 Aurora Serverless DB クラスターには、2 つの AWS PrivateLink エンドポイントが必要です。VPC 内の AWS PrivateLink エンドポイントが制限に達した場合、その VPC にそれ以上 Aurora Serverless クラスターを作成することはできません。
要は、VPCにサブネットを2つ以上用意しておく必要があります。
これも自分の場合は元々東京リージョンに3個持っていたので特に作業の必要はありませんでした。

3. セキュリティグループ

ドキュメントの通り、3306番のポートを利用するので、「インバウンド」で、3306番ポートが開通したセキュリティグループが必要になります。
セキュリティグループの設定画面で「タイプ」に「MYSQL/Aurora」を選択すると自動的に必要な設定が入るので作っておきます。

4. クライアント

実際の利用にはDBに接続するクライアントが必要です。
MySQLか、その互換のMariaDBクライアントが入ったインスタンスを同じVPC内に立てておきましょう。

さて、準備が終わった後、実際に DBを作成するのですが、これは簡単でした。
手順にすると多いですが画面に沿って進むだけなのでほぼ迷いません。

1. AWSのコンソールにログインし、RDSの管理画面に移動する。
2. [データベースの作成]をクリック
3. 標準作成を選択 (簡単作成でも良い)
4. エンジンのタイプ は [Amazon Aurora]を選択
5. エディション は [MySQLとの互換性を持つ Amazon Aurora]
6. MySQLのバージョンを選ぶ。
  これは、ドキュメントで指定されているバージョンでないと、次の選択肢からサーバレスが消えるので注意が必要です。

7. データベースの機能 は [サーバーレス]
8. DBクラスター識別子 は何か名前をつける。
9. マスターユーザー名 を指定 (デフォルトは admin)
10. パスワードの設定。 (自分はパスワードの自動作成にしました)
11. キャパシティーの設定を変更。(予算を抑えるため気持ち低めにしました。)
12. [データベースの作成]をクリック

ここまで進むとDBの作成が始まり、数分でDBが出来上がります。
出来上がったら、[認証情報の詳細を表示] から、 adminのパスワードを入手します。
また、同時に エンドポイント もわかるのでこれも記録しておきます。

DBが作成できたら、クライアントの環境から以下のコマンドで接続できます。


mysql -h {エンドポイント} -u {ユーザー名} -p

Enter password: 
と聞かれるのでパスワードを入力する。

ポートはデフォルトの3306を使っているので、 -P 3306 はつける必要ありません。(つけても大丈夫ですが。)

これで、通常のDBとして、使用できるようになりました。

もしDBが作成できているのに接続できなかった場合、セキュリティグループを見直してみてください。
(僕は用意していたセキュリティグループと違うグループが付与されていてしばらく詰まりました。)

あとは、残る課題はお値段ですね。
しばらく使ってみて、どのくらいの金額になるのか様子をみようと思います。

※ 以下、追記
2~3日ほど放置した後、様子を見たらメキメキと課金されていました。触っていない間も稼働しっぱなしだったようです。

設定項目の中に、「数分間アイドル状態のままの場合コンピューティング性能を一時停止する」
というがあり、これにチェックを入れないと、期待してた使っていない間は停止する効果が得られないようです。
てっきりデフォルトだと思っていたので危なかったです。
(請求金額アラートに救われました)

Amazon Comprehend でエンティティ認識

Amazon Comprehend シリーズの3記事目です。今回はエンティテイ認識をやってみます。
キーフレーズ抽出とかなりかぶるのですが、抽出した要素に対して人物なのか場所なのか時間なのかのフラグがつく点がメリットと言えるでしょう。

使うboto3のメソッドは、対象の文章が1つなら、detect_entities() で、
複数(ただし25個まで)なら batch_detect_entities()です。

比較のために前回の記事と全く同じテキストに対して実行してみました。


# サンプルテキスト。
# これで括弧内のテキストが連結されて1つの文字列になる。
text= (
    "メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。"
    "メロスには政治がわからぬ。メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。"
    "けれども邪悪に対しては、人一倍に敏感であった。"
    "きょう未明メロスは村を出発し、野を越え山越え、十里はなれた此のシラクスの市にやって来た。"
)

import boto3
comprehend = boto3.client("comprehend")
result = comprehend.detect_key_phrases(Text=text, LanguageCode="ja")

import boto3
comprehend = boto3.client("comprehend")

entities = comprehend.detect_entities(Text=text, LanguageCode="ja")
for entity in entities["Entities"]:
    print(entity)

"""
{'Score': 0.9998800754547119, 'Type': 'PERSON', 'Text': 'メロス', 'BeginOffset': 0, 'EndOffset': 3}
{'Score': 0.9998433589935303, 'Type': 'PERSON', 'Text': 'メロス', 'BeginOffset': 36, 'EndOffset': 39}
{'Score': 0.9998514652252197, 'Type': 'PERSON', 'Text': 'メロス', 'BeginOffset': 49, 'EndOffset': 52}
{'Score': 0.7808283567428589, 'Type': 'QUANTITY', 'Text': '人一倍', 'BeginOffset': 90, 'EndOffset': 93}
{'Score': 0.6928854584693909, 'Type': 'DATE', 'Text': '未明', 'BeginOffset': 104, 'EndOffset': 106}
{'Score': 0.9995416402816772, 'Type': 'PERSON', 'Text': 'メロス', 'BeginOffset': 106, 'EndOffset': 109}
{'Score': 0.506858766078949, 'Type': 'LOCATION', 'Text': '十里', 'BeginOffset': 124, 'EndOffset': 126}
{'Score': 0.9970796704292297, 'Type': 'LOCATION', 'Text': 'シラクス', 'BeginOffset': 132, 'EndOffset': 136}
{'Score': 0.6032651662826538, 'Type': 'LOCATION', 'Text': '市', 'BeginOffset': 137, 'EndOffset': 138}
"""

キーフレーズ抽出に比べて抽出された単語は少ないですが、 PERSON とか、 LOCATION といったTypeが付与されています。
ドキュメントによると、Typeは次の値を取りうる様です。

– ‘PERSON’
– ‘LOCATION’
– ‘ORGANIZATION’
– ‘COMMERCIAL_ITEM’
– ‘EVENT’
– ‘DATE’
– ‘QUANTITY’
– ‘TITLE’
– ‘OTHER’,

Amazon Comprehend でキーフレーズ抽出

前回の記事に続いて Amazon Comprehend の話です。
今度はキーフレーズ抽出をやってみます。

ドキュメントは同じところを参照します。
Comprehend — Boto3 Docs 1.14.32 documentation

Amazon Comprehend の特徴ページによると、
キーフレーズ抽出 API は、キーフレーズまたは会話のポイント、およびそれがキーフレーズであることを裏付ける信頼性スコアを返します。
とのことです。

早速やってみましょう。使うboto3のメソッドは、
detect_key_phrases() か、batch_detect_key_phrases()です。
それぞれ、単一テキストを対象とするか、テキストのリストを対象とするかの違いです。
ほとんど同じなので、今回は1テキストだけやってみることにしました。
サンプルにはいつのもメロスの最初の方の文章を使います。(全テキストで実行したら5000byteの制限によりエラーになりました。)


# サンプルテキスト。
# これで括弧内のテキストが連結されて1つの文字列になる。
text= (
    "メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。"
    "メロスには政治がわからぬ。メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。"
    "けれども邪悪に対しては、人一倍に敏感であった。"
    "きょう未明メロスは村を出発し、野を越え山越え、十里はなれた此のシラクスの市にやって来た。"
)

import boto3
comprehend = boto3.client("comprehend")
result = comprehend.detect_key_phrases(Text=text, LanguageCode="ja")

for key_phrase in result["KeyPhrases"]:
    print(key_phrase)

"""
{'Score': 0.9999992847442627, 'Text': 'メロス', 'BeginOffset': 0, 'EndOffset': 3}
{'Score': 0.5104176998138428, 'Text': 'かの', 'BeginOffset': 12, 'EndOffset': 14}
{'Score': 0.9680508971214294, 'Text': '邪智暴虐の王', 'BeginOffset': 14, 'EndOffset': 20}
{'Score': 0.9999995231628418, 'Text': 'メロス', 'BeginOffset': 36, 'EndOffset': 39}
{'Score': 0.9999402761459351, 'Text': '政治', 'BeginOffset': 41, 'EndOffset': 43}
{'Score': 0.9999988079071045, 'Text': 'メロス', 'BeginOffset': 49, 'EndOffset': 52}
{'Score': 0.9999657869338989, 'Text': '村の牧人', 'BeginOffset': 54, 'EndOffset': 58}
{'Score': 0.9999977350234985, 'Text': '笛', 'BeginOffset': 62, 'EndOffset': 63}
{'Score': 0.9999823570251465, 'Text': '羊', 'BeginOffset': 67, 'EndOffset': 68}
{'Score': 0.9975282549858093, 'Text': '人一倍', 'BeginOffset': 90, 'EndOffset': 93}
{'Score': 0.8310525417327881, 'Text': 'きょう未明', 'BeginOffset': 101, 'EndOffset': 106}
{'Score': 0.9997578263282776, 'Text': 'メロス', 'BeginOffset': 106, 'EndOffset': 109}
{'Score': 0.9997960925102234, 'Text': '村', 'BeginOffset': 110, 'EndOffset': 111}
{'Score': 0.9999336004257202, 'Text': '野', 'BeginOffset': 116, 'EndOffset': 117}
{'Score': 0.9991182088851929, 'Text': '十里', 'BeginOffset': 124, 'EndOffset': 126}
{'Score': 0.9819957613945007, 'Text': '此のシラクスの市', 'BeginOffset': 130, 'EndOffset': 138}
"""

ものすごく簡単に使えましたね。
一応重要な名詞は拾えてる様な気がしますし、王様は「邪智暴虐の王」として抽出できています。
ただ抽出したテキストだけなど意味がわからないので使い道に悩むところです。
BeginOffset と、 EndOffset は、その該当テキストを切り出すスライスに使える様です。

こんな感じです。


print(text[14: 20])
# 邪智暴虐の王

print(text[54: 58])
# 村の牧人

Amazon Comprehend でテキストのセンチメント分析

いつのまにか Amazon Comprehend の感情分析が日本語に対応しているのを見つけたので試してみました。

Amazon Comprehend というのは AWSが提供している自然言語処理の機械学習サービスです。
すでに学習済みのモデルが用意されており、利用者はデータを渡すだけで、感情分析(ポジネガ)や、キーフレーズの抽出ができます。

少し前までは日本語は言語判別のみ対応していて、センチメント分析するには一度対応してる言語に翻訳する必要があったはずなのですが、今は日本語も使えます。

ということで、Pythonからこれを動かしてみましょう。

・準備
AWSのPython SDKである boto3が動くように環境をつくっておきます。
主な作業は、 Comprehend の権限を持ったIAMの作成と、そのAccess Key と Secret Access Keyの設定でしょうか。
(僕は環境変数に入れました。)

これで動くはずなのでやってみます。
ドキュメントはこちらです。
Comprehend — Boto3 Docs 1.14.32 documentation

テキストは青空文庫の走れメロスを拝借しました。
まず、1文のポジネガを判定します。使うメソッドは、 detect_sentimentです。
本当に簡単に使えます。


import boto3

# 試すテキストを準備する
text1 = "メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。"
text2 = "メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。"

comprehend = boto3.client("comprehend")
for t in [text1, text2]:
    comprehend_result = comprehend.detect_sentiment(Text=t, LanguageCode="ja")
    print(t)
    print(comprehend_result["Sentiment"])
    for k, v in comprehend_result["SentimentScore"].items():
        print(f"    {k}: {v}")
    print()

# 以下出力結果
"""
メロスは激怒した。必ず、かの邪智暴虐の王を除かなければならぬと決意した。
NEGATIVE
    Positive: 0.00021381396800279617
    Negative: 0.8228716850280762
    Neutral: 0.17690636217594147
    Mixed: 8.087589776550885e-06

メロスは、村の牧人である。笛を吹き、羊と遊んで暮して来た。
NEUTRAL
    Positive: 0.0011265947250649333
    Negative: 6.331767508527264e-05
    Neutral: 0.9988085031509399
    Mixed: 1.5915205722194514e-06
"""

みて分かる通り、 Positive(肯定的)/ Negative(否定的)/ Neutral(中立的)/ Mixed(混在) の4つの感情の割合を返してくれます。

複数のテキストをまとめて判定する関数も用意されています。
それが、batch_detect_sentimentです。

A list containing the text of the input documents. The list can contain a maximum of 25 documents. Each document must contain fewer that 5,000 bytes of UTF-8 encoded characters.

とある通り、 25個までのテキスト(それぞれ5000バイト未満)を順番に判定してくれます。

走れメロスの中に登場する会話文を順番に判定かけてみましょう。

準備として、以下のコードでメロスの会話文の一覧を取得します。


import requests
from bs4 import BeautifulSoup
import re

# 青空文庫 走れメロスのURL
url = "https://www.aozora.gr.jp/cards/000035/files/1567_14913.html"
response = requests.get(url)
# 文字化け対応
response.encoding = response.apparent_encoding
html = response.text

soup = BeautifulSoup(html)

# ルビを取り除く
for tag in soup.findAll(["rt", "rp"]):
    # タグとその内容の削除
    tag.decompose()

# ルビを取り除いたテキストを取得
text = soup.find(class_="main_text").get_text()

# 改行を消す。
text = text.replace("\r\n", "")
text = text.replace("\n", "")
# 全角スペースを消す
text = text.replace("\u3000", "")

# カッコの内側の文字列を抽出する正規表現パターン
speech_pattern = re.compile("「([^「」]+)」")

# カッコの内側の文字列取得
speech_texts = speech_pattern.findall(text)

全部で62文あるので3回に分けて取得します。
結果は扱いやすい様にPandasのDataFrameに入れておきましょう。


import pandas as pd

sentiment_list = []
positive_list = []
negative_list = []
neutral_list = []
mixed_list = []

for i in range(3):
    target_texts = speech_texts[25*i: 25*(i+1)]
    comprehend_result = comprehend.batch_detect_sentiment(
        TextList=target_texts,
        LanguageCode="ja"
    )
    result_list = comprehend_result["ResultList"]

    for r in result_list:
        sentiment_list.append(r["Sentiment"])

        positive_list.append(r["SentimentScore"]["Positive"])
        negative_list.append(r["SentimentScore"]["Negative"])
        neutral_list.append(r["SentimentScore"]["Neutral"])
        mixed_list.append(r["SentimentScore"]["Mixed"])

# 結果をDataFrameに変換
df = pd.DataFrame(
    {
        "text": speech_texts,
        "sentiment": sentiment_list,
        "positive": positive_list,
        "negative": negative_list,
        "neutral": neutral_list,
        "mixed": mixed_list,
    }
)

こうして、走れメロスの全台詞に対してポジネガのフラグをつけることができました。
ちなみに最もポジティブだったセリフはこちらです。

text ありがとう、友よ。
sentiment POSITIVE
positive 0.998629
negative 1.88228e-05
neutral 0.00135026
mixed 1.96162e-06

そして、最もネガティブだったのがこれ。

text ‘もう、駄目でございます。むだでございます。走るのは、やめて下さい。もう、あの方をお助けになることは出来ません。
sentiment NEGATIVE
positive 0.000276001
negative 0.996889
neutral 0.00283329
mixed 1.40147e-06
Name: 46, dtype: object

全テキストの結果を見ていくと流石に「ん?」と思う様なものもあるのですが、
概ねしっかりと感情分析ができてる様に思います。

LightsailのMySQLに接続する

このブログはAWSのLightsailを使って構築しています。
ちょっと訳あって、そのサーバーのDB(MySQL)に接続したくなったのですが、
少しつまずいたのでメモです。

mysqlは勝手に構築してくれているので初期パスワードに何が設定されているのか、わかりませんでした。

結論から言うと
user : root
pass : bitnami_application_password ファイルの中身
で接続できます。
このwordpressの管理画面と同じ初期パスワードだったんですね。

わかるまで、サーバーにログインし、

\$ mysql
\$ mysql -u user
\$ mysql -u root
など試しましたが、ログインできず。

パスワードとして心当たりがあるのが管理画面のパスワードだけだったので、

\$ mysql -u root -p
とコマンドを打った後、bitnami_application_passwordの中身を入力したら接続できました。

念のため設定変えておこう。

Let’s Encrypt の証明書を自動更新する

このブログのhttps化のために導入したLet’s Encrypt の証明書ですが、90日ごとに期限が切れてしまうそうです。
更新手順が用意されていますが、毎回行うのは面倒なのでそれを自動化します。

手順は、証明書を導入した時と同じbitnamiのドキュメントの下の方にあります。
Generate And Install A Let’s Encrypt SSL Certificate For A Bitnami Application
これの Step 5: Renew The Let’s Encrypt Certificate がそれです。

rootユーザーにsuし、
/etc/lego/renew-certificate.sh
というファイルを作ります。中身はこれです。
ドキュメント中の”EMAIL-ADDRESS” と “DOMAIN” は自分のものに置き換える必要があります。


#!/bin/bash

sudo /opt/bitnami/ctlscript.sh stop apache
sudo /usr/local/bin/lego --email=メールアドレス --domains=analytics-note.xyz --path="/etc/lego" renew
sudo /opt/bitnami/ctlscript.sh start apache

スクリプトファイルを作成したら実行できるように権限を修正します。(ユーザーはrootで実行)


chmod +x /etc/lego/renew-certificate.sh

そして、このスクリプトを cronに設定します。
下記コマンドを実行して編集画面を起動。


sudo crontab -e

最終行に先ほど作ったスクリプトを登録して保存したら完了です。


0 0 1 * * /etc/lego/renew-certificate.sh 2> /dev/null

httpのアクセスをhttpsにリダイレクトする

せっかくhttps通信を使うように証明書を設定しましたが、そのままではhttpでもアクセスできてしまいます。
対応として、httpでアクセスがあったらhttpsのURLへリダイレクトするようにします。

これも人によって方法の流儀があるようですが、bitnami のドキュメントにそって設定します。

Force HTTPS Redirection With Apache

方法は簡単で、設定ファイルを書き換えてapachを再起動するだけです。

書き換える設定ファイルはこれ。
/opt/bitnami/apache2/conf/bitnami/bitnami.conf
DocumentRoot の設定の下に3行追加します。


<VirtualHost _default_:80>
  DocumentRoot "/opt/bitnami/apache2/htdocs"
  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteRule ^/(.*) https://analytics-note.xyz/$1 [R,L]
  <Directory "/opt/bitnami/apache2/htdocs">

設定したらapachを再起動。ちなみにコマンドはこちらです。


sudo /opt/bitnami/ctlscript.sh restart apache

あとは、httpのURLでアクセスして、httpsページが表示されたらOKです。
Chromの開発者ツールで通信をみるとリダイレクトされていることも確認できます。

LightsailのWordPressサーバーにLet’s Encryptの証明書を設定してhttps通信できるようにする

httpのままだと通信が安全でないなどの警告が出るため、https化を試みます。
本当は利用サービスをAWSに寄せていくため、AWS Certificate Managerを使いたくて、
色々調べていたのですが、結局ここで発行した証明書はサーバーに配置できないことがわかりました。
ロードバランサーに設定するそうですがロードバランサー自体がいいお値段するので断念し、
Let’s Encryptというのを利用することにしました。

各所で色々な人が手順を書いていくれていて、微妙に異なるので正しい手順がわからず混乱していたのですが、
bitnami の公式ドキュメントに、Let’s Encryptを使う手順がありますしたのでここの手順を採用します。

Generate And Install A Let’s Encrypt SSL Certificate For A Bitnami Application

ただし、ドキュメント場では下記のスクリプトを使えば簡単なように書いてありますが、Lightsailのサーバーにはこのファイルが無かったので、代替手順(Alternative Approach)の方を採用します。
/opt/bitnami/letsencrypt/scripts/generate-certificate.sh

注意点としては、X.Y.Zを最新のバージョン番号に読み替えるとか、DOMAINやEMAIL-ADDRESSを正しいものに読み替えて実行することと、
自分の場合は wwwのサブドメインを使っていないので、コマンドに含めないようにすることでしょうか。

Lego Client のインストール

サーバーにssh接続して下記コマンドを入れます。


cd /tmp
curl -s https://api.github.com/repos/xenolf/lego/releases/latest | grep browser_download_url | grep linux_amd64 | cut -d '"' -f 4 | wget -i -
# ドキュメント場の記載
# tar xf lego_vX.Y.Z_linux_amd64.tar.gz
# 実際は、curlで取得されたファイルに合わせて、バージョン番号を入れる
tar xf lego_v1.2.1_linux_amd64.tar.gz
sudo mv lego /usr/local/bin/lego

自分のドメインの証明書を作成する

Bitnami servicesを全て止める


sudo /opt/bitnami/ctlscript.sh stop

legoを実行。


# ドキュメントの記載
# sudo lego --email="EMAIL-ADDRESS" --domains="DOMAIN" --domains="www.DOMAIN" --path="/etc/lego" run
# 実際に打ったコマンド(ただしメールアドレスは伏せます)
sudo lego --email=メールアドレス --domains=analytics-note.xyz --path="/etc/lego" run

証明書を利用するようにサーバーを設定する

Apache用の手順を使用します。


sudo mv /opt/bitnami/apache2/conf/server.crt /opt/bitnami/apache2/conf/server.crt.old
sudo mv /opt/bitnami/apache2/conf/server.key /opt/bitnami/apache2/conf/server.key.old
sudo mv /opt/bitnami/apache2/conf/server.csr /opt/bitnami/apache2/conf/server.csr.old
# sudo ln -s /etc/lego/certificates/DOMAIN.key /opt/bitnami/apache2/conf/server.key
sudo ln -s /etc/lego/certificates/analytics-note.xyz.key /opt/bitnami/apache2/conf/server.key
# sudo ln -s /etc/lego/certificates/DOMAIN.crt /opt/bitnami/apache2/conf/server.crt
sudo ln -s /etc/lego/certificates/analytics-note.xyz.crt /opt/bitnami/apache2/conf/server.crt
sudo chown root:root /opt/bitnami/apache2/conf/server*
sudo chmod 600 /opt/bitnami/apache2/conf/server*

お恥ずかしながら、DOMAIN.key や DOMAIN.crtのDOMAIN を見落とし、置き換えないまま実行してしばらくここで詰まりました。

Bitnami servicesを再開


sudo /opt/bitnami/ctlscript.sh start

アクセステスト

https://analytics-note.xyz/
にアクセスします。
正常につながったのでOKです。

一旦設定は完了ですが、このままでは、
httpでも普通にアクセスできてしまうのと、
数ヶ月おきに証明書の有効期限が切れる問題があるのでそれぞれ対応します。