Ubuntu

ローカル環境でRoRチュートリアルを学習する環境を手軽に作る

Ruby on Railsチュートリアル第7版を3ヶ月以上掛けて完走した。したけれども、途中から演習を飛ばしてしまっているし、集中できていなかったから理解しているとは言いがたい感じ。これは、もう一周しなければ。



広告


色々と周囲の準備はできていたので、ローカルにUbuntu 22.04 serverを用意して、一周目からすべて自前の環境で試した。
コーディングもVimでやっていて、それで全然問題はないのだけれども、Visual Studio Codeはだいぶ便利なようだし、GiteaやKopanoもあるからUbuntuにセットアップすれば、かなり良い環境で学習ができそうだ…

ということで、これらを備えた環境を作ってみようと思う。

これから構築する環境

メインPCは10年以上アップグレードを繰り返して使っているので、相応に汚れていると思われる。でも、壊したくない。
こんな理由から、好きなときに作って、好きなときに捨てられる環境を、仮想PCで作成しようと思う。

使用するPC

メインPCで、Windows 11 Proが動いている。

ここに、VMwareで仮想マシンを作り、Ubuntu 22.04 desktopを動かそうと考えた。
この手順が整理できれば、Hyper-Vでも似たようなやり方でいけると思っている。

項目設定値
CPU2個
メモリー4GB
HDD30GB
ネットワークNAT

ちなみに、セットアップが終わって色々やっていたら、ディスク使用量が19GB程になった。
多少余裕を持たないとシステムが安定動作しないので、30GB程度は与えておいた方が良い。

最初、HDDのサイズをデフォルトの20GBで作成してしまい容量が足りなくなったので、こちらの手順でディスク容量を増やしている

できあがる環境

ブラウザはChrome(またはEdge、Firefoxももちろん使える)。
Gitサーバー(Gitea)にはブラウザでアクセスができて、sshで操作ができる。
グループウェア(Kopano)も使えるようになっており、アプリケーションからメール送信をすれば、ブラウザでそれを見ることができる。※ただし、外にメールは出さない、この環境で閉じている。
コーディングにはVisual Studio Codeが使える。

システム構成を図解すると、このような形になる。

           ┌───────────────┐
           │         [ Tutorial ]         │
           │Chrome/Edge/Visual Studio Code│
           └───────┬───────┘
     ┌─────────────┴──────────────┐
┌────┴───┐                        │
│Apache(Proxy)   ├───┬──────┬──────┐      │
│SSH(Passthrough)│   │      │      │      │
└────────┘┌──┴──┐┌──┴──┐┌──┴──┐┌──┴───┐
          │Kopano    ││Gitea     ││MariaDB   ││PostgreSQL  │
          │Groupware ││Git server││DB server ││for Tutorial│
          └──┬──┘└──┬──┘└──┬──┘└──────┘
             └──────┴──────┘
          ├──── docker compose (1) ─────┤├─  (2) ──┤
          ┌───────────────────────────┐
          │                        Docker                        │
          └───────────────────────────┘
┌─────────────────────────────────────┐
│                          Ubuntu 22.04 desktop                            │
├─────────────────────────────────────┤
│                        VMware Workstation Player                         │
└─────────────────────────────────────┘

OSのセットアップ

Ubuntu 22.04 desktop

この日ダウンロードしたのは、ubuntu-22.04.2-desktop-amd64.iso。
これを手動インストールしていく。

もし、UEFIにしたい場合は、仮想マシンを作成した直後(仮想マシンを起動する前)に以下の記述を追加。

仮想マシン名.vmx

firmware = "efi"
efi.legacyBoot.enabled = "FALSE"
uefi.secureBoot.enabled = "TRUE"
ulm.disableMitigations="TRUE"
disk.EnableUUID = "TRUE"

※やらなくても全然OK。

最小構成でインストールしたこともあって、5分ほどで完了した。

再起動する際に設定を開いて、CD/DVD(SATA)の「起動時に接続」チェックを外しておいた。

再起動して、アップデートをインストールして、インストール完了。
最小構成だったこともあってか、アップデートも程なく終了している。

この時点で、ディスク使用量は12GBほどになっている。

電源管理

デフォルトでは、5分間操作がないとブランクスクリーンになり、画面がロックされる。

ロック解除のためにはパスワード入力が必要なのだが、時間が短すぎて不便。
適切に長くするか、ブランクにしない設定にしておくのが良いのではないかと思う。

Dash(左下の9個のドット)をクリックし、設定を選択すると、設定アプリが起動する。

左ペインから電源管理を選択し、画面のブランクが「5分」になっているのを、適切な時間に設定する。
ここでは、「しない」を選択している。

日本語入力

インストール時に、日本語環境・日本語キーボードを選択しているので、日本語入力はできる。
でも、ログイン直後には「日本語」が選択されており、「日本語(Mozc)」に切り替える必要がある。
→ [Super]+[Space]で切り替え。この[Super]はWindowsキー。

これが面倒なので、最初に「日本語(Mozc)」が選択されるようにしたいと思ったのだが…若干バグっぽかった。

設定アプリの左ペインでキーボードを選択し、順序を入れ替えてみた。

再起動してみたが、「日本語」が選択されていた。

そこで、一度「日本語」を消してみた。

これで再起動したところ、日本語入力ができなくなった。

そこで、改めて「日本語」を追加した。

これで再起動したところ、最初に「日本語(Mozc)」が選択されるようになった。
現在選択されているキーボードが変わったことは、画面右上にある「Ja」と表示されていたところが「A」に変わっていることで確認ができる。

Docker

これをOSのセットアップに入れるのはちょっと違うかもしれないが、この先Dockerでサービスをインストールするので、ここでセットアップしておくことにする。

まず、端末を開き([CTRL]+[ALT]+[T])、いったん、パッケージを更新しておく。

$ sudo apt update; sudo apt -y dist-upgrade; sudo apt -y autoremove

公式のセットアップ手順はここに書かれており、それを見て実施するのが一番。
やることだけに絞るとこんな感じではある。

$ sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
$ docker -v
Docker version 23.0.5, build bc4487a
$ docker compose version
Docker Compose version v2.17.3

※バージョンは実行した日のもの。実行した時点の新しいバージョンがインストールされる。

この時点で、ディスク使用量は13GBほどになっている。

ブラウザのセットアップ

探し物をするにも、テストをするにもブラウザが必要。
Firefoxが入っているので、それを使う場合はこのセクションを飛ばしてOK。

Google Chrome

日頃Chromeを使用しているので、ブックマークの同期やらなんやら便利なので、インストールする。
Firefoxを開き、「chrome download」を検索して、Googleからパッケージをダウンロードしてインストールする。

このインストール操作で、aptに以下のファイルが追加され、アップデートができるようになる。

/etc/apt/sources.list.d/google-chrome.list

deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main

初回起動時に問いかけがあるので答えて起動しつつ、ランチャーに登録するためお気に入りに追加する。

この時点で、ディスク使用量は13GBほどになっている。

Microsoft Edge

日頃Microsoft Edgeを使用している方もいるだろう。
Firefoxを開き、「microsoft edge download」を検索して、Microsoftからパッケージをダウンロードしてインストールする。

少し分かりづらいけれども、下の方に行くと Linux(.deb) のリンクがあるので、そこからダウンロードができる。

このインストール操作で、aptに以下のファイルが追加され、アップデートができるようになる。

/etc/apt/sources.list.d/microsoft-edge.list

deb [arch=amd64] https://packages.microsoft.com/repos/edge/ stable main

初回起動時に問いかけがあるので答えて起動しつつ、必要ならMicrosoftアカウントを設定。
ランチャーに登録するなら、お気に入りに追加する。

この時点で、ディスク使用量は14GBほどになっている。

デフォルトのアプリケーション

デフォルトのアプリケーションにChromeやEdgeを設定するには、設定アプリを起動し、左ペーンのデフォルトアプリを選択する。
ウェブの項目でChrome、または、Edgeを選択すればOK。

エディターのセットアップ

Vim

使いこなせているとはいえないが、Linuxをさわりはじめて以降ずっとVimを使ってきたので、あると安心。

Ubuntu Software というアプリを起動し、左上の虫眼鏡マークをクリックして、vim と入力。
最初の検索には少し時間が掛かる。

GUIの方はGVimという名前でエントリーされているので、これを選択してインストール。
インストールボタンを押すと、認証を求められるので、パスワードを入力する。

このインストール作業で、CUIの方もSmallからHugeに変わるので、CUIでもVimの便利な機能が使えるようになっている。

GVimインストール前

$ vi --version
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Apr 03 2023 07:45:49)
Included patches: 1-3995, 4563, 4646, 4774, 4895, 4899, 4901, 4919
Modified by team+vim@tracker.debian.org
Compiled by team+vim@tracker.debian.org
Small version without GUI.  Features included (+) or not (-):
+acl               -file_in_path      -mouse_urxvt       -tcl
…

GVimインストール後

$ vi --version
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Apr 03 2023 07:45:49)
適用済パッチ: 1-3995, 4563, 4646, 4774, 4895, 4899, 4901, 4919
Modified by team+vim@tracker.debian.org
Compiled by team+vim@tracker.debian.org
Huge 版 with GTK3 GUI.  機能の一覧 有効(+)/無効(-)
+acl               +file_in_path      +mouse_urxvt       -tag_any_white
…

この時点で、ディスク使用量は14GBほどになっている。

Visual Studio Code

Ubuntu Softwareでcodeをインストールすることもできる。この場合はsnap版がインストールされる。

