Raspberry Pi 4 Model B に CentOS Stream 9 をインストールしてみた

## はじめに
自前のサーバを構築するために、Raspberry Pi 4 Model B に CentOS Stream 9 をインストールしてみました。私が購入したのは Raspberry Pi 4 Model B 4GB で、2021年7月に9,130円で購入しました。2023年2月現在、18,900円と品薄状態のためかなり高騰しています（Amazonでの最安値は6,875円なのでかなり高騰していますね。2023年後半から流通が戻る見込みだそうです）。

## 必要なもの
* [Raspberry Pi 4 Model B 4GB](https://amzn.to/409NOPk)（8GBのモデルもあります）
* microSD カード（32GB以上くらいあるといいでしょう。私は64GBのものを利用しました）
* [USB microSD カードリーダー](https://amzn.to/3I1LPW2)
* [Type-C 電源ACアダプタ](https://amzn.to/3wIgvqn)（オン/オフスイッチが付いてるので、ターミナルを開いて再起動するのが面倒くさい時に使ってます（故障の原因になるので推奨はしませんが…））
* [HDMI ケーブル タイプAオス-タイプDオス（micro）](https://amzn.to/3Rn30W) （無くても問題ありませんがあった方が便利です）
* [Raspberry Pi 4 ケース](https://amzn.to/3JAMcJI)（執筆現在、[m.2 SSD を使用できるケース](https://bit.ly/3XVtsck)が気になっているので買い替えるかもしれません）
* LAN ケーブル

## CentOS のインストール
まず始めに、OS のイメージファイルをダウンロードします。<a href="https://people.centos.org/pgreco/"> このサイト</a>より Raspberry Pi 向けの CentOS Stream 9 イメージファイルをダウンロードできます（有難いことに有志の Pablo Greco 氏が作成してくれています）。目的のファイルが入ってる `CentOS-Userland-9-stream-aarch64-RaspberryPI-Minimal-4/` を選択します。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/a0a67de7-eee1-1601-7353-b8a6945e3bde.png)
拡張子が __.raw.xz__ ファイルが目的のイメージファイルになります。クリックしてダウンロードしましょう。
![3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/52ed55a3-ae4c-2278-d157-43d8ec96e4bd.png)
ダウンロードした OS のイメージファイルを microSD カードに書き込みます。ここでは <a href="https://rufus.ie/ja/">Rufus</a> というツールを利用します。ダウンロードした Rufus を起動します。[デバイス] から書き込みたい microSD カードを選び、[選択] ボタンから先程ダウンロードした __.raw.xz__ ファイルを選びます。
![スクリーンショット 2023-02-01 19.45.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/dddb8be3-e680-ed36-892f-3f79d75d89d0.png)
[スタート] ボタンを押すことで書き込みが始まります（私の環境では3分程かかりました）。
![スクリーンショット 2023-02-01 19.46.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/79b3d204-2aee-7c16-64ae-0d29108c071c.png)
なお、ここで以下のような警告が出るときがありますが（microSD カードにデータがある場合表示されます）、[OK] ボタンを押して実行して問題ありません。
![スクリーンショット 2023-02-01 19.46.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/5601a078-cd6a-e506-d40a-8894935ab15b.png)![スクリーンショット 2023-02-01 19.46.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/fcc390bf-8f5e-936c-7d40-eb3367d34289.png)
以下のように"状態"が"準備完了"となれば書き込み完了です。これで Raspberry Pi 用の CentOS Stream 9 が起動できる microSD カードが完成しました。
![スクリーンショット 2023-02-01 19.49.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/445afc40-b394-2bcc-01f0-464b0c17f2e2.png)

## CentOS の起動と ssh アクセス

### microSD カードを挿入し Raspberry Pi を起動する
書き込みが完了した microSD カードを　Raspberry Pi に挿入します。Raspberry Pi には電源ボタンがなく、通電を開始すると自動的に起動する仕組みになっています。そのためキーボードやモニターといった I/O デバイスと LAN ケーブルは、通電を開始する前に接続しておきましょう。CentOS Stream 9 が起動すると以下のようにログイン画面が表示されます。

```console:login
CentOS Stream 9
Kernel 5.15.59-v8.2.el9 on an aarch64

localhost login:
```
ログインするには、ユーザ名に **root** 、パスワードに **centos** を使用します。

### ssh で CentOS にアクセス
DHCP で動的に IP アドレスが割り当てられているはずなので、`ifconfig` コマンドで IP アドレスを調べます（モニターに接続せず IP アドレスを調べ、ターミナルから ssh で接続することも可能です。IP アドレスの調べ方は<a href="https://geek-memo.com/lan-device/">このサイト</a>を参考にして下さい）。

```console:ifconfig
[root@localhost ~]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.7.74.116  netmask 255.255.255.224  broadcast 10.7.74.127
        inet6 fe80::9cdb:82ea:dedd:f3a  prefixlen 64  scopeid 0x20<link>
        ether dc:a6:32:8e:8e:ef  txqueuelen 1000  (Ethernet)
        RX packets 794  bytes 71559 (69.8 KiB)
        RX errors 0  dropped 79  overruns 0  frame 0
        TX packets 585  bytes 64599 (63.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
```
この場合、IP アドレスは"10.7.74.116"になります。適当なターミナルソフト（個人的に"<a href="https://kmiya-culti.github.io/RLogin/">Rlogin</a>"が好きです）をインストールし、ssh で CentOS にアクセスして下さい。<font color="red">注意点として root ユーザでは ssh でアクセスできません。</font>理由としては、ssh で root によるパスワード認証を用いたログインがデフォルトで禁止されているからです（RHEL9 系から `/etc/ssh/sshd_config` ファイルの `PermitRootLogin` のデフォルト値が、"yes" から "prohibit-password" に変更されました。公開鍵認証と GSSAPI 認証だけが許可されます。RHEL8 系以前では ssh で root ログインができていました）。
そこで、REHL9 系からデフォルトユーザとして用意してある **centos** ユーザを使いましょう。パスワードは **centos** になります。ssh で centos ユーザにログインして下さい。ssh で root によるログインを可能にしたい場合は、以下を参考にして下さい。別に直接 ssh で root にログインしないよという方は読み飛ばして下さい。

### ssh で root によるパスワード認証を用いたログインを可能にする
centos ユーザでログインし `su -` コマンドを実行して下さい（パスワードは **centos** です）。root にログインできたら `/etc/ssh/sshd_config` ファイルに以下を追加し、sshd サービスを再起動して下さい。
```bash:sshd_config
PermitRootLogin yes # 追加
```
```console
[root@localhost ~]# systemctl restart sshd
```
これで ssh で root によるパスワード認証を用いたログインが可能となります。しかしセキュリティの都合上、このログイン方法を可能とするのはあまりよろしくありません（公式でも `PermitRootLogin` を `no` にすることを検討するように言われています）。`yes` にするとブルートフォース攻撃を防げなかったり、root のパスワードが漏洩した時に、ssh で root としてログインできてしまったりと問題があります。この時 `su` コマンドを実行できるユーザを制限することが前提となっています。以下のように `/etc/pam.d/su` ファイル中のコメントアウトを外すことで、"wheel" グループに所属しているユーザのみ `su` を実行できるように制限できます。そうすることで、万が一 "wheel" グループ以外のユーザにパスワードが漏洩しても `su` コマンドを実行できないため、安全性が担保できます（パスワードが漏洩するような状態が安全かは知りませんが…）。

```bash:/etc/pam.d/su
# Uncomment the following line to require a user to be in the "wheel" group.
auth           required        pam_wheel.so use_uid # コメントアウトを外す
```

また、同ファイル内の以下の行のコメントアウトを外すと、"wheel" グループに所属しているユーザはパスワードなしで `su` コマンドを実行することが可能になります。いちいちパスワードを打つのが面倒くさい方は、変更してみて下さい。

```bash:/etc/pam.d/su
# Uncomment the following line to implicitly trust users in the "wheel" group.
auth           sufficient      pam_wheel.so trust use_uid # コメントアウトを外す
```

## CentOS の各種環境の設定
ssh でリモートログインが可能になったら、CentOS の各種設定を行っていきましょう。

### パスワードの変更
root ユーザと centos ユーザのパスワードを変更します（デフォルトで用意されている centos ユーザは "wheel" グループに属しており、かなり権限が強いです。パスワードを変更しないと脆弱性に繋がります）。以下のように `passwd` コマンドを実行して下さい。
```console:passwd
[root@localhost ~]# passwd root
Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@localhost ~]# passwd centos
Changing password for user centos.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
```

### パーティションの拡張
初期状態では、microSD カードの全ての領域を利用することができません。ディスク利用状況を確認してみると、容量が64GBの microSD カードを使っているにも関わらず、`/`のサイズが2.3GBしかないことが分かります。
```console:ディスク利用状況
[root@localhost ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           759M   18M  741M   3% /run
/dev/mmcblk0p3  2.3G  788M  1.5G  36% /
/dev/mmcblk0p1  286M   61M  226M  21% /boot
tmpfs           380M     0  380M   0% /run/user/1000
```
これを解決するためにパーティションを拡張する必要があります。自動でパーティションを拡張してくれる `rootfs-expand` というコマンドがデフォルトで用意されていますが、私の環境では以下のように上手く実行できませんでした。
```console:rootfs-expand
[root@localhost ~]# /usr/local/bin/rootfs-expand

/dev/mmcblk0p3 /dev/mmcblk0p 3
Extending partition 3 to max size ....
FAILED: /dev/mmcblk0p: does not exist
Resizing ext4 filesystem ...
resize2fs 1.46.5 (30-Dec-2021)
The filesystem is already 610304 (4k) blocks long.  Nothing to do!

Done.
/dev/mmcblk0p3  2.3G  788M  1.5G  36% /
```
そこで、`rootfs-expand` コマンドが実行している内容を手動で行うことにします。以下のように実行して下さい。
```console:手動でパーティションを拡張
[root@localhost ~]# growpart /dev/mmcblk0 3
CHANGED: partition=3 start=1593344 old: size=4882432 end=6475776 new: size=123580383 end=125173727
[root@localhost ~]# resize2fs /dev/mmcblk0p3
resize2fs 1.46.5 (30-Dec-2021)
Filesystem at /dev/mmcblk0p3 is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 8
The filesystem on /dev/mmcblk0p3 is now 15447547 (4k) blocks long.
```
再起動しディスク利用状況を確認してみると、以下のようにパーティションが拡張できていることが分かります。
```console:ディスク利用状況
[root@localhost ~]# df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs           1.9G     0  1.9G   0% /dev/shm
tmpfs           759M   18M  741M   3% /run
/dev/mmcblk0p3   58G  788M   58G   2% /
/dev/mmcblk0p1  286M   61M  226M  21% /boot
tmpfs           380M     0  380M   0% /run/user/1000
```
### パッケージの更新
パッケージの更新を行います。
```console:update
[root@localhost ~]# dnf -y update
```

### キーボード配列の変更
物理キーボードを JIS 配列に変更します（US 配列を使用している方はそのままで問題ありません）。
```console
[root@localhost ~]# localectl set-keymap jp
```

### 言語設定
日本語設定にすると HDMI から Raspberry Pi にアクセスした時に文字化けするのでオススメしません。特に問題がなければ "en_US" でいいでしょう。
```console
[root@localhost ~]# dnf install glibc-langpack-en
[root@localhost ~]# localectl set-locale LANG=en_US.utf8
```

### タイムゾーンの変更
タイムゾーンを "Asia/Tokyo" に変更します。
```console
[root@localhost ~]# timedatectl set-timezone Asia/Tokyo
```

### ホスト名の変更
変えても変えなくてもいいと思います（私は変えていません。お好みで）。
```console
[root@localhost ~]# hostname hoge
```

### Wi-Fi と Bluetooth の無効化
Wi-Fi と Bluetooth を利用しない場合は、節電のためにも無効化しておくとよいでしょう。設定するには `/boot/config.txt` に以下を追加して下さい。
```bash:config.txt
dtoverlay=disable-bt
dtoverlay=disable-wifi
```
設定追加後、再起動して下さい。

### SELinux の無効化
プログラムが動かなかったり、インストールできなっかたりすることがあるため、 SELinux を無効化します。`/etc/selinux/config` ファイル中の "SELINUX" を以下のように変更して下さい。
```bash:/etc/selinux/config
# 変更前
SELINUX=enforcing
# 変更後
SELINUX=disabled
```
### firewall の無効化
こちらも有効化していると、プログラムが動かなかったりといった不都合が生じます。Raspberry Pi を Web サーバとして外部に公開するのでなければ無効化しても問題ないでしょう（責任は取りません）。
```console
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# systemctl disable firewalld
Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
```

### 静的 IP アドレスの設定
まずはデフォルトのコネクション名を変更します（スペースが入っていると入力が面倒なため）。
```console:コネクション名の変更
[root@localhost ~]# nmcli c
NAME                UUID                                  TYPE      DEVICE 
Wired connection 1  b0c826aa-8f27-38ca-8576-19d795d6cb17  ethernet  eth0 
[root@localhost ~]# nmcli con mod "Wired connection 1" con.id wired1
```
続いて静的 IP アドレスの設定ですが、特に理由がなければ、DHCP で動的に割り当てられた IP アドレスでいいでしょう。IP アドレスとデフォルトゲートウェイの調べ方は以下になります。

```console
[root@localhost ~]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.7.74.116  netmask 255.255.255.224  broadcast 10.7.74.127
        inet6 fe80::9cdb:82ea:dedd:f3a  prefixlen 64  scopeid 0x20<link>
        ether dc:a6:32:8e:8e:ef  txqueuelen 1000  (Ethernet)
        RX packets 794  bytes 71559 (69.8 KiB)
        RX errors 0  dropped 79  overruns 0  frame 0
        TX packets 585  bytes 64599 (63.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
[root@localhost ~]# ip route
default via 10.7.74.97 dev eth0 proto dhcp src 10.7.74.116 metric 100 
10.7.74.96/27 dev eth0 proto kernel scope link src 10.7.74.116 metric 100
```

上記では IP アドレスが"10.7.74.116"、サブネットマスクが"255.255.255.224"（プレフィックスは27。<a href="https://www.ahref.org/doc/ipsubnet.html">サブネットマスク早見表</a>から自分のプレフィックスを調べて下さい）、デフォルトゲートウェイは `ip route` コマンドで出てきた `default via` 以降の"10.7.74.97"になります。設定方法は以下の通りになります。
```console:設定方法
[root@localhost ~]# nmcli con mod wired1 ipv4.addresses 10.7.74.116/27
[root@localhost ~]# nmcli con mod wired1 ipv4.gateway 10.7.74.97
[root@localhost ~]# nmcli con mod wired1 ipv4.dns 10.7.74.97
[root@localhost ~]# nmcli con mod wired1 ipv4.method manual 
[root@localhost ~]# nmcli con reload
[root@localhost ~]# nmcli con down wired1 & nmcli con up wired1
```
設定ができたか以下のように確認してみましょう。設定が反映されていれば問題ありません。
```console:確認方法
[root@localhost ~]# nmcli con show wired1|grep ipv4
```
私の場合 DNS サーバを"10.7.74.97"にしたところ、CentOS の時刻がおかしくなってしまいました（ルータの ntp サーバがおかしい？）。そこでDNS サーバを"1.1.1.1"（Cloudflare が運営するパブリック DNS リゾルバ）に再設定し直したら治りました。

```console:date
[web@localhost ~]$ date
Fri Jun 22 20:12:07 JST 2018
```

### LED 消灯
電源や LAN ポートの LED が目障りなので無効化します。`/boot/config.txt` に以下を追加します。

```bash:config.txt
# turn off onboard LEDs
dtoverlay=act-led

# disable the ACT LED
dtparam=act_led_trigger=none
dtparam=act_led_activelow=off

# disable the PWR LED
dtparam=pwr_led_trigger=none
dtparam=pwr_led_activelow=off

# turn off ethernet port LEDs
dtparam=eth_led0=4
dtparam=eth_led1=4
```
設定追加後、再起動して下さい。

## 最後に
私が Raspberry Pi 4 を購入したときは、まだ CentOS Stream 9 はリリースされておらず、CentOS Stream 8 をインストールしていました。ですが、CentOS Stream 9 がリリースされている中、今更 CentOS Stream 8 をインストールする特異な方はいらっしゃらないでしょう（CentOS Stream 8 から CentOS Stream 9 への移行方法についてもまとめてみたいと思います）。なので新しく CentOS Stream 9 をインストールし、設定方法などについてまとめてみました。

## 参考
<a href="https://blog.yamk.net/posts/20220904-raspiserver-centosstream9/#%E5%8F%82%E8%80%83">Raspberry Pi 4B を自宅サーバにする(CentOS Stream 9)</a>
<a href="https://zenn.dev/kusaremkn/articles/d96571438a6497">Raspberry Pi に CentOS Stream 9 をインストールしてみる</a>
<a href="https://community.phileweb.com/mypage/entry/5642/20210302/67142/">ラズパイ4BでpiCorePlayer - 全てのLEDを消灯する方法</a>
<a href="https://engineers-life.com/linux_command/network_linux/linux_ip-route/">【ip route,route】Linuxコマンド_経路情報（ルーティングテーブル）の確認・設定をする</a>
<a href="https://happy-nap.hatenablog.com/entry/2022/10/08/220946">RHEL9系からsshdのPermitRootLoginがYesでない経緯を辿る</a>