「visual studio code download」で検索し、code.visualstudio.comにアクセスする。
そこで、.dev x64をクリックしてダウンロードしてインストールする。ChromeやEdgeの時とやっていることは同じだが、Chromeで操作しているので、少し操作が異なっている。

日本語化するには、拡張機能の言語パックをインストールすれば良いようだ。
JavaDrive / Visual Studio Codeを日本語化する

この時点で、ディスク使用量は14GBほどになっている。

各種サービスのセットアップ

当初、設定に関わる様々な手順を書いていたのだけれど、自分でもすべての手順をこなすのに時間が掛かるように思えてきた…だったら、手順を全部スクリプトにしてしまえ!と考えた。

環境を作るために一直線、エラーチェックなんか全然しないスクリプト。
その代わりに、手作業をあれこれやるよりだいぶ早い。

途中で秘密鍵のパスフレーズを入れたり入れなかったりしているので、注意深く進める必要はある。

エラーチェックをしないことは良くないことだけれど、上手くいかなかったときにはきれいに戻せるスクリプトも作って、何度でもやり直せるようにすることで、割り切った。まぁ、そのきれいに戻せるスクリプトも、エラーチェックなんか全然しないわけだけれども。

この章で「詳細説明」と記したセクションは、スクリプトの中身を説明しているだけなので、何か問題でも発生しない限りは読む必要なし。

スクリプトはこちらで公開している。
https://gitea.rohhie.net/rohhie/rorenv

スクリプトはDockerエンジンがインストールされていることが前提なので注意。

この手順が完了した時点で、ディスク使用量は16GBほどになっている。

スクリプトの実行

操作

端末を起動([CTRL]+[ALT]+[T])し、以下のコマンドを実行して、構築に必要なファイルを含むリポジトリをローカルにコピーする。

$ git clone https://gitea.rohhie.net/rohhie/rorenv.git

rorenvディレクトリに移動して、スクリプトを起動する。

$ cd rorenv
$ ./01-setup.sh
[sudo] hoge のパスワード: [パスワード][Enter]

処理に時間が掛かった場合、途中で[sudo]によりパスワードを求められる場合があるかもしれない。
その時には、Ubuntuにログインする際に使用するアカウントのパスワードを入力する。

2023/05/28 追記
セットアップヘルパーを作成した。expectコマンドを使用し、多くの場所で入力を自動化している。
これを利用する場合は、01-setup.shではなく、00-setup-helper.shを使用する。

$ cd rorenv
$ sudo apt -y install expect
$ ./00-setup-helper.sh
[sudo] hoge のパスワード: [パスワード][Enter]

このスクリプトを作成するにあたり、この投稿を参考にさせていただきました。
ありがとうございます。
stack overflow / Enter sudo password while in expect script

プライベート認証局の作成

操作

プライベート認証局(Private CA / Private Certificate Authority)を作成する。
この認証局が作成する証明書を使って、ブラウザでSSLアクセスができるようになる。
また、Giteaはメールを送信するときにTLSでその証明書が正しいことを要求するので、そこでも使用している。

================================================
  認証局の作成
================================================
CA certificate filename (or enter to create)
[Enter]
Making CA certificate ...
==== ※ここで、認証局の秘密鍵と証明書署名要求が作られる
openssl req -config ./openssl.cnf -new -keyout ./exampleCA/private/cakey.pem -out ./exampleCA/careq.pem 
..+...+.........+.+...........+...+.+..............+.+......+...+...........+....+........+............+
 <省略>
...........+......+.....+....+.....+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Enter PEM pass phrase:[認証局の秘密鍵のパスフレーズ][Enter]
Verifying - Enter PEM pass phrase:[同じパスフレーズ][Enter]
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [JA]:[Enter]
State or Province Name (full name) [Tokyo]:[Enter]
Locality Name (eg, city) [Chiyoda]:[Enter]
Organization Name (eg, company) [Example Networks Inc.]:[Enter]
Organizational Unit Name (eg, section) []:[Enter]
Common Name (e.g. server FQDN or YOUR name) [example.net]:[Enter]
Email Address [webmaster@example.net]:[Enter]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:[Enter]
An optional company name []:[Enter]
==> 0
====
==== ※ここで、自分が作成した認証局の署名要求に、自分の秘密鍵で署名する
openssl ca -config ./openssl.cnf -create_serial -out ./exampleCA/cacert.pem -days 10950 -batch -keyfile ./exampleCA/private/cakey.pem -selfsign -extensions v3_ca -infiles ./exampleCA/careq.pem 
Using configuration from ./openssl.cnf
Enter pass phrase for ./exampleCA/private/cakey.pem:[上で入力した認証局の秘密鍵のパスフレーズ][Enter]
Check that the request matches the signature

Signature ok
Certificate Details:
        Serial Number:
            49:b4:f2:4f:e4:7d:a0:cb:27:d4:78:6f:be:58:af:92:56:fd:af:e2
        Validity
            Not Before: Apr 27 23:13:50 2023 GMT
            Not After : Apr 19 23:13:50 2053 GMT
        Subject:
            countryName               = JA
            stateOrProvinceName       = Tokyo
            organizationName          = Example Networks Inc.
            commonName                = example.net
            emailAddress              = webmaster@example.net
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                92:2C:8A:30:EA:FB:12:DC:DB:9E:4D:1D:8E:5F:66:00:35:8A:73:B1
            X509v3 Authority Key Identifier: 
                92:2C:8A:30:EA:FB:12:DC:DB:9E:4D:1D:8E:5F:66:00:35:8A:73:B1
            X509v3 Basic Constraints: critical
                CA:TRUE
Certificate is to be certified until Apr 15 00:48:04 2053 GMT (10950 days)

Write out database with 1 new entries
Data Base Updated
==> 0
====
CA certificate is in /home/hoge/rorenv/SSL/exampleCA/cacert.pem



=== 同じ宛先の署名要求に署名できるようにする



=== CA証明書部分を切り出す



=== OSにCA証明書を登録
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

詳細説明

プライベート認証局は、SSLディレクトリのexampleCAに作成している。

SSL/
├─ CA.pl
├─ exampleCA/
│   ├─ cacert.pem
│   ├─ careq.pem
│   ├─ certs/ ※後にここでSSL証明書を作成する
│   ├─ crl/
│   ├─ crlnumber
│   ├─ example.net.ca.crt ※cacert.pemから証明書部分を切り出したもの
│   ├─ index.txt
│   ├─ index.txt.attr
│   ├─ index.txt.old
│   ├─ newcerts/
│   │   └─ 49B4F24FE47DA0CB27D4786FBE58AF9256FDAFE2.pem ※cacert.pemと同じもの
│   ├─ private/
│   │   └─ cakey.pem ※プライベート認証局の秘密鍵で署名するときに使う重要なファイル
│   └─ serial
└─ openssl.cnf

スクリプト内部では、以下を実行している。

SCRIPTHOME=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
export SSLHOME=$SCRIPTHOME/SSL
cd $SSLHOME
./CA.pl -newca

このディレクトリで正しく動作するように、環境変数SSLHOMEにCA.plを実行するベースとなるディレクトリをフルパスで設定している。そして、CA.plや、openssl.cnfでもこのSSLHOMEを参照するようにして、ベースとなるディレクトリを整合させている。
そのため、新たに証明書に関わる操作をするときには、

$ SSLHOME=/home/hoge/rorenv/SSL CA.pl -piyo

等の方法で、環境変数SSLHOMEにベースとなるディレクトリを設定すること。
※hogeは自分のユーザー名、piyoはどんな操作をしたいのかを表すパラメーターに置き換える。

CA.plについて、CAのデフォルト値や、CAの有効期間(30年)、証明書の有効期間(10年)を変更している。
(CA.plには、OpenSSL ProjectによりApache License 2.0が適用されている。今回の配布物もこれに従う。)

~/SSL/CA.pl

…
my $openssl = $ENV{'OPENSSL'} // "openssl";
$ENV{'OPENSSL'} = $openssl;
my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // "-config $ENV{'SSLHOME'}/openssl.cnf";
…
# Default values for various configuration settings.
my $CATOP = "$ENV{'SSLHOME'}/exampleCA";
my $CAKEY = "cakey.pem";
my $CAREQ = "careq.pem";
my $CACERT = "cacert.pem";
my $CACRL = "crl.pem";
my $DAYS = "-days 3650";         # 10 years
my $CADAYS = "-days 10950";      # 30 years
my $NEWKEY = "newkey.pem";
…

※赤文字部分を追加・変更。

設定ファイルも一部変更し、コマンド実行時にそれっぽいデフォルト値が入るようにしている。

~/SSL/openssl.cnf

…
[ CA_default ]

dir             = $ENV::HOME/SSL/exampleCA      # Where everything is kept
certs           = $dir/certs            # Where the issued certs are kept
crl_dir         = $dir/crl              # Where the issued crl are kept
database        = $dir/index.txt        # database index file.
unique_subject  = no                    # Set to 'no' to allow creation of
…
default_days    = 3650                  # how long to certify for
…

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
countryName_default             = JA
countryName_min                 = 2
countryName_max                 = 2

stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default     = Tokyo

localityName                    = Locality Name (eg, city)
localityName_default            = Chiyoda

0.organizationName              = Organization Name (eg, company)
0.organizationName_default      = Example Networks Inc.

# we can do this but it is not needed normally :-)
#1.organizationName             = Second Organization Name (eg, company)
#1.organizationName_default     = World Wide Web Pty Ltd

organizationalUnitName          = Organizational Unit Name (eg, section)
#organizationalUnitName_default =

commonName                      = Common Name (e.g. server FQDN or YOUR name)
commonName_default              = example.net
commonName_max                  = 64

emailAddress                    = Email Address
emailAddress_default            = webmaster@example.net
emailAddress_max                = 64
…

※赤文字部分を追加・変更。

スクリプト内部では、さらに、署名されたCA証明書のファイルから、証明書部分だけを切り出している。

sed -n "/-----BEGIN/,/CERTIFICATE-----/p" exampleCA/cacert.pem > exampleCA/example.net.ca.crt

OSに対してこの証明書をWindowsでいうところの「信頼されたルート証明機関」として登録している。

sudo cp exampleCA/example.net.ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

SSL証明書の作成

操作

SSL証明書を作成するために、証明書署名要求を作成する。
証明書署名要求を作成するためには秘密鍵が必要だが、このコマンドでは自動的に生成される。

生成する秘密鍵にはパスフレーズを設定する(ここではパスフレーズなしにはできない)。
認証局の秘密鍵とは別物だけれども、同じパスフレーズを使うこともできる。テスト環境なので割り切ってもいい。

================================================
  SSL証明書の作成
================================================

=== 証明書署名要求の作成
Use of uninitialized value $1 in concatenation (.) or string at /home/hoge/rorenv/SSL/CA.pl line 145.
====
openssl req -config /home/hoge/rorenv/SSL/openssl.cnf -new  -keyout newkey.pem -out newreq.pem -days 3650 
Ignoring -days without -x509; not generating a certificate
..+...+.........+.+...........+...+.+..............+.+......+...+...........+....+........+............+
 <省略>
...........+......+.....+....+.....+...+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Enter PEM pass phrase:[SSL証明書とセットになる秘密鍵のパスフレーズ][Enter]
Verifying - Enter PEM pass phrase:[同じパスフレーズ][Enter]
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [JA]:[Enter]
State or Province Name (full name) [Tokyo]:[Enter]
Locality Name (eg, city) [Chiyoda]:[Enter]
Organization Name (eg, company) [Example Networks Inc.]:[Enter]
Organizational Unit Name (eg, section) []:[Enter]
Common Name (e.g. server FQDN or YOUR name) [example.net]:[Enter]
Email Address [webmaster@example.net]:[Enter]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:[Enter]
An optional company name []:[Enter]
==> 0
====
Request is in newreq.pem, private key is in newkey.pem

続いて、認証局で証明書署名要求に署名する。
署名には認証局の秘密鍵を使うので、認証局の秘密鍵のパスフレーズを入力する。

=== CAで署名
====
openssl ca -config /home/hoge/rorenv/SSL/openssl.cnf -policy policy_anything -out newcert.pem -infiles newreq.pem 
Using configuration from /home/hoge/rorenv/SSL/openssl.cnf
Enter pass phrase for /home/hoge/rorenv/SSL/exampleCA/private/cakey.pem:[認証局の秘密鍵のパスフレーズ][Enter]
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            49:b4:f2:4f:e4:7d:a0:cb:27:d4:78:6f:be:58:af:92:56:fd:af:e3
        Validity
            Not Before: Apr 27 23:15:24 2023 GMT
            Not After : Apr 26 23:15:24 2033 GMT
        Subject:
            countryName               = JA
            stateOrProvinceName       = Tokyo
            localityName              = Chiyoda
            organizationName          = Example Networks Inc.
            commonName                = example.net
            emailAddress              = webmaster@example.net
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                09:81:B2:60:93:B9:A3:11:FF:D3:3E:B7:D9:81:C2:F5:D0:AA:A6:4B
            X509v3 Authority Key Identifier: 
                92:2C:8A:30:EA:FB:12:DC:DB:9E:4D:1D:8E:5F:66:00:35:8A:73:B1
            X509v3 Subject Alternative Name: 
                DNS:example.net, DNS:*.example.net
Certificate is to be certified until Apr 22 01:40:21 2024 GMT (365 days)
Sign the certificate? [y/n]:y[Enter]


1 out of 1 certificate requests certified, commit? [y/n]y[Enter]
Write out database with 1 new entries
Data Base Updated
==> 0
====
Signed certificate is in newcert.pem

最後に、SSL証明書とセットになる秘密鍵のパスフレーズを削除する。
Apacheを起動する度に秘密鍵のパスフレーズを入力する必要があるが、それはだいぶ大変なのでパスフレーズを削除しておく。

=== SSL証明書部分を切り出す



=== 秘密鍵からパスフレーズを削除
Enter pass phrase for newkey.pem:[SSL証明書とセットになる秘密鍵のパスフレーズ][Enter]



=== SSL証明書と秘密鍵を配置

詳細説明

SSL証明書を作る時、

  • Webサイトの管理者が証明書署名要求(CSR)を発行して、認証局に提出する。
  • 認証局がCSRをもとに証明書を作成し、に署名する。

という手順を踏む。

一方で、証明書をください、とだけいわれるパターンも結構ある。
こういう要望にも上手く対応ができるよう、情報を別の方法で受け取ったり、証明書に設定する値を固定したりして、運用されている。この時には、認証局でCSRを作成して署名する。
今回の手順はこの方式を採っている。

この操作で、以下のようなディレクトリとファイルが生成される。※抜粋

SSL/
├─ exampleCA/
│   ├─ certs/
│   │   └─ 202304230948_wildcard.example.net/
│   │       ├─ newkey.pem  ※証明書署名要求を作成するために作られる秘密鍵
│   │       ├─ newreq.pem  ※証明書署名要求
│   │       ├─ newcert.pem ※CAで署名した証明書
│   │       ├─ wildcard.example.net.crt ※CAで署名した証明書から証明書部分を切り出したもの
│   │       └─ wildcard.example.net.key ※秘密鍵からパスフレーズを削除して生成したもの
│   ├─ newcerts/
│   │   ├─ 49B4F24FE47DA0CB27D4786FBE58AF9256FDAFE2.pem
│   │   └─ 49B4F24FE47DA0CB27D4786FBE58AF9256FDAFE3.pem ※newcert.pemと同じファイル

※202304230948は、スクリプトを実行した年月日時分で付けている。

スクリプト内部では、以下を実行している。

ちゃんと調べたわけではないのだけれど、今まで認証局を運用している経験では、certsディレクトリには何も作られることがない。ということで、証明書関連の作業用ディレクトリとして使って良いと解釈。
日付+目的でディレクトリを作りそこで作業をする。管理簿を作るのはメンドクサイし…

SSLCERTDIR=$(date +%Y%m%d%H%M)_wildcard.example.net
mkdir $SSLCERTDIR
cd $SSLCERTDIR

このディレクトリで、証明書署名要求を作成する。

$SSLHOME/CA.pl -newreq

※この改造したCA.plを意図通りに動かすために、環境変数SSLHOMEを新設。OPENSSL_CONFIGとも使い方がちょっと違うので。

そして、認証局で署名する。

$SSLHOME/CA.pl -sign

署名した証明書から、証明書部分だけを切り出したファイルを作る。

sed -n "/-----BEGIN/,/CERTIFICATE-----/p" newcert.pem > wildcard.example.net.crt

秘密鍵を読み込んで、パスフレーズを再設定する。
ユーザーにはパスフレーズを入れずに[Enter]を押してもらう想定。

openssl pkey -in newkey.pem -out wildcard.example.net.key

最後に、できあがった秘密鍵とSSL証明書を /etc/ssl/private に配置する。

sudo cp wildcard.example.net.crt /etc/ssl/private
sudo cp wildcard.example.net.key /etc/ssl/private

なお、SSL証明書を作るにあたっては、X509v3 extensions に Subject Alternative Name の指定が必要なので、その設定がしてある。

~/SSL/openssl.cnf

…
[ req ]
default_bits            = 2048
…
req_extensions = v3_req # The extensions to add to a certificate request ※先頭の#を外して有効化
…

[ usr_cert ]

# These extensions are added when 'ca' signs a request.

# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.

basicConstraints=CA:FALSE

# This is typical in keyUsage for a client certificate.
# keyUsage = nonRepudiation, digitalSignature, keyEncipherment

# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer

# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
# subjectAltName=email:move
subjectAltName=@v3_altname # CAで署名するときに使われる
…

[ v3_req ]

# Extensions to add to a certificate request

basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName=@v3_altname # リクエストを作成するときに使われる

[ v3_altname ]
# リクエストする時にも、CAで署名するときにも同じ値が使われるので、同じ名前で定義している
DNS.1=example.net
DNS.2=*.example.net

※赤文字部分を追加・変更。
※サーバーの運営者からCSRを受け取ったら、その中身を確認して、[v3_req_altname]セクションの中身をあわせる。この操作は今回の記事の範囲を超えるので、詳しく知りたい場合には過去記事参照(内容は少し怪しいものの、大体合っているので)。

Apacheの設定

操作

なし。

詳細説明

スクリプト内部では、以下を実行している。

Apacheのインストール。

sudo apt -y install apache2

デフォルトのサイトを無効化する。

sudo a2dissite 000-default

あらかじめ用意している以下のサイト設定をコピーして、有効化する。

  • example.netとして、ポート3000番で動くRailsアプリにProxyするサイト。
  • mail.example.netとして、Kopanoを動作させるサイト。
  • git.example.netとして、Giteaを動作させるサイト。
  • test.example.netとして、/var/www/testディレクトリに置いたファイルを表示するサイト。
sudo cp apache/*.conf /etc/apache2/sites-available/
sudo a2ensite example.net gitea kopano

サイトで利用する追加機能を有効化する。

sudo a2enmod ssl rewrite proxy_http headers http2

debian系のApacheで出力される警告を止めるための設定ファイルを作成して、有効化する。

echo "ServerName localhost" | sudo tee /etc/apache2/conf-available/fqdn.conf > /dev/null
sudo a2enconf fqdn

設定変更を反映するため、Apacheを再起動する。

sudo systemctl restart apache2

git接続設定の構成

操作

最初にパッケージsshがインストールされる(表示がかなり進んでしまうので、「git接続設定の構成」というメッセージが見づらいので注意)。

Giteaに接続する際に利用する公開鍵・秘密鍵のセットを生成する。
パスフレーズなしが便利(鍵を大切に保管する代わりに、使用するときにはパスフレーズが要らないスタイル)。

================================================
  git接続設定の構成
================================================
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています... 完了        
<省略>
Generating public/private ed25519 key pair.
Created directory '/home/hoge/.ssh'.
Enter passphrase (empty for no passphrase): [Enter]
Enter same passphrase again: [Enter]

詳細説明

スクリプト内部では、以下を実行している。

SSHサーバーのインストール。

sudo apt -y install ssh

Giteaに接続する際に利用する公開鍵・秘密鍵のセットを生成。
このとき、パスフレーズの入力が求められるが、何も入力せずに[Enter]が押されることを期待している。

ssh-keygen -t ed25519 -C "$(whoami) git key" -f ~/.ssh/git-key

Giteaに接続するための設定を ~/.ssh/config に書く。これによって、接続時に秘密鍵のファイルがどうとか、ユーザーが誰とかいった指定が省略できる。

cat <<EOF >> ~/.ssh/config
host git.example.net
        HostName        git.example.net
        User            $(whoami)
        IdentityFile    ~/.ssh/git-key
EOF

ユーザーgitの作成

操作

gitというユーザーで接続を受けると、Giteaにパススルーする仕組みを作る。
ここでは、そのgitユーザーが使用する公開鍵・秘密鍵のセットを作成している。

================================================
  ユーザーgitの作成
================================================
=== UID/GIDの書き換え
=== gitの証明書の作成
Generating public/private rsa key pair.
Created directory '/home/git/.ssh'.
Enter passphrase (empty for no passphrase): [Enter]
Enter same passphrase again: [Enter]

詳細説明

スクリプト内部では、以下を実行している。

ユーザーgitの作成。

sudo useradd -m git

UIDとGIDを docker-compose.yml に反映させる。

sed -i "s/\(- USER_UID=\)[[:digit:]]\+/\1$(id -u git)/" docker/docker-compose.yml
sed -i "s/\(- USER_GID=\)[[:digit:]]\+/\1$(id -g git)/" docker/docker-compose.yml

さらに、ユーザーgitが2222/tcpで待ち受けているGiteaに接続ができるよう、公開鍵・秘密鍵のセットを作成。
また、接続用の設定を入れる。

sudo -u git ssh-keygen -t rsa -b 4096 -C "Gitea Host Key" -f /home/git/.ssh/id_rsa
sudo -u git cp /home/git/.ssh/id_rsa.pub /home/git/.ssh/authorized_keys
sudo -u git chmod 600 /home/git/.ssh/authorized_keys

※Ubuntu 22.04の場合、SSH接続は標準でrsaの鍵が使えなくなっているはずだから、これで接続はできないはず。

ユーザーがGiteaで公開鍵を設定すると、その公開鍵がパススルー用のコマンドと共に保管されるとのこと。
なので、接続されると2222/tcpに向けてそのコマンドが実行するようだ。

実行されるコマンドを作成。

cat <<"EOF" | sudo tee /usr/local/bin/gitea > /dev/null
#!/bin/sh
ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@"
EOF
sudo chmod +x /usr/local/bin/gitea

ユーザーの公開鍵についているコマンドはこれで、呼び出されると2222/tcpに接続に行くようになっている。
後は、Giteaが上手くユーザーを処理してくれるようになっている。

処理について詳しく知りたい場合は、こちらを参照。
Gitea / Installation with Docker

コンテナの起動

操作

Kopanoパッケージの配置で入力待ちになるので、Kopanoのコミュニティエディションをダウンロードする。
download.kopano.io > community

ディレクトリダウンロードするファイル
community/corecore-XX.X.X.XX.XXXXXXX-Ubuntu_20.04-amd64.tar.gz
community/webappwebapp-X.X.X.XX.XXXXXXX-Ubuntu_20.04-all.tar.gz

Xにはバージョン番号等が入っている。
対象となるOSがUbuntu 20.04であることが重要なので、間違えないようにダウンロードする。

ダウンロードが終わったら、ファイルアプリを開いてファイルをコピーする。もちろん、コマンドでコピーしても構わない。
コピー先は以下。
/home/hoge/rorenv/docker/config/kopano/packages ※hogeは自分のユーザー名に読み替える

コピーが終わったら、Enterキーを押す。
Dockerイメージのダウンロード、イメージのカスタマイズ、コンテナの起動までが行われる。

================================================
  コンテナの起動
================================================

=== 証明書の配置



=== Kopanoパッケージの配置
Kopano Community Edition の core と webapp をダウンロードして
/home/hoge/rorenv/docker/config/kopano/packagesにコピーしてください。
  core-XX.X.X.XX.XXXXXXX-Ubuntu_20.04-amd64.tar.gz
  webapp-X.X.X.XX.XXXXXXX-Ubuntu_20.04-all.tar.gz
  ※Xはバージョンを表す英数字になっています。
https://download.kopano.io/community/
コピーが終わったらEnterキーを押してください。[Enter]



=== コンテナの起動
<以降省略>

ここで、Dockerのイメージファイルをダウンロードし、さらにUbuntu 20.04 serverではKopanoが必要とするパッケージを大量にダウンロードしている関係で、かなり時間が掛かる。

詳細説明

スクリプト内部では、以下を実行している。

kopanoコンテナの中で動作するPostfixが使用する証明書を配置する。
PostfixはTLS接続の際に、この証明書を使用する。

cd $SCRIPTHOME/docker
if [ ! -d config/kopano/packages/cert ]; then
        mkdir config/kopano/packages/cert
fi
cp $SSLCERTDIR/wildcard.example.net.crt config/kopano/packages/cert/server.crt
cp $SSLCERTDIR/wildcard.example.net.key config/kopano/packages/cert/server.key

Giteaにプライベート認証局の証明書を配置する。
Giteaはメールを送信する際に、メールサーバーが提示する証明書を確認し、信用できない場合にはメール送信を止めてしまう。そうならないように、giteaコンテナのOSにCA証明書を登録している。

if [ ! -d config/gitea/cert ]; then
        mkdir config/gitea/cert
fi
cp ../SSL/exampleCA/example.net.ca.crt config/gitea/cert/ca.crt

ユーザーがKopanoのファイルを配置してくれたら、docker-compose.ymlに基づいてコンテナを起動させる。

sudo docker compose up -d --build

rvmのインストール

操作

なし。

詳細説明

スクリプト内部では、以下を実行している。

sudo apt install gnupg2
gpg --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
\curl -sSL https://get.rvm.io | bash -s stable

これは、公式ホームページのルートで説明されている手順を実行しているのみ。
Ruby Version Manager (RVM)

ただし、このままだと少し問題があるので、.bashrcに設定を追加している。

sed -i '$ a \\n[[ -s "$HOME/.rvm/scripts/rvm" ]] && source  "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*' ~/.bashrc

また、いくつか追加される設定も、この環境にあると不具合が起きるものも含めて不要だったりするので、元々存在しないファイルが新たに作られていると判断したら(ファイルサイズで見ている…)、削除している。

if [ $(stat -c %s ~/.bash_profile) -eq 200 ]; then rm ~/.bash_profile; fi
if [ $(stat -c %s ~/.mkshrc) -eq 118 ]; then rm ~/.mkshrc; fi
if [ $(stat -c %s ~/.zlogin) -eq 118 ]; then rm ~/.zlogin; fi
if [ $(stat -c %s ~/.zshrc) -eq 118 ]; then rm ~/.zshrc; fi

特に .bashrc と .bash_profile は、この環境にとっては相性の良くない設定がされている。
このことについては、後日整理する。

hostsの設定

操作

example.netの名前解決をしたとき、どんなIPアドレスを返却するのかを決める。

チュートリアルでサーバーを起動する方法を見ると、ループバック(127.0.0.1)で動作させることを前提に書かれているように思われるが、デプロイまで試すことを考えると、ens33のIPアドレスを設定したい。
IPアドレスが固定できない環境(Hyper-Vだと一手間必要)の場合は、ループバックを選ばないと面倒かもしれない。

尚、hostsを設定するスクリプトは別ファイルに切り出しているので、後から変更することもできる。

================================================
  hostsの設定
================================================

現在のネットワーク設定はこのようになっています。
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    inet 192.168.110.103/24 brd 192.168.110.255 scope global dynamic noprefixroute ens33
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
314: br-5a0a13ad553d: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    inet 172.25.0.1/16 brd 172.25.255.255 scope global br-5a0a13ad553d
316: vethb27f962@if315: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-5a0a13ad553d state UP group default 
318: vethd1d94b3@if317: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-5a0a13ad553d state UP group default 
320: veth123278c@if319: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-5a0a13ad553d state UP group default 
example.netのIPアドレスとして何を登録しますか?
何も入力しなければ 127.0.0.1 を登録します。
IPアドレス: 必要ならIPアドレスを入力して[Enter]



=== セットアップ完了
rmvコマンドが正しく動作するように、一度端末を開き直してください

※表示されるIPアドレスは、環境によって違うはず。画面に表示された値をよく見て設定する。

詳細説明

スクリプト内部では、以下のように別ファイルを呼び出している。

cd $SCRIPTHOME
./10-hosts.sh

別ファイルの中では、ユーザーが入力した値に従って、/etc/hosts を書き直している。
もしも登録がなければ追加するし、既に登録されていればIPアドレスを書き換える。

DOMMEMBER="example\.net git\.example\.net mail\.example\.net smtp\.example\.net test\.example\.net"
if [ $(grep -c "$DOMMEMBER" /etc/hosts) -eq 0 ]; then
        sudo sed -i "\$a $IPADDRESS\t$DOMMEMBER" /etc/hosts
else
        sudo sed -i sed "s/^[0-9.]\+[[:blank:]]\+\($DOMMEMBER\)/$IPADDRESS\t\1/" /etc/hosts
fi

はっきり言って、/etc/hostsを手で書き換えた方が早い…

ens33のIPアドレスを入力してみた結果は以下。

/etc/hosts

127.0.0.1	localhost
127.0.1.1	dreamer

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
192.168.110.103	example.net git.example.net mail.example.net smtp.example.net test.example.net

※赤文字部分が追加されている。

各種サービスのティアダウン

コマンドを起動したら、何かを問い合わせることもなく、削除処理が始まる。
セットアップ中に何か失敗したとき、すべてを消して元の状態に戻す目的で作成している。

使い込んでいる環境で実行することは想定しておらず、01-setup.shでセットアップされたものをすべて削除(セットアップ前にインストールされていたパッケージがあったとしても!)するので、そのつもりで実行する必要がある。

端末を起動([CTRL]+[ALT]+[T])し、以下のコマンドを実行。
途中で問い合わせがあるので、そこではyesと回答する。

$ cd rorenv
$ ./91-teardown.sh
[sudo] <あなたのアカウント> のパスワード: [パスワード][Enter]
<省略>
Are you SURE you wish for rvm to implode?
This will recursively remove /home/hoge/.rvm and other rvm traces?
(anything other than 'yes' will cancel) > yes[Enter]
Removing rvm-shipped binaries (rvm-prompt, rvm, rvm-sudo rvm-shell and rvm-auto-ruby)
Removing rvm wrappers in /home/hoge/.rvm/bin
Hai! Removing /home/hoge/.rvm
/home/hoge/.rvm has been removed.

Note you may need to manually remove /etc/rvmrc and ~/.rvmrc if they exist still.
Please check all .bashrc .bash_profile .profile and .zshrc for RVM source lines and delete or comment out if this was a Per-User installation.
Also make sure to remove `rvm` group if this was a system installation.
Finally it might help to relogin / restart if you want to have fresh environment (like for installing RVM again).
<省略>

削除内容は以下。

  • 認証局、CA証明書を削除。
  • SSL証明書と秘密鍵を削除。ただし、ChromeやEdgeに登録した証明書は削除していない(やり方不明)。
  • Apacheに配置したファイルを削除し、アンインストール。
    また、これによって不要になったパッケージもアンインストール。
  • git接続設定の削除。
  • Giteaのパススルーで使用するユーザーgitの削除。
  • Dockerのコンテナ、ネットワーク、ボリューム、イメージ、Builderを削除。
  • rvmの削除。
  • /etc/hostsのエントリーを削除。

PostgreSQL

DockerでPostgreSQLを起動するスクリプトを用意した。
あわせて、Ruby on RailsからPostgreSQLへのアクセスで必要となるライブラリもインストールする。

セットアップ

操作

rorenvディレクトリに移動して、スクリプトを起動する。

$ cd rorenv
$ ./02-setup-postgres.sh
[sudo] hoge のパスワード: [パスワード][Enter]

この時点で、ディスク使用量は17GBほどになっている。

詳細説明

チュートリアルで使用するGemのpgだけれども、途中でエラーが出て、こんなメッセージが表示されたりする。

Unable to find PostgreSQL client library.

Please install libpq or postgresql client package like so:
  sudo apt install libpq-dev
  sudo yum install postgresql-devel
  sudo zypper in postgresql-devel
  sudo pacman -S postgresql-libs

or try again with:
  gem install pg -- --with-pg-config=/path/to/pg_config

or set library paths manually with:
  gem install pg -- --with-pg-include=/path/to/libpq-fe.h/ --with-pg-lib=/path/to/libpq.so/

なので、libpq-devパッケージもあわせてインストールしている。

ティアダウン

コマンドを起動したら、何かを問い合わせることもなく、PostgreSQLをボリュームごと削除する。
ボリュームを消すということは、データーも消えるということなので、実行時には要注意。

端末を起動([CTRL]+[ALT]+[T])し、以下のコマンドを実行。

$ cd rorenv
$ ./91-cleanup-postgres.sh
[sudo] <あなたのアカウント> のパスワード: [パスワード][Enter]

インストールされたlibpq-devパッケージもパージしている。

各種サービスの初期設定

ブラウザ

チュートリアルで作成するアプリケーションや、Kopano、Giteaは、プライベート認証局が署名した証明書を使って通信を暗号化する。プライベート認証局をブラウザに登録し、ブラウザが安全な接続であると認識できるようにする。

これにより、この環境で使用する example.net と *.example.net への接続が、安全であると見なされるようになる。

ここでは、Chromeでプライベート認証局の証明書をインポートする。
証明書は、ホーム → rorenv → SSL → exampleCA をたどると、example.net.ca.crt という名前で保管されている。

Edgeでも操作はほとんど同じ。

Kopano

ブラウザで、https://mail.example.net にアクセスする。

Welcome画面が表示されるので、初期ユーザーで管理者の
 Username: webmaster
 Paswsword: webmaster
でサインインする。

初回サインイン時に簡易設定画面が表示されるが、ここでは言語を日本語にさえしておけば、後は設定メニューからどうにかできるだろうと思われる。

URLをブックマークしておけば、簡単にアクセスができるようになる。

Gitea

ブラウザで https://git.example.net にアクセスする。

初期設定画面が表示されるので、以下を設定していく。その他はデフォルトのままでOK。

項目設定項目設定値
データベース設定デフォルト値のままでOK
基本設定デフォルト値のままでOK
オプション設定/メール設定SMTPホストsmtp.example.net
SMTPポート465
メール送信者webmaster@example.net
SMTPユーザー名webmaster
SMTPパスワードwebmaster
登録にはメールによる確認が必要チェックなし
メール通知を有効にするチェックなし
オプション設定/サーバーと外部サービスの設定デフォルト値のままでOK
管理者アカウントの設定管理者ユーザー名webmaster
パスワードwebmaster
パスワード確認webmaster
メールアドレスwebmaster@example.net

入力したら、「Giteaをインストールボタン」をクリックすると、Giteaにログインした状態になる。

URLをブックマークしておけば、簡単にアクセスができるようになる。

普段使いのユーザーを作成

ここで、Kopano、Giteaの両方からサインアウトしておく。

最初に、メールのアカウントを作成。

端末を開き([CTRL]+[ALT]+[T])、以下のコマンドを打ち込む。
黄色で示したユーザー名、パスワード、メールアドレス、名前のところは、自分のものに置き換える。

$ sudo docker exec kopano kopano-admin -c hoge -p hoge -e hoge@example.net -f "Hoge" -a no
User created.

コマンドを簡単に解説すると、このような感じ。

  • sudo docker exec kopano までが、kopanoコンテナでコマンドを実行することを表している。
  • kopano-admin からが、kopanoのコマンドで、ユーザー名、パスワード、メールアドレス、フルネーム、管理者権限の順で指定している。

メールアドレスのドメイン部分(@example.net)は変更できない。
厳密には、Kopanoはマルチドメインに対応しているので、ちゃんと設定すれば新しいドメインを追加することができるはず。しかし、今回の設定ではそれをしていないため。練習環境なので、割り切り。

改めて、ブラウザで https://mail.example.net にアクセスし、今作成したユーザーでサインインできることを確認する。
ログインできたら、webmaseter@example.netとメールのやりとりをして試してみるのもいいかもしれない。

続いて、Giteaのアカウントを作成。

https://git.example.net にアクセスし、登録をクリックする。
ユーザー名やメールアドレスはKopanoと同じものにする。

これでユーザーができた。
設定完了まで、もう一息。

GiteaへのSSH接続

Githubでは、リポジトリを更新するために、SSH接続が必要になっている。
ということで、こちらでもSSHで接続ができるようにしておく。
実際、設定しておけば更新時にパスワード入力もいらないので、とっても便利。

実は既に公開鍵・秘密鍵のセット、および、接続設定を作ってあるので、それをGiteaに登録する。

端末を開き([CTRL]+[ALT]+[T])、以下のコマンドを打ち込んで、公開鍵を表示させる。

$ cat .ssh/git-key.pub

表示された公開鍵(ssh-ed25519からはじまりgit keyで終わる文字列)をコピーする。

Giteaで、設定 → SSH/GPGキーと進み、SSHキーの管理の「キーを追加」をクリック。
キー名は適当なものを付けて、内容のところにコピーしておいた公開鍵を貼り付け、緑の「キーを追加」をクリック。

続いて、その鍵の右にある「確認」をクリックし、署名はこの方法で生成できます:の下にある
 echo ~ gitea -f
迄をコピーして、端末に貼り付け、以下の黄色部分を追記して実行する。

$ echo -n 'e0a9ec75ead2954a581372d3443441e5078aad4443637086f5ea71e85030b15f' |
   ssh-keygen -Y sign -n gitea -f ~/.ssh/git-key
Signing data on standard input
-----BEGIN SSH SIGNATURE-----
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgefs6EQCns/vlN7U6T17jjBk2X/
GSnwdp6SiNXiJUBlEAAAAFZ2l0ZWEAAAAAAAAABnNoYTUxMgAAAFMAAAALc3NoLWVkMjU1
MTkAAABAi9V48u6APp/NX7ur6BVMBDmF8v/QkV4Ro3fo3rWmnMZF32zSlXohyA91i+xIZ/
KBiuBQNG7x0zvuz9wj8Q8mCQ==
-----END SSH SIGNATURE-----

—–BEGIN SSH SIGNATURE—– から —–END SSH SIGNATURE—– 迄をコピーして、Armor形式のSSH署名の欄に貼り付けて、緑の「確認」をクリック。

これで、公開鍵・秘密鍵のペアに間違いがないことが確認される。
※スクリーンショットを別のタイミングで撮ったので、端末の公開鍵と、Giteaに登録されている公開鍵が違う…あくまでも操作イメージを絵にしているということでご容赦ください。

最後に、SSH接続を確認してみる。
初回接続時には、このホストに接続しても良いか?と確認されるのでyesと入力している。

$ ssh git@git.example.net
The authenticity of host 'git.example.net (127.0.0.1)' can't be established.
ED25519 key fingerprint is SHA256:SVss4Xw3poRHIjXpV0DpmytEx5T7Qzu/psmR2YH97k8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'git.example.net' (ED25519) to the list of known hosts.
PTY allocation request failed on channel 0
Hi there, hoge! You've successfully authenticated with the key named hoge git key, but Gitea does not provide shell access.
If this is unexpected, please log in with password and setup Gitea under another user.
Connection to git.example.net closed.

Hi there, <あなたのアカウント名>! ~
と表示されれば、接続設定はうまくできている。

これで、初期設定は完了!

ここまでの設定がしてあれば、Giteaにリポジトリを作成し、最初にローカルのリポジトリをプッシュするときには、SSHが使用できて、パスワードなし(秘密鍵を使った認証)で操作ができるようになっている。

環境構築後の操作あれこれ

example.netのIPアドレス変更

Hyper-Vを使用しているとき、IPアドレスを固定するには一手間必要。
ちょっとメンドクサイので、DHCPが払い出すIPアドレスを使用することが多いと思う。

その時、example.netをloopbackではなく、その時のIPアドレスにしたかったら、以下のスクリプトを実行。
現在のネットワーク設定が表示され、これと思うものを入力すれば/etc/hostsを書き換える。

$ cd rorenv
$ 10-hosts.sh

とはいえ、やっていることは/etc/hostsの書き換えなので、テキストエディタで書き換えてもOK(スクリプトはたいしたことをしていない)。

開発中のアプリへのアクセス

チュートリアルで開発中のアプリケーションには、http://localhost:3000でアクセスができる。

さらに、Apacheでlocalhost:3000にReverse Proxyしているので、https://example.netでもアクセスができる。
ただし、example.netのIPアドレスが127.0.0.1以外の場合には、

$ rails server -b 0.0.0.0

と、-b パラメーターを付けて、すべてのネットワークインターフェースをバインドするようにしておく。

元々、一周目を「GUIのないサーバー」でやっていたので、「http://localhost:3000にアクセスして動作を確認してくれ」といわれてもできるはずがなく、このパラメーターを付けて実行して問題を回避していた。

逆に、パケットさえ届けば(少なくとも仮想マシンのホストからは届く)、開発中のアプリケーションに外からアクセスすることもできる、とも言える。

本番環境へのデプロイ

本来の形というのが正直なところよく分からないが、Sample Appをリポジトリからダウンロードしてきて、分かる範囲で実行できる環境を作ってみる。

まずは、Giteaに作成しているリポジトリから、好きな場所にソースをクローンする。

$ cd <好きな場所へ>
$ git clone git@example.net:<gitのユーザー名>/<リポジトリ名>.git

Gemのインストール。

$ bundle _2.3.14_ install
$ bundle _2.3.14_ lock --add-platform x86_64-linux

PostgreSQLの設定をする。これは、以下に合う値を ~/rorenv/postgres/docker-compose.yml で設定している。

config/database.yml

#production:
#  <<: *default
#  database: db/production.sqlite3
production:
  <<: *default
  adapter: postgresql
  encoding: utf8
 #url: <%= ENV['DATABASE_URL'] %>
  host: localhost
  username: postgres
  password: postgresql
  database: sample_app

データーベースにアクセスするための秘密鍵を設定。

他の環境からソースをクローンしてきた場合には、config/credentials.yml.enc ファイルがあるかもしれない。
この場合、開発元から config/master.key をもらうか、credentials.yml.enc を削除して、鍵から作り直す感じ。

$ EDITOR="vim" rails credentials:edit

データーベースを作成。

$ rails db:create RAILS_ENV=production
Created database 'sample_app'

もしここで、rails aborted! と表示された場合には、データーベースにアクセスするための秘密鍵がcredentials.yml.encと合っていないと思われる。作り直すのであれば、config/credentials.yml.encを削除する。

データーベースのマイグレーション。

$ rails db:migrate RAILS_ENV=production

SSLを強制している場合、この環境ではhttpでReverseProxyしているのでエラーが発生するので、コメント化しておく。

config/environments/production.rb

  # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
  # config.force_ssl = true

アセットパイプラインが有効になっていない場合は、有効にする。

config/environments/production.rb

  # Do not fallback to assets pipeline if a precompiled asset is missed.
  config.assets.compile = true

メールの設定も入れておく。

config/environments/production.rb

  host = 'example.net'
  config.action_mailer.default_url_options = { host: host, protocol: 'https' }
  config.action_mailer.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    :user_name => 465,
    :address => 'smtp.example.net',
    :user_name => 'webmaster',
    :password => 'webmaster',
    :domain => host,
    :authentication => :plain,
  }

メール関係の設定は以下にもあるので、念のため確認しておくといいかもしれない。

  • app/mailers/application_mailer.rb
  • config/environments/development.rb
  • config/environments/test.rb
  • test/mailers/user_mailer_test.rb

これで準備ができたので、サーバーをプロダクション環境で起動する。

$ rails server -b 0.0.0.0 --environment production

ここで、https://example.net に接続すればOK。

503

example.netは、Ruby on Railsのアプリケーションが表示されることを意識して、3000/tcpへのReverse Proxyにしてある。
ここにアクセスしたとき、以下のエラーが表示されたら、rails serverを起動していないと思われる。

Service Unavailable
The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later.

エラーページを表示させることもできるけれども、Ruby on Railsでは絶対に作られないページというのがよく分からないので、ここで説明して、エラーページを表示させるのは諦めている。

ディスク容量の拡張

最初に環境を作ったときの想定よりも、ディスク使用量が増加することはよくある。

こんな時には、

  • 仮想ディスクの容量を増やす。
  • パーティションをディスク容量いっぱいまで広げる。
  • ファイルシステムをパーティションいっぱいまで広げる。

という3段階の手続きを踏む。

まずは仮想ディスクの容量を増やす。
VMware Workstation Playerの場合は以下の操作だが、他の仮想システムでもきっと似たようなことができるだろう。

仮想マシンを選択し、「仮想マシン設定の編集」をクリック。
開いた、仮想マシン設定の画面で、ハードディスクを選択し、「展開」ボタンをクリックする。

ディスク最大サイズを増やして「展開」ボタンをクリックすると、ディスクの容量が増加する。

続いて、ディスク容量いっぱいまでパーティションを広げる。
この構成だと、ディスクは/dev/sdaで表され、OSはパーティション3(/dev/sda3)にインストールされている。このパーティションをディスクいっぱいまで広げる。

$ sudo parted /dev/sda
GNU Parted 3.4
/dev/sda を使用
GNU Parted へようこそ! コマンド一覧を見るには 'help' と入力してください。
(parted) print
モデル: VMware, VMware Virtual S (scsi)
ディスク /dev/sda: 32.2GB
セクタサイズ (論理/物理): 512B/512B
パーティションテーブル: gpt
ディスクフラグ: 

番号  開始    終了    サイズ  ファイルシステム  名前                  フラグ
 1    1049kB  2097kB  1049kB                                          bios_grub
 2    2097kB  540MB   538MB   fat32             EFI System Partition  boot, esp
 3    540MB   21.5GB  20.9GB  ext4

(parted) resizepart 3
警告: パーティション /dev/sda3 は使用中です。それでも実行しますか?
はい(Y)/Yes/いいえ(N)/No? Y
終了?  [21.5GB]? 100%
(parted) quit
通知: 必要であれば /etc/fstab を更新するのを忘れないようにしてください。

最後に、ファイルシステムをパーティションいっぱいまで拡張する。

$ sudo resize2fs /dev/sda3
resize2fs 1.46.5 (30-Dec-2021)
Filesystem at /dev/sda3 is mounted on /; on-line resizing required
old_desc_blocks = 3, new_desc_blocks = 4
The filesystem on /dev/sda3 is now 7732475 (4k) blocks long.

使用可能な領域が増えているか確認する。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           389M  2.0M  387M   1% /run
/dev/sda3        29G   14G   15G  49% /
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
/dev/sda2       512M  6.1M  506M   2% /boot/efi
tmpfs           389M  2.4M  387M   1% /run/user/1000

※この時は20GB→30GBへの拡張だった。EFIに540MB取られているので、29GBならば上手くいったと分かる。

バックアップとリストア

2023/05/05 追記

ちょっと真面目に環境を使い込んだら、バックアップが機能が欲しくなった。やっぱりあったほうが安心。
以前、ボリュームのバックアップにトライしていたので、そのやり方を流用している。

バックアップ

端末を起動([CTRL]+[ALT]+[T])し、rorenvディレクトリに移動して、スクリプトを起動する。

$ cd rorenv
$ ./11-backup.sh
[sudo] hoge のパスワード: [パスワード][Enter]

これで、rorenv/backup/backupsディレクトリにバックアップが作られる。
ファイル名には年月日時分秒が含まれ、tar.gz形式で圧縮されている。

バックアップに含むのは以下。

  • Kopanoの添付ファイル
  • Giteaのプログラム・設定ファイル一式
  • MariaDBのデーターディレクトリ一式

MariaDBについて、ダンプを取らずにディレクトリをまるごとバックアップしているので、バージョンは一緒でないとうまく動かないかもしれない。

リストア

テストは一度ティアダウンし、再度セットアップした環境で試している。
バックアップしたファイルを「上書き」するので、使い込んでいる環境にリストアすると、何が起きるかわからない。バックアップよりファイルが多くなっていると、復元後には必要のないファイルが残ることになるので。

端末を起動([CTRL]+[ALT]+[T])し、rorenvディレクトリに移動して、スクリプトを起動する。

$ cd rorenv
$ ./12-restore.sh
[sudo] hoge のパスワード: [パスワード][Enter]
<省略>
[+] Running 2/2
 ✔ Network backup_default  Created                                                                  0.1s 
 ✔ Container backup        Started                                                                  0.6s 
The following backups are available.
backup-exbackup-2023-05-05-09-19-42.tar.gz  backup-exbackup-2023-05-05-11-19-16.tar.gz

Enter the backup file name to be restored.
-> backup-exbackup-2023-05-05-11-19-16.tar.gz[Enter]
/mnt/backups/backup-exbackup-2023-05-05-11-19-16.tar.gz
<省略>

途中で「Enter the backup file name to be restored.」のメッセージが表示されるので、表示されているbackupsのファイルのうち1つをコピペする。

これでバックアップされたファイルで上書きされる。

なお、GiteaにSSH接続するために公開鍵を登録している場合は、そのデーターも復元されてしまうので、登録しなお薄必要がある。

登録し直さないと、以下の通りSSHが失敗する。

$ ssh git@git.example.net
The authenticity of host 'git.example.net (192.168.110.103)' can't be established.
ED25519 key fingerprint is SHA256:hD+y3njKcQ9jsPNnyZOmzpasXKn9PS6lfOQMBKh8Mes.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:4: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'git.example.net' (ED25519) to the list of known hosts.
git@git.example.net's password: 
Permission denied, please try again.
git@git.example.net's password: 
Permission denied, please try again.
git@git.example.net's password: 
git@git.example.net: Permission denied (publickey,password).

登録し直すとSSHが成功する。

$ ssh git@git.example.net
PTY allocation request failed on channel 0
Warning: Permanently added '[127.0.0.1]:2222' (ED25519) to the list of known hosts.
Hi there, rohhie! You've successfully authenticated with the key named rohhie git key new, but Gitea does not provide shell access.
If this is unexpected, please log in with password and setup Gitea under another user.
Connection to git.example.net closed.

認証局の運営

今回、プライベート認証局(Private Certificate Authority)を作ってSSL証明書を発行し、それを使ってチュートリアルで作ったアプリケーションを暗号化する環境にしてみている。

せっかくなので、認証局とはなんなのか、というところを自分なりの解釈で記してみる。
以降、認証局を「おじさん」に例えているが、気に入らなければ「おねえさん」とか「おにいさん」とかいったイメージがわく「くくり」に読み替えてほしい。

認証局

誰かがWebサイトを運営するので、証明書をくださいと申請書を提出してきた。

ここでいう申請書は、証明書署名要求ファイルを表している。
証明書署名要求は、CSR(Certificate Signing Request)のこと。

すると「おじさん」はその人が信頼に足る人なのかどうかを確認し、信頼できると思ったら申請書に基づいた証明書を作り、判子を押す。

ここでいう判子は、秘密鍵を表している。
判子を押すことは、署名することに相当する。

Webサイトにアクセスする人は、証明書と印影を見て、あぁ、あの「おじさん」が発行した証明書なのね、じゃあ信頼して大丈夫だなと安心する。

ルート認証局

高い知名度を持つ「おじさん」や、厳しい外部の審査を受けて立候補した「おじさん」について、OSやアプリケーションを作成した人が信頼しても良いだろうと考える。そうすると、その「おじさん」個人が信頼されたことになる。

これがルート認証局(Root Certificate Authority)。

信頼できる「おじさん」について、OSやアプリケーションがそれぞれCA証明書を束ねて持っている。OSやアプリケーションは、証明書の印影をCA証明書の束と照らし合わせ、信頼できる「おじさん」が発行した証明書であるか確認している。

Windowsであれば「信頼されたルート証明機関」にCA証明書を束ねているし、Ubuntuだと/etc/ssl/certsにCA証明書を束ねている。Ubuntu用のChromeは独自にCA証明書を束ねている。Androidもそうだ。そして、それらの作り手は違うわけだから、それぞれが束ねて持っているCA証明書は当然微妙に違っている。

中間認証局

ルート認証局は忙しい。だから、この人は大丈夫、安心だ、と考える「おじさん」に証明書を出し、認証局として任命して働いてもらう。

これが中間認証局(Intermediate Certificate Authority)。

「任命されたおじさん」は、申請書から証明書を作って署名し、、その証明書と一緒に自分の証明書も渡す。Webサイトを運営する人は、利用者に向けて「任命されたおじさん」の証明書と一緒に証明書を提示することで、信頼してもらえる。

Let’s Encryptで発行してもらう証明書がこのタイプ。

プライベート認証局

とある組織でとある「おじさん」が認証局をはじめました。その組織の中で「おじさん」の判子は大切な意味を持ち、信頼されている。

これがプライベート認証局(Private Certificate Authority)。

プライベート認証局を信頼するには、OSやアプリケーションに信頼していることを伝えればよい。
Windowsであれば「信頼されたルート証明機関」にCA証明書を登録すればいいし、Ubuntuなら所定のディレクトリにCA証明書を置いてupdate-ca-certificatesを実行すればいい。Ubuntu用のChromeでは設定画面から「認証局」にCA証明書を登録すればいい。

WindowsのActive Directoryでは、CA証明書を配布する機能がある(管理したことがないので、具体的な手順は知らない)。なので、組織全体にプライベート認証局を信頼させることができる。

こう考えると、ルート認証局もプライベート認証局の一種で、超有力な「おじさん」ということじゃないかなと思っている。
超有力な「おじさん」は、多数の巨大サイトに証明書を発行している…となった場合、それらのサイトにアクセスする製品はその「おじさん」を信頼しておかないと使ってもらえない、だから信頼しておくか、となる。そんな理屈なんじゃないだろうか。

先日、「公的機関に署名してもらった証明書を用意してください」とかいわれたんだけれど、個人的にはピンとこない。彼らは行政機関や独立行政法人じゃないし、信頼できるCAを認定する機関が決まっているわけでもないので、公的機関というわけじゃない。一般に通用しそうな認証局、くらいのものなんじゃないかと思っている。

証明書の有効期限

CA証明書や、CAが署名した証明書には有効期限が設定されている。
ルート認証局のCA証明書の有効期限が切れると、中間認証局も含めたすべての証明書が無効になる理屈なので、ルート認証局は計画的に置き換えていく必要がある。

もちろん、OSやアプリケーションもそれに対応してルート認証局のCA証明書を登録しておく必要があるから、彼らにもその計画を示して新しい証明書を渡しておく。

このことは、プライベート認証局にも当てはまるから、プライベート認証局を運営している人は大変。
ということで、今回用意した環境では、CA証明書の有効期間を30年に設定している。OSの有効期間は優に超えるから、チュートリアルの学習用には十分だろうから。

ホームラボで運営しているプライベート認証局も30年設定だったけれど、現在残り20年となっている。家族に証明書のことを言っても分からないから、全部の端末をメンテナンスするのか…大変過ぎる(笑)
まぁ、20年の内にどうにかすればOKということで、後回し。

証明書の目的

証明書にはCAであるかどうかを示す情報がある(TRUE/FALSE)。
ChromeでCA証明書をインポートするときには、なんのために使うのか選択するダイアログボックスが表示されたりするので、そのCA証明書をどのように使うのか、というところはユーザーに任されているところがあるようだ。

Webサイトで使用する証明書の場合、X509v3 extensionsというところで、どんな名前のサイトで使うのかが示されている。今回用意した環境では example.net と *.example.net で使用できるSSL証明書を作成している。アスタリスクはワイルドカードっぽい動作をするので、mail.example.net とか git.example.net というサイトでも問題なく使える。
逆にこの指定がないと、Webサイトで使っても信用を得られない。

証明書の取り消し

証明書は取り消す(Revoke)ことができる。取り消された証明書は、CRL(Certificate Revocation List)で示される。
CA証明書にはCRL配布ポイントを示す情報を書き込むことができて、これが実装されていれば、無効にした証明書を示すことができる。

これが配布できない場合、どれか1つの証明書だけ取り消し、といったことができなくて、OSやアプリケーションに直接「これは駄目」と配って回るか、認証局自体を信頼されていないところに区分するのかなと思われる。

今回用意した環境では、これを実装していない。今後の学習課題。
恐らくは openssl.cnf で指定ができて、それをApacheで配布できれば良さそうだなと。キーワードは crlDistributionPoints だった。

ちなみに、CA.plは過去に署名した宛先の証明書があったとき、同じ宛先の証明書署名要求には署名できなかった。事前に取り消しておかなければならない。
Unix & Linux / Generating duplicate certificates with OpenSSL CA

これを回避するには、index.txt.attrに

unique_subject = no

を指定すれば良い。

Kopanoについて

Kopanoは、以前からホームラボで愛用しているオープンソースのグループウェア。
Zarafaとしてスタートし、開発が今の体制に移行してKopanoという名前になっている。

Outlookとも連携が可能で、Z-pushを用いて携帯でもExchange的な接続が利用できる、大変に優れたシステムである。
それなのに、コミュニティエディションであれば無料で利用できるということで、ありがたく利用させていただいている。
今は、基本機能の他に、ビデオ会議、チャット、LibreOffice等も統合できるようになっている。

せっかく提供されている新しい機能に追従できていないのは残念だけれども、個人的な時間・能力的に致し方なし。

公式のDockerイメージは提供されていない。
普通に考えて設定項目が多すぎるし、柔軟な設定ができるようにもなっているので、大変過ぎるだろうなと思う。

なお、開発は比較的ゆっくりであり、4/28現在、Ubuntu 18.04と20.04への対応のみとなっている。開発が止まっているわけではなく、OpenSSL3.0への対応が大変なんだよ、とのこと。

そのため、複数サービスを1つのサーバーに同居させようとしている関係で、他のシステムと対応OSのバージョンがズレている期間も長くなりがち。そのため、Dockerで動作させることを過去に検討していたので、今回の環境ではそれを流用している。
ちょっとオーバースペックかなとは思ったものの、できあがってみればWebでメールが確認できるので、簡単。

なお、コミュニティエディションのダウンロードサイトには、以下のコメントが書き記されている。

The downloads you find here are our nightly builds! Essentially the development version with the latest code and newest features – which in many cases are untested. If you are using these builds, we’d love to hear your feedback on new features and bugreports. If you have a Kopano subscription and you’re looking for stable and tested version, you can either visit the supported section, or go to the portal and click downloads. You can also use the portal to generate a repository configuration file, which makes installing and updating your systems very easy.

DeepL先生の翻訳:
ここにあるダウンロードは、私たちのナイトリービルドです! 基本的には、最新のコードと最新の機能を備えた開発版ですが、多くの場合、未試験です。 これらのビルドを使用している場合、新機能やバグレポートに関するフィードバックをお待ちしています。 コパノのサブスクリプションをお持ちで、安定したテスト済みのバージョンをお探しの場合は、サポートされたセクションをご覧になるか、ポータルに移動してダウンロードをクリックすることができます。 また、ポータルを使ってリポジトリ設定ファイルを生成することもでき、システムのインストールやアップデートが非常に簡単になります。

download.kopano.io > community

実際に、機能追加がされている間?なのか、ちょっとログが爆発的に出力されるバージョンがあったりして、コミュニティでバグや修正案がレポートされたこともあった。

しかし、開発が安定している今(2023/4現在)は、だいぶ安定動作しているように思われる。
そういう安定したときのパッケージを持っておくと、安定した運用ができたりする。

Giteaについて

Gitea(ギッティー)は、最近愛用しているオープンソースのGitサーバー。
気軽に使えそうなGitサーバーを探していたら見つけた優れもの。

一通り操作してみると、Gitがなんとなく分かってくるし、Githubで表示されている様々な情報が何を意味しているのか分かってくる。だいぶ似せてあるにもかかわらず、リソースもあまり食わないので、これはいい!と本格的に使っている。

こちらは公式のDockerイメージがあり、かなり気軽に使い始めることができる。

チュートリアルでやっているようなことはすべてできるし、気付いたことをIssueに書いておいたり、何かをまとめたくなったらWikiに書いておいたりできるので、学習用に使うのには十分すぎる機能を持っている。

やったこと

SMTPサーバーの認証を試す

コマンドラインでSMTPサーバーの認証を試す方法を調べた。
技術メモの壁 / openssl s_client で SMTP STARTTLS と SMTP AUTH を動作確認する
noknow / [Postfix] [OpenSSL] [解決] RENEGOTIATING SSL routines:SSL_renegotiate:wrong ssl version:ssl/ssl_lib.c

STARTTLSでやりとりするので、telnetでは上手くいかず、opensslを使用。

まず、ユーザー名とパスワードをBASE64エンコーディングしておく。
ユーザー名\0ユーザー名\0パスワードの順で指定。
今回の環境ではユーザー名とパスワードが一緒(webmaster)なので以下の状態。

$ printf 'webmaster\0webmaster\0webmaster' | base64
d2VibWFzdGVyAHdlYm1hc3RlcgB3ZWJtYXN0ZXI=

ついでに失敗用のも用意。
$ printf 'webmaster\0webmaster\0hogehoge' | base64
d2VibWFzdGVyAHdlYm1hc3RlcgBob2dlaG9nZQ==

認証を試しつつ、メールを送信してみる。

$ openssl s_client -connect smtp.example.net:587 -starttls smtp -quiet
depth=1 C = JA, ST = Tokyo, O = Example Networks Inc., CN = example.net, emailAddress = webmaster@example.net
verify return:1
depth=0 C = JA, ST = Tokyo, L = Chiyoda, O = Example Networks Inc., CN = example.net, emailAddress = webmaster@example.net
verify return:1
250 CHUNKING
EHLO example.net
250-kopano
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH PLAIN d2VibWFzdGVyAHdlYm1hc3RlcgBob2dlaG9nZQ==
535 5.7.8 Error: authentication failed: authentication failure
AUTH PLAIN d2VibWFzdGVyAHdlYm1hc3RlcgB3ZWJtYXN0ZXI=
235 2.7.0 Authentication successful
MAIL FROM: test@example.net
250 2.1.0 Ok
RCPT TO: webmaster@example.net
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: test@example.net
Subject: mail test
mail from command line.
.
250 2.0.0 Ok: queued as 78ABB1463F1
QUIT
221 2.0.0 Bye

認証できていることが確認できて、メールの送信もできた。

外部へのメール送信を止める

この環境から、インターネットにメールを送信できるのはまずい。
example.net等というドメインはサンプル表記用であって、LAN内ならともかく、インターネットで使ってはいけない。

ということで、止め方を探してみた。
Server Fault / Postfix: stop all outgoing emails

main.cf

smtpd_relay_restrictions = defer_unauth_destination

Poxtfixのマニュアルを見てみたんだけれども、これでいけそうかな?と思って設定しても、これと同じようには動かなかった。こういうのがサラッと分かるのはうらやましい限り。

クライアント証明書についてメモ

プライベート認証局を作ったので、前からちょっと気になっていたことを調べてみたメモ。

クライアント証明書について、以前、nsCertType = clientというのを設定していた。
だが、これは古くて、使用は推奨されていないようだ。今は、extendedKeyUsageという値を使用するそうだ。
OpenSSL / x509v3_config / Extended Key Usage.

Apacheでの証明書の値の取り扱いは、ここで調べれば良さそうだ。
Apache HTTP Server Version 2.4 / Apache Module mod_ssl

rvmでエラー

このエラーが出ていて、気になっている。

Libraries missing for ruby-3.1.2: libcrypto.so.1.1,libssl.so.1.1. Refer to your system manual for installing libraries

Ubuntu 22.04では、libcrypt.soが1ではなく3になっているようだった。
少なくとも、Sample Appは動かせているので、今のところ問題はないのかなと思う。

VMware Playerでマルチモニタ

できるのかなと思って探してみたら、だいぶ前からできていたらしい。
VMware Docs / Use Multiple Monitors for One Virtual Machine in Workstation Player

サーバーばっかり立てていたから、気付かなかったよ…。

バージョン15では、仮想マシン設定の「ディスプレイ」で、使用するモニター数を定義しておく。
仮想マシンの画面をモニター1において、全画面表示にし、「複数の画面を循環」というボタンを押したら切り替えが行われる。

これなら、仮想マシンの中ですべてを完結させても良さそうだ。
もう少し少しリソースを増やしてみようかな。

さいごに

記事のリリースが、計画から1日遅れてしまった。
引っかかったのは、ティアダウンスクリプトで環境を完全にきれいに戻すところで、特に.bashrcとか.bash_profileとかに書き込まれた、

(空行)
# コメント
設定


をきれいに元に戻すところだった。後から設定を見ようと思ったら、(空行)があるべきなんだけれども、これをスクリプトで消そうとすると難しかった。awkを使えばできそうなことが書かれているのだけれど、sedだってちゃんと使えないのに、更にこの段階でテーマを増やす?と考えてsedで粘っていたのが原因。

結果として、tacでひっくり返して消しているアイディアを見かけて、なるほどなぁと実装。無条件に1行消しちゃっているので、何らかの理由で(空行)が消されているとまずいことになるけれど、まぁ、今回の用途ならこれでいいやと割り切った。

知っていることは多いに越したことはない。それこそ、いずれRubyでどうにかできるようになるかもしれない。学習は続く…

広告
ろっひー

コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